TerraformPilot

Terraform

Azure Cosmos DB with Terraform - Global NoSQL Database

Deploy Azure Cosmos DB with Terraform. SQL API, MongoDB API, global distribution, autoscale throughput, private endpoints, and backup configuration.

LLuca Berton1 min read

Quick Answer

#
resource "azurerm_cosmosdb_account" "main" {
  name                = "myapp-cosmos"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  offer_type          = "Standard"
  kind                = "GlobalDocumentDB"
 
  consistency_policy {
    consistency_level = "Session"
  }
 
  geo_location {
    location          = azurerm_resource_group.main.location
    failover_priority = 0
  }
}

Production Cosmos DB (SQL API)

#
resource "azurerm_cosmosdb_account" "main" {
  name                      = "${var.project}-${var.environment}-cosmos"
  location                  = azurerm_resource_group.main.location
  resource_group_name       = azurerm_resource_group.main.name
  offer_type                = "Standard"
  kind                      = "GlobalDocumentDB"
  automatic_failover_enabled = true
  free_tier_enabled         = false
 
  consistency_policy {
    consistency_level       = "BoundedStaleness"
    max_interval_in_seconds = 300
    max_staleness_prefix    = 100000
  }
 
  # Primary region
  geo_location {
    location          = var.primary_location
    failover_priority = 0
    zone_redundant    = true
  }
 
  # Secondary region (disaster recovery)
  geo_location {
    location          = var.secondary_location
    failover_priority = 1
    zone_redundant    = true
  }
 
  # Network security
  is_virtual_network_filter_enabled = true
  public_network_access_enabled     = false
 
  virtual_network_rule {
    id = azurerm_subnet.app.id
  }
 
  backup {
    type                = "Continuous"
    tier                = "Continuous7Days"
  }
 
  tags = { Environment = var.environment }
}

Database and Containers

#
resource "azurerm_cosmosdb_sql_database" "app" {
  name                = "myapp"
  resource_group_name = azurerm_resource_group.main.name
  account_name        = azurerm_cosmosdb_account.main.name
}
 
# Container with autoscale
resource "azurerm_cosmosdb_sql_container" "orders" {
  name                = "orders"
  resource_group_name = azurerm_resource_group.main.name
  account_name        = azurerm_cosmosdb_account.main.name
  database_name       = azurerm_cosmosdb_sql_database.app.name
  partition_key_paths  = ["/customerId"]
 
  autoscale_settings {
    max_throughput = 4000  # Scales between 400-4000 RU/s
  }
 
  indexing_policy {
    indexing_mode = "consistent"
 
    included_path {
      path = "/*"
    }
 
    excluded_path {
      path = "/description/?"
    }
 
    composite_index {
      index {
        path  = "/customerId"
        order = "ascending"
      }
      index {
        path  = "/createdAt"
        order = "descending"
      }
    }
  }
 
  unique_key {
    paths = ["/email"]
  }
 
  default_ttl = 2592000  # 30 days
}
 
# Container with fixed throughput
resource "azurerm_cosmosdb_sql_container" "sessions" {
  name                = "sessions"
  resource_group_name = azurerm_resource_group.main.name
  account_name        = azurerm_cosmosdb_account.main.name
  database_name       = azurerm_cosmosdb_sql_database.app.name
  partition_key_paths  = ["/sessionId"]
  throughput          = 400
  default_ttl         = 3600  # 1 hour
}

Private Endpoint

#
resource "azurerm_private_endpoint" "cosmos" {
  name                = "${var.project}-cosmos-pe"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  subnet_id           = azurerm_subnet.private_endpoints.id
 
  private_service_connection {
    name                           = "${var.project}-cosmos-psc"
    private_connection_resource_id = azurerm_cosmosdb_account.main.id
    is_manual_connection           = false
    subresource_names              = ["sql"]
  }
 
  private_dns_zone_group {
    name                 = "cosmos-dns"
    private_dns_zone_ids = [azurerm_private_dns_zone.cosmos.id]
  }
}
 
resource "azurerm_private_dns_zone" "cosmos" {
  name                = "privatelink.documents.azure.com"
  resource_group_name = azurerm_resource_group.main.name
}
 
resource "azurerm_private_dns_zone_virtual_network_link" "cosmos" {
  name                  = "cosmos-dns-link"
  resource_group_name   = azurerm_resource_group.main.name
  private_dns_zone_name = azurerm_private_dns_zone.cosmos.name
  virtual_network_id    = azurerm_virtual_network.main.id
}

MongoDB API

#
resource "azurerm_cosmosdb_account" "mongo" {
  name                = "${var.project}-mongo"
  location            = azurerm_resource_group.main.location
  resource_group_name = azurerm_resource_group.main.name
  offer_type          = "Standard"
  kind                = "MongoDB"
 
  capabilities {
    name = "EnableMongo"
  }
 
  capabilities {
    name = "MongoDBv3.4"  # or mongoEnableDocLevelTTL
  }
 
  consistency_policy {
    consistency_level = "Session"
  }
 
  geo_location {
    location          = azurerm_resource_group.main.location
    failover_priority = 0
  }
}
 
resource "azurerm_cosmosdb_mongo_database" "app" {
  name                = "myapp"
  resource_group_name = azurerm_resource_group.main.name
  account_name        = azurerm_cosmosdb_account.mongo.name
}
 
resource "azurerm_cosmosdb_mongo_collection" "users" {
  name                = "users"
  resource_group_name = azurerm_resource_group.main.name
  account_name        = azurerm_cosmosdb_account.mongo.name
  database_name       = azurerm_cosmosdb_mongo_database.app.name
  shard_key           = "userId"
  throughput          = 400
 
  index {
    keys   = ["_id"]
    unique = true
  }
}

Consistency Levels

#
LevelLatencyAvailabilityUse Case
StrongHighestLowerFinancial transactions
Bounded StalenessMediumHighGlobal apps needing ordering
SessionLowHighMost applications (default)
Consistent PrefixLowHighRead-heavy workloads
EventualLowestHighestSocial feeds, analytics

Outputs

#
output "cosmos_endpoint" {
  value = azurerm_cosmosdb_account.main.endpoint
}
 
output "cosmos_connection_strings" {
  value     = azurerm_cosmosdb_account.main.connection_strings
  sensitive = true
}
#

Conclusion

#

Choose the right consistency level (Session for most apps), use autoscale throughput to handle traffic spikes, enable continuous backup, and use private endpoints in production. Pick your partition key carefully — it's the most important design decision for Cosmos DB performance.

#Terraform#Azure#Cosmos DB#Database#Infrastructure as Code

Share this article