Declarative vs Imperative Operations
Complete the full lesson to earn 25 points — 50 with Pro
Work through each section, then tap “Mark as Complete” on the last one.
✦ Skip the page breaks, the wait, and see fewer ads — read each lesson on a single page with Pro
Lesson: Declarative vs. Imperative Operations in Azure Cosmos DB
Introduction: The Philosophy of Infrastructure Management
When you manage a database as powerful and distributed as Azure Cosmos DB, the way you interact with the infrastructure matters as much as the data itself. Throughout your career, you will encounter two primary paradigms for managing cloud resources: imperative operations and declarative operations. Understanding the difference between these two is not merely an academic exercise; it is the fundamental difference between a fragile, manual infrastructure and a reliable, scalable system that stands the test of time.
Imperative operations focus on the "how." You provide a series of commands or scripts that tell the system exactly which steps to take to reach a desired state. It is like giving a child a list of instructions: "Open the box, take out the toy, put the battery in, and press the button." If one step fails or the environment changes unexpectedly, the entire process might break.
Declarative operations, on the other hand, focus on the "what." You define the end state—the configuration you want to see—and the system determines the steps required to achieve that state. This is more like hiring a professional organizer: you tell them, "I want this room to be a home office," and they figure out how to arrange the furniture, paint the walls, and install the lighting to make that reality happen. In the world of Azure, moving toward a declarative model is the industry standard for maintaining consistent, repeatable, and audit-ready Cosmos DB environments.
The Imperative Approach: Command-Line and Scripting
Imperative management in Azure is most commonly associated with Azure CLI, Azure PowerShell, or direct SDK calls. When you use these tools, you are essentially "doing" things to the database. You might write a script that checks if a container exists; if it doesn't, it creates it. If it does exist, it might update the throughput.
The Mechanics of Imperative Scripts
Consider a common scenario where you need to provision a new Cosmos DB container for a development environment. An imperative script might look like this PowerShell example:
# Imperative approach to creating a container
$containerName = "UserOrders"
$databaseName = "RetailStore"
# Step 1: Check if the container exists
$container = Get-AzCosmosDBSqlContainer -ResourceGroupName "RG-Prod" -AccountName "Cosmos-Main" -DatabaseName $databaseName -Name $containerName -ErrorAction SilentlyContinue
# Step 2: Logic to handle existence
if ($null -eq $container) {
Write-Host "Container does not exist. Creating now..."
New-AzCosmosDBSqlContainer -ResourceGroupName "RG-Prod" -AccountName "Cosmos-Main" -DatabaseName $databaseName -Name $containerName -PartitionKeyPath "/userId" -Throughput 400
} else {
Write-Host "Container exists. Updating throughput..."
Update-AzCosmosDBSqlContainerThroughput -ResourceGroupName "RG-Prod" -AccountName "Cosmos-Main" -DatabaseName $databaseName -Name $containerName -Throughput 1000
}
Why Imperative Operations Can Be Risky
While this script works for a simple task, it introduces several risks in a production environment. First, it is prone to "state drift." If someone manually changes the throughput in the Azure portal, your script may not account for that change correctly, or it might overwrite manual adjustments that were intended to be temporary. Second, these scripts are difficult to maintain. As your database grows to include dozens of containers, your script becomes a complex web of if-else statements, which are notoriously difficult to test and debug.
Warning: The Manual Intervention Trap Imperative scripts often fail when they assume the environment is in a specific state. If a developer manually deletes a container or changes a partition key, your imperative script might crash or, worse, attempt to re-create resources in a way that causes downtime. Always treat imperative scripts as "one-off" tools rather than the foundation of your production deployment strategy.
The Declarative Approach: Infrastructure as Code (IaC)
Declarative operations rely on Infrastructure as Code (IaC) tools like Bicep, ARM templates, or Terraform. Instead of writing a procedure, you write a blueprint. When you submit this blueprint to Azure, the platform compares your definition with the current state of the resource and applies only the changes necessary to match your definition.
The Power of Bicep for Cosmos DB
Bicep is a domain-specific language designed specifically for Azure. It simplifies the syntax of ARM templates, making it easier to read and maintain. When you define a Cosmos DB container in Bicep, you are stating what the container should look like, regardless of what is currently there.
// Declarative approach using Bicep
resource cosmosContainer 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2023-04-15' = {
name: 'RetailStore/UserOrders'
properties: {
resource: {
id: 'UserOrders'
partitionKey: {
paths: [
'/userId'
]
kind: 'Hash'
}
}
options: {
throughput: 400
}
}
}
When you deploy this file, Azure Resource Manager (ARM) handles the logic. If the container exists, it updates the properties. If it doesn't, it creates it. You do not need to write if-else logic to check for existence; the platform handles the state reconciliation for you.
Benefits of the Declarative Model
The declarative model is superior for long-term maintenance for several reasons:
- Idempotency: You can run the same deployment script a hundred times, and the result will always be the same. The system will not try to create a resource that already exists.
- Version Control: Because your infrastructure is defined in files, you can store those files in Git. This provides a history of who changed what and when, which is critical for compliance and debugging.
- Environment Parity: You can use the exact same Bicep file to deploy to Development, Testing, and Production, changing only the parameters (like throughput or location). This eliminates "it works in my environment" bugs.
Callout: Idempotency Explained Idempotency is the ability of an operation to be performed multiple times without changing the result beyond the initial application. In declarative infrastructure, this means that if your desired state is "Container X with 400 RU/s," applying the configuration will result in exactly that, whether the container was empty, already at 400 RU/s, or at 1000 RU/s. This removes the need for complex state-checking logic in your deployment pipelines.
Implementing DevOps for Cosmos DB
To move from manual, imperative management to a professional DevOps workflow, you must integrate your declarative files into a CI/CD (Continuous Integration/Continuous Deployment) pipeline. This is where the real value of your Azure Cosmos DB management strategy is realized.
Building a Pipeline with GitHub Actions or Azure DevOps
A standard DevOps pipeline for Cosmos DB generally follows these steps:
- Validation: The pipeline checks the syntax of your Bicep or Terraform files.
- Pre-flight/What-If: The pipeline runs a "what-if" operation to show you exactly what will change before it actually happens.
- Deployment: The pipeline applies the changes to the Azure environment.
- Verification: The pipeline runs automated tests to ensure the database is reachable and performing as expected.
Example: Using the "What-If" Command
One of the best practices in declarative management is the "What-If" operation. Before you deploy, you can run a command that asks Azure to simulate the deployment.
# Running a What-If operation via Azure CLI
az deployment group what-if --resource-group RG-Prod --template-file main.bicep
This command will output a report showing exactly which properties will be created, modified, or deleted. This is an essential step to prevent accidental deletions of production data or unintended throughput spikes.
Comparing Imperative and Declarative Operations
| Feature | Imperative | Declarative |
|---|---|---|
| Primary Focus | The steps to achieve a result | The final desired state |
| Logic Complexity | High (requires error handling) | Low (system handles logic) |
| Idempotency | Difficult to implement manually | Built into the framework |
| Auditability | Poor (scripts change over time) | Excellent (Git history) |
| Tooling | CLI, PowerShell, SDKs | Bicep, Terraform, ARM Templates |
| Consistency | Risk of manual drift | High (enforced by the platform) |
Best Practices for Cosmos DB DevOps
Transitioning to a declarative model is only half the battle. To be successful, you must follow industry-standard practices that protect your data and your sanity.
1. Treat Infrastructure as Code (IaC) as Application Code
Your Bicep files or Terraform modules should be treated with the same rigor as your application code. This means they should be stored in source control (like GitHub or Azure DevOps Repos), undergo peer reviews (Pull Requests), and follow branching strategies. Never manually change a production database setting without updating the corresponding code file first.
2. Parameterization for Environment Parity
Avoid hard-coding values like throughput or container names inside your resource definitions. Instead, use parameter files. This allows you to have a prod.parameters.json and a dev.parameters.json. This ensures that your production environment is tuned for high performance while your dev environment remains cost-effective.
3. Use Automated Testing
When you modify your infrastructure, how do you know you haven't broken anything? Use testing frameworks to validate your infrastructure. For example, you can write tests that check if a container was created with the correct partition key or if the Time-to-Live (TTL) setting is enabled.
4. Implement Least Privilege
Your CI/CD service principal should not have "Owner" access to your entire Azure subscription. Use RBAC (Role-Based Access Control) to grant the pipeline only the permissions necessary to manage the specific Cosmos DB resources. This limits the damage if a pipeline is compromised.
Tip: The "Manual Change" Policy If you have a team, create a policy that manual changes in the Azure Portal are prohibited for production databases. If someone must make an emergency change to throughput, they should be required to update the source code immediately afterward. This keeps the "source of truth" in your repository, not in the portal.
Common Pitfalls and How to Avoid Them
Even with the best tools, teams often fall into traps that can cause significant headaches. Let's look at the most common ones.
Trap 1: The "Partial" Declarative Approach
Some teams use declarative files to create the database but use imperative scripts to create containers or update throughput. This creates a "split brain" scenario where you never know which tool is the source of truth.
- The Fix: Commit to a fully declarative model. If it exists in Azure, it should be defined in your IaC files.
Trap 2: Neglecting State Files
If you are using Terraform, you will encounter "state files." These files track the current mapping between your code and the real-world resources. If you lose or corrupt this file, you lose your ability to manage the infrastructure declaratively.
- The Fix: Always store your state files in a remote, secure location with versioning enabled (like an Azure Blob Storage container with soft delete).
Trap 3: Ignoring Throughput Limits
When you define throughput in a declarative file, it is easy to accidentally set a value that is too high, leading to massive, unexpected bills.
- The Fix: Implement "policy as code" (Azure Policy) to set a maximum limit on throughput that any deployment can request. This acts as a safety guardrail for your deployments.
Deep Dive: Managing Throughput Declaratively
One of the most frequent tasks in Cosmos DB management is adjusting Request Units (RU/s). In an imperative world, you might have a script that runs every morning to bump up capacity for business hours. In a declarative world, this becomes slightly trickier because "business hours" are a dynamic concept, not a static state.
Using Autoscale for Declarative Efficiency
Rather than trying to manage throughput using scripts, the declarative approach favors using Autoscale. When you define an autoscale container in Bicep, you are declaring the maximum throughput. Azure then manages the scaling for you.
resource autoscaleContainer 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2023-04-15' = {
name: 'RetailStore/Orders'
properties: {
resource: {
id: 'Orders'
partitionKey: { paths: ['/id'], kind: 'Hash' }
}
options: {
autoscaleSettings: {
maxThroughput: 4000
}
}
}
}
By choosing the right feature (autoscale) and declaring it via code, you remove the need for imperative "scaling scripts" entirely. This is the ultimate goal of DevOps: using platform features to replace custom, complex code.
Handling Database Migrations
What happens when you need to change a partition key? In Cosmos DB, this is a "destructive" operation—you cannot simply change a partition key on an existing container. You must create a new container and migrate the data.
The Imperative Approach to Migration
An imperative script would involve:
- Creating a new container.
- Running a data migration tool (like Azure Data Factory).
- Updating the application code to point to the new container.
- Deleting the old container.
The Declarative Approach to Migration
In a declarative workflow, you treat the migration as a change in the desired state. You update your Bicep file to define the new container. Your CI/CD pipeline then deploys the new container. You then trigger an automation process (perhaps a Function App or Azure Data Factory pipeline) that handles the data copy. Once the data is verified, you remove the old container definition from your Bicep file.
The advantage here is that the infrastructure state is always documented. Your Git history shows the transition from the old schema to the new one, providing a perfect audit trail for compliance teams.
Security and Governance in Declarative Operations
Managing Cosmos DB isn't just about containers and throughput; it is about security. Declarative files allow you to define security settings such as Firewall rules, Virtual Network (VNet) service endpoints, and Private Link connections.
Example: Declaring a Private Endpoint
If you are working in a highly regulated environment, you might need to ensure all traffic goes through a private endpoint. You can declare this in your Bicep file:
resource privateEndpoint 'Microsoft.Network/privateEndpoints@2022-07-01' = {
name: 'cosmos-private-endpoint'
location: resourceGroup().location
properties: {
subnet: { id: subnetId }
privateLinkServiceConnections: [
{
name: 'cosmos-connection'
properties: {
privateLinkServiceId: cosmosAccount.id
groupIds: ['Sql']
}
}
]
}
}
By including this in your infrastructure code, you ensure that every deployment is secure by default. You no longer have to worry that a developer might accidentally deploy a database that is exposed to the public internet because the "secure" configuration is baked into the code that everyone uses.
The Role of Documentation in DevOps
A common misconception is that "code is the documentation." While code is the source of truth, it is often hard for a human to read quickly to understand the architectural intent.
Best Practices for Documentation
- Comments in Code: Use comments in your Bicep/Terraform files to explain why a certain configuration was chosen (e.g., "Setting throughput to 1000 to handle peak holiday traffic").
- README Files: In your infrastructure repository, include a README that explains the overall architecture of your Cosmos DB environment.
- Architecture Diagrams: While not code, keeping a high-level diagram alongside your code helps new team members understand how the pieces fit together.
Callout: The "Why" vs. the "What" Code tells you what is happening. Comments in your code tell you why it is happening. When you look at a line of code setting a partition key to
/customerId, a comment explaining that this was chosen to optimize for "customer-specific query patterns" provides invaluable context for future developers who may need to refactor the database.
Troubleshooting Common Deployment Failures
Even with a declarative approach, deployments can fail. Here is how to handle the most common issues:
- Conflict Errors: If a resource is being modified by someone else or a concurrent process, the deployment will fail.
- Solution: Use a central CI/CD pipeline so that all deployments are serialized. Never allow local, ad-hoc deployments from developer machines.
- Validation Errors: Azure Resource Manager validates your template before deployment. If your syntax is wrong, it will fail early.
- Solution: Use VS Code extensions for Bicep or Terraform to validate your code as you type.
- Dependency Errors: Sometimes you try to create a container before the database account is ready.
- Solution: Use the
dependsOnproperty in Bicep to explicitly define the order of operations.
- Solution: Use the
Summary: Key Takeaways for Success
As you move forward in your journey to master Azure Cosmos DB operations, keep these core principles at the forefront of your work:
- Prioritize Declarative Over Imperative: Always favor tools like Bicep or Terraform. They are the foundation of stable, repeatable, and scalable cloud infrastructure.
- Embrace Idempotency: Design your deployments so they can be run repeatedly without side effects. This is the hallmark of a mature DevOps process.
- Version Control Everything: Treat your infrastructure as a software product. Store your files in Git, use branches, and enforce code reviews for all changes.
- Automate, Don't Script: Use built-in platform features like Autoscale instead of writing custom "scaling scripts." Let Azure handle the heavy lifting of resource management.
- Security by Default: Use your declarative files to enforce security configurations (like Private Links and Firewall rules) so that every deployment is secure from the start.
- Use What-If Analysis: Always verify your changes before applying them. The "What-If" command is your most powerful tool to prevent accidental data loss or configuration errors.
- Standardize Your Pipeline: Build a single, reliable CI/CD pipeline that manages your deployments. Eliminate the "wild west" of local deployments by ensuring all infrastructure changes flow through your automated system.
By adopting these practices, you transform yourself from a database administrator who "fixes things" into a platform engineer who "builds systems." The shift to declarative operations is the single most effective way to ensure your Azure Cosmos DB solution remains performant, secure, and manageable as your organization grows.
Reach the last section to complete this lesson and earn points — you're on section 1 of 11.
- Introduction to Cosmos DB Data Modeling
- Introduction to Cosmos DB Data Modeling Quiz5q
- Multiple Entity Types in Same Container
- Multiple Entity Types in Same Container Quiz5q
- Storing Related Entities in Same Document
- Storing Related Entities in Same Document Quiz5q
- Denormalizing Data Across Documents
- Denormalizing Data Across Documents Quiz5q
- Referencing Between Documents
- Referencing Between Documents Quiz5q
- Partition Keys and Document IDs
- Partition Keys and Document IDs Quiz5q
- Time to Live (TTL) Configuration
- Time to Live (TTL) Configuration Quiz5q
- Document Versioning Strategies
- Document Versioning Strategies Quiz5q
- Schema Versioning Patterns
- Schema Versioning Patterns Quiz5q
- Choosing Partition Strategies
- Choosing Partition Strategies Quiz5q
- Partition Key Selection Best Practices
- Partition Key Selection Best Practices Quiz5q
- Transactions and Partition Keys
- Transactions and Partition Keys Quiz5q
- Cross-Partition Query Costs
- Cross-Partition Query Costs Quiz5q
- Data Distribution Analysis
- Data Distribution Analysis Quiz5q
- Throughput Distribution Planning
- Throughput Distribution Planning Quiz5q
- Synthetic Partition Keys
- Synthetic Partition Keys Quiz5q
- Hierarchical Partition Keys
- Hierarchical Partition Keys Quiz5q
- Throughput and Storage Requirements
- Throughput and Storage Requirements Quiz5q
- Serverless vs Provisioned Throughput
- Serverless vs Provisioned Throughput Quiz5q
- Database-Level Provisioned Throughput
- Database-Level Provisioned Throughput Quiz5q
- Granular Scale Units
- Granular Scale Units Quiz5q
- Global Distribution Costs
- Global Distribution Costs Quiz5q
- Configuring Throughput in Portal
- Configuring Throughput in Portal Quiz5q
- Gateway vs Direct Connectivity Mode
- Gateway vs Direct Connectivity Mode Quiz5q
- Creating Database Connections
- Creating Database Connections Quiz5q
- Azure Cosmos DB Emulator
- Azure Cosmos DB Emulator Quiz5q
- Connection Error Handling
- Connection Error Handling Quiz5q
- Singleton Pattern for Clients
- Singleton Pattern for Clients Quiz5q
- Global Distribution Regions
- Global Distribution Regions Quiz5q
- Threading and Parallelism
- Threading and Parallelism Quiz5q
- Arrays and Nested Objects Queries
- Arrays and Nested Objects Queries Quiz5q
- Correlated Subqueries
- Correlated Subqueries Quiz5q
- Array and Type-Checking Functions
- Array and Type-Checking Functions Quiz5q
- Mathematical and String Functions
- Mathematical and String Functions Quiz5q
- Date Functions in Queries
- Date Functions in Queries Quiz5q
- Point Operations vs Query Operations
- Point Operations vs Query Operations Quiz5q
- CRUD Point Operations
- CRUD Point Operations Quiz5q
- Patch Operations for Updates
- Patch Operations for Updates Quiz5q
- Transactional Batch Operations
- Transactional Batch Operations Quiz5q
- Bulk Operations with SDK
- Bulk Operations with SDK Quiz5q
- Optimistic Concurrency with ETags
- Optimistic Concurrency with ETags Quiz5q
- Query Pagination and Continuation
- Query Pagination and Continuation Quiz5q
- Cosmos DB Mirroring for Fabric
- Cosmos DB Mirroring for Fabric Quiz5q
- Mirroring vs Spark Connector
- Mirroring vs Spark Connector Quiz5q
- Enabling Analytical Store
- Enabling Analytical Store Quiz5q
- Synapse Spark and SQL Queries
- Synapse Spark and SQL Queries Quiz5q
- Change Data Capture in Analytical Store
- Change Data Capture in Analytical Store Quiz5q
- Azure Functions and Event Hubs Integration
- Azure Functions and Event Hubs Integration Quiz5q
- Denormalization with Change Feed
- Denormalization with Change Feed Quiz5q
- Referential Integrity with Change Feed
- Referential Integrity with Change Feed Quiz5q
- Azure AI Search Integration
- Azure AI Search Integration Quiz5q
- Azure Functions Change Feed Trigger
- Azure Functions Change Feed Trigger Quiz5q
- Consuming Change Feed with SDK
- Consuming Change Feed with SDK Quiz5q
- Change Feed Estimator
- Change Feed Estimator Quiz5q
- Denormalization via Change Feed
- Denormalization via Change Feed Quiz5q
- Aggregation Persistence with Change Feed
- Aggregation Persistence with Change Feed Quiz5q
- Read-Heavy vs Write-Heavy Indexing
- Read-Heavy vs Write-Heavy Indexing Quiz5q
- Index Type Selection
- Index Type Selection Quiz5q
- Custom Indexing Policies
- Custom Indexing Policies Quiz5q
- Composite Index Implementation
- Composite Index Implementation Quiz5q
- Index Performance Optimization
- Index Performance Optimization Quiz5q
- Response Status Codes and Metrics
- Response Status Codes and Metrics Quiz5q
- Normalized RU Consumption Monitoring
- Normalized RU Consumption Monitoring Quiz5q
- Server-Side Latency Metrics
- Server-Side Latency Metrics Quiz5q
- Data Replication Monitoring
- Data Replication Monitoring Quiz5q
- Azure Monitor Alerts Configuration
- Azure Monitor Alerts Configuration Quiz5q
- Resource Logs Implementation
- Resource Logs Implementation Quiz5q
- Partition Throughput Monitoring
- Partition Throughput Monitoring Quiz5q
- Encryption Key Management
- Encryption Key Management Quiz5q
- Network-Level Access Control
- Network-Level Access Control Quiz5q
- Data Encryption Configuration
- Data Encryption Configuration Quiz5q
- Azure RBAC for Control Plane
- Azure RBAC for Control Plane Quiz5q
- Microsoft Entra ID for Data Plane
- Microsoft Entra ID for Data Plane Quiz5q
- CORS Settings Configuration
- CORS Settings Configuration Quiz5q
- Customer-Managed Keys
- Customer-Managed Keys Quiz5q
- Always Encrypted Implementation
- Always Encrypted Implementation Quiz5q
- Data Movement Strategy Selection
- Data Movement Strategy Selection Quiz5q
- SDK Bulk Operations for Data Movement
- SDK Bulk Operations for Data Movement Quiz5q
- Azure Data Factory Pipelines
- Azure Data Factory Pipelines Quiz5q
- Kafka Connector Integration
- Kafka Connector Integration Quiz5q
- Azure Stream Analytics Integration
- Azure Stream Analytics Integration Quiz5q
- Cosmos DB Spark Connector
- Cosmos DB Spark Connector Quiz5q
Enjoying the courses?
Everything stays free. Pro shows fewer ads, doubles the points you earn on every lesson and quiz so you progress twice as fast, unlocks half of every practice exam — plus full case studies — with the Learn & Exam study modes, and lets you read each lesson on one page.
- ✓ Fewer advertisements
- ✓ 2× points per lesson & quiz
- ✓ 50% of every exam unlocked
- ✓ Learn & Exam modes
- ✓ Distraction-free lessons