Playbook - AZ-204 Microsoft Azure Developer Associate
Last reviewed: May 2026
A scannable reference of architectural patterns the AZ-204 exam tests. Read top-to-bottom, or jump to a section.
Develop Azure compute solutions
Need an App Service plan for a production web app with custom domains/SSL, autoscale, and deployment slots.
Use the Standard (S1) App Service plan tier or higher.
Why: Standard is the minimum tier supporting all key production features: custom domains with SSL, autoscale, and deployment slots. Basic tier lacks autoscale and slots.
Perform a zero-downtime deployment for an App Service and keep production settings (like connection strings) in the production slot.
Use deployment slots. Mark production-specific settings as "deployment slot settings" (sticky). Perform a swap operation to deploy.
Why: The swap operation warms up the staging slot before redirecting traffic. Sticky settings do not move with the code during a swap, preventing staging settings from going live.
An App Service needs to connect to an on-premises resource (e.g., SQL Server) without a VPN or ExpressRoute.
Use App Service Hybrid Connections. Install the Hybrid Connection Manager (HCM) on-premises.
Why: Hybrid Connections provide a secure TCP tunnel to on-premises resources without requiring inbound firewall ports, a VPN, or VNet integration. The HCM initiates the outbound connection.
An Azure Function on the Consumption plan experiences long cold starts, causing latency.
Migrate to the Functions Premium plan and configure a minimum of one pre-warmed instance.
Why: The Premium plan eliminates cold starts by keeping a specified number of instances always ready. It is more cost-effective than a full Dedicated plan for this purpose.
An Azure Function on the Consumption plan is timing out because it takes more than 10 minutes to execute.
Migrate the function to a Premium or Dedicated (App Service) plan.
Why: The Consumption plan has a maximum timeout of 10 minutes. Premium and Dedicated plans support much longer execution times (up to 60 minutes or unlimited).
Process a large number of independent items in parallel and wait for all to complete before proceeding.
Implement the Durable Functions Fan-out/Fan-in pattern. The orchestrator calls multiple activity functions concurrently and uses `Task.WhenAll` (or equivalent) to wait for completion.
Why: This pattern is designed for parallel execution, which is far more efficient than sequential processing (Function Chaining) for independent tasks.
A long-running workflow must wait for an external event, such as human approval, with a timeout.
Use the Durable Functions Human Interaction pattern. Combine `waitForExternalEvent` with a `createTimer`. Use `Task.WhenAny` to proceed when either the event arrives or the timer expires.
Why: This pattern allows orchestrations to pause indefinitely without consuming compute, awaiting an external trigger, while also handling timeouts gracefully.
A containerized application needs to scale to zero instances when there is no traffic to minimize cost.
Use Azure Container Apps with a KEDA-based scaling rule (e.g., HTTP requests or queue length).
Why: Container Apps with KEDA scalers can scale down to zero replicas when idle and scale up on demand, which is ideal for event-driven or intermittent workloads. CPU/memory scaling cannot scale to zero.
A backend microservice in Azure Container Apps must only be accessible by other container apps within the same environment, not from the public internet.
Enable ingress on the backend container app and set the traffic visibility to `internal`.
Why: Internal ingress restricts access to the Container Apps environment. Other apps in the environment can discover and call the service using its internal FQDN.
Need to run a single container for a simple task, a test, or a batch job without orchestration.
Use Azure Container Instances (ACI).
Why: ACI is the fastest and simplest way to run a single container without managing any underlying infrastructure. Use Container Apps or AKS for orchestrating multi-container applications.
Need to build and push a Docker image to Azure Container Registry (ACR) from a local Dockerfile, but Docker is not installed locally.
Use the `az acr build` command.
Why: `az acr build` offloads the build process to ACR Tasks in the cloud. It sends the build context to Azure, builds the image, and stores it directly in the registry.
Develop for Azure storage
Designing a Cosmos DB container with frequent queries filtering on a specific property (e.g., `region`).
Select the most frequently queried, high-cardinality property as the partition key (e.g., `/region`).
Why: Queries that include the partition key in the `WHERE` clause are targeted to a single logical partition, avoiding costly cross-partition fan-out queries and minimizing RU consumption.
A globally distributed application requires that reads always return the most recently committed write.
Configure the Cosmos DB account consistency level to Strong.
Why: Strong consistency provides a linearizability guarantee, ensuring reads are always up-to-date. Other levels (Session, Bounded Staleness, Eventual) trade consistency for lower latency and higher availability.
Need to process all new or updated documents in a Cosmos DB container in real-time to update a materialized view.
Use an Azure Function with a Cosmos DB trigger, which leverages the change feed processor.
Why: The change feed provides a persistent log of changes. The Cosmos DB trigger with the change feed processor automates state management and load balancing across multiple function instances.
Need to perform an atomic operation on multiple documents within the same logical partition (e.g., create two and update one).
Use the `TransactionalBatch` API in the Cosmos DB SDK. All operations must target the same partition key.
Why: TransactionalBatch ensures that all operations in the batch succeed or fail as a single atomic unit, preventing partial updates. It is more efficient than a stored procedure for client-side batch operations.
A Cosmos DB workload is unpredictable, with significant peaks and troughs in traffic.
Configure autoscale provisioned throughput on the database or container.
Why: Autoscale automatically scales RU/s based on usage, ensuring performance during peaks and cost savings during troughs. It scales between 10% and 100% of the max configured RU/s.
Data is accessed frequently at first, then infrequently, and finally archived for long-term retention.
Use a combination of Hot, Cool, and Archive access tiers. Automate transitions with a Lifecycle Management policy.
Why: Aligning the access tier with the access pattern optimizes cost. Hot is for frequent access, Cool for infrequent, and Archive for long-term, low-cost storage. Lifecycle policies automate this.
Prevent multiple processes from modifying the same blob simultaneously.
Implement blob leases. A process acquires an exclusive-write lock (lease) on a blob before modifying it.
Why: Leases provide pessimistic concurrency control. Once a lease is acquired, no other client can write to the blob until the lease is released or expires.
Store audit logs in Blob Storage and ensure they cannot be modified or deleted for a fixed retention period (e.g., 7 years).
Configure a time-based retention policy on the blob container. For indefinite holds, use a legal hold.
Why: Immutable storage policies enforce WORM (Write-Once, Read-Many) state, which is essential for compliance. Once locked, a time-based policy cannot be shortened.
Need to categorize blobs with key-value attributes and query them across an entire storage account without listing all blobs.
Use Blob Index Tags.
Why: Index tags are indexed by the storage service and can be used in server-side filtering queries (`Find Blobs by Tags`). Metadata is not indexed and can only be filtered client-side after listing.
Implement Azure security
Securely authenticate users in a Single-Page Application (SPA) and acquire tokens for a backend API.
Use the Authorization Code flow with PKCE (Proof Key for Code Exchange).
Why: This is the current security best practice for public clients. It avoids exposing tokens in the URL (unlike the deprecated Implicit flow) and does not require a client secret.
A background service or daemon needs to call a protected API (like Microsoft Graph) without a signed-in user.
Use the Client Credentials flow with Application permissions.
Why: This flow authenticates the application itself using a client secret or certificate. Application permissions grant access across the organization, subject to admin consent.
A middle-tier web API needs to call a downstream API while preserving the original signed-in user's identity.
Implement the On-Behalf-Of (OBO) flow.
Why: The middle-tier API exchanges the user's access token for a new token scoped to the downstream API. This delegates the user's identity securely.
An application using MSAL needs to acquire tokens efficiently, minimizing user prompts.
Always call `AcquireTokenSilent()` first. If it fails with a `MsalUiRequiredException`, fall back to an interactive method like `AcquireTokenInteractive()`.
Why: `AcquireTokenSilent()` checks the cache for a valid token or uses a refresh token to get a new one without user interaction. This is critical for good user experience.
An Azure resource (e.g., App Service, Function) needs to access another Azure resource (e.g., Key Vault, SQL Database) without storing credentials in code or config.
Enable a managed identity (system-assigned or user-assigned) on the source resource and grant it RBAC permissions on the target resource.
Why: Managed identity provides an identity in Microsoft Entra ID for the resource. Azure manages the credential lifecycle, eliminating the need for developers to handle secrets.
Multiple Azure resources need to share the same identity and permissions to access other services.
Create a single user-assigned managed identity and assign it to all required resources.
Why: A user-assigned identity has a lifecycle independent of any resource, making it reusable. A system-assigned identity is tied to a single resource and is deleted when the resource is.
Need to grant access to Key Vault secrets using Azure AD groups with fine-grained permissions at the individual secret level.
Use the Azure RBAC permission model for Key Vault. Assign roles like `Key Vault Secrets User` to principals.
Why: RBAC allows role assignments at the vault, or individual key/secret/certificate scope, providing more granularity than access policies, which apply to all objects of a type in the vault.
An application needs to pick up configuration changes from Azure App Configuration without restarting.
Use the App Configuration provider/SDK and configure it to refresh by monitoring a sentinel key.
Why: The SDK can periodically check a sentinel key for changes. When you update application settings, you also update the sentinel key, which triggers all clients to refresh their configuration.
Need to enable a new feature for a specific group of users (e.g., beta testers) and a percentage of the general audience.
Use an Azure App Configuration feature flag with a Targeting filter.
Why: The Targeting filter supports complex rollouts, allowing you to define audiences based on users and groups with specific percentages, plus a default rollout percentage for everyone else.
Need to generate a secure, short-lived token to grant a client access to a specific blob.
Create a user delegation SAS.
Why: A user delegation SAS is signed with Microsoft Entra ID credentials, not the storage account key. This is more secure because it avoids distributing the account key and access can be revoked via Entra ID policies.
Monitor, troubleshoot, and optimize Azure solutions
Troubleshoot a performance issue in a microservices application by visualizing dependencies and identifying which downstream service is causing high latency.
Use the Application Map feature in Application Insights.
Why: Application Map auto-discovers and displays a topological view of your distributed application, showing health and performance metrics for each component and the calls between them.
Trace a single user request as it flows across multiple microservices.
Use the End-to-End transaction details view in Application Insights. All telemetry is correlated by a shared `operation_Id`.
Why: The Application Insights SDKs automatically propagate W3C Trace Context headers, allowing all telemetry for a single operation to be correlated with the same `operation_Id`, enabling a unified view.
Diagnose a production issue: intermittent slow performance vs. an intermittent exception.
For slow performance, use Application Insights Profiler. For exceptions, use Snapshot Debugger.
Why: Profiler captures method-level timing traces for slow requests ("hot paths"). Snapshot Debugger captures the call stack and local variables at the moment an exception is thrown.
Reduce Application Insights data volume and cost from a high-traffic application while maintaining statistically valid data.
Enable adaptive sampling in the application's SDK configuration.
Why: Adaptive sampling automatically adjusts the sampling rate to stay within a target data volume, sampling more aggressively during high traffic and less during low traffic, preserving important telemetry.
Continuously monitor the availability of a web application endpoint from multiple geographic locations.
Configure a standard availability test (URL ping test) in Application Insights.
Why: Availability tests send requests to your endpoint from Azure datacenters worldwide, providing proactive monitoring of uptime and responsiveness and triggering alerts on failure.
Create an alert that fires when a performance metric (e.g., average response time) exceeds a specific threshold for a defined period.
Create an Azure Monitor metric alert rule. Target the resource and metric, configure a static threshold, aggregation type, and evaluation period. Link to an action group.
Why: Metric alerts provide low-latency, stateful monitoring of near-real-time metric data, which is ideal for performance-based alerting.
Connect to and consume Azure services and third-party services
Control API usage by limiting call frequency (e.g., 100 calls/min) versus total calls over a longer period (e.g., 10,000 calls/month).
Use the `rate-limit` policy for call frequency. Use the `quota` policy for total call volume.
Why: `rate-limit` throttles short-term bursts and returns HTTP 429. `quota` enforces a usage cap over a longer term (e.g., a billing period) and returns HTTP 403 when exceeded.
Cache API responses in API Management to reduce backend load, with the cache key varying by a request header.
Use a `<cache-lookup vary-by-header="..." />` policy in the inbound section and a `<cache-store duration="..." />` policy in the outbound section.
Why: This two-part policy combination enables response caching. `cache-lookup` checks for a cached item, and `cache-store` saves the response. The `vary-by` attributes ensure unique cache entries for different request variations.
Manage changes to an API. A breaking change is required vs. a non-breaking change needs to be tested.
Use Versions for breaking changes (e.g., /v1, /v2). Use Revisions for non-breaking changes and safe, staged rollouts.
Why: Versioning allows multiple API versions to be live simultaneously. Revisions allow you to modify an API offline, test it, and then make it the "current" revision without downtime.
Notify multiple, independent downstream services when an event occurs in an Azure service (e.g., blob created, resource group created).
Use Azure Event Grid. Create a system topic for the Azure resource and event subscriptions for each downstream handler.
Why: Event Grid is a fully managed, push-based pub/sub service that decouples event publishers from subscribers, enabling reactive, event-driven architectures.
Ingest a high-volume stream of telemetry or event data (millions of events per second) from many devices.
Use Azure Event Hubs.
Why: Event Hubs is a massively scalable data streaming platform designed for high-throughput ingestion. It uses a partitioned consumer model for parallel processing.
Ensure events from the same source (e.g., a specific IoT device) are processed in order by the same consumer.
Send events to Event Hubs with a partition key set to the source identifier (e.g., device ID).
Why: Event Hubs routes all messages with the same partition key to the same partition. Within a partition, message order is maintained.
Process a sequence of related messages in strict First-In, First-Out (FIFO) order.
Use Azure Service Bus sessions. Send all related messages with the same `SessionId`.
Why: Sessions provide a concurrent, ordered stream of messages. A session-aware receiver locks the session, guaranteeing that messages are processed sequentially by a single consumer.
A single publisher sends messages to a topic, but multiple subscribers only want a subset of those messages based on message properties.
Use a Service Bus topic with multiple subscriptions. Apply SQL filters or Correlation filters to each subscription.
Why: This is the canonical publish-subscribe pattern with content-based routing. Each subscription receives a copy of the message if it matches its filter rule.
A message cannot be processed successfully after multiple retries and must be set aside for later inspection.
Let the message fail processing until its max delivery count is exceeded. It will automatically be moved to the Dead-Letter Queue (DLQ).
Why: The DLQ is a built-in sub-queue for poison messages. This prevents a failing message from blocking the main queue and allows for offline analysis and reprocessing.
Choose a messaging service for: enterprise commands, reactive events, or high-volume telemetry.
Service Bus for commands (orders, transactions). Event Grid for reactive events (blob created, resource changed). Event Hubs for telemetry (IoT data, clickstreams).
Why: Service Bus offers rich features like ordering, transactions, and dead-lettering. Event Grid is for lightweight, push-based event routing. Event Hubs is for high-throughput data streaming.