Azure Container Registry Naming: Rules, Limits, and CAF Patterns
Azure Container Registry name requirements: 5 to 50 characters, lowercase alphanumeric only, no hyphens, globally unique. The CAF pattern, examples, and Terraform and Bicep.
An Azure Container Registry name must be 5 to 50 characters, lowercase letters and numbers only, with no hyphens or underscores, and globally unique across Azure, because the name becomes your login server:
<name>.azurecr.io. The CAF pattern concatenates components with no separator:cr{workload}{environment}{region}{instance}, for examplecrpaymentsprodeus001.
Azure Container Registry (ACR) has some of the strictest naming rules in Azure, and they catch out anyone used to hyphenated resource names. No hyphens. No uppercase. Globally unique. The reason is the same as storage accounts: the registry name becomes a public DNS host, your container login server.
The constraints
| Rule | Detail |
|---|---|
| Min length | 5 characters |
| Max length | 50 characters |
| Allowed characters | Lowercase letters and numbers only |
| Hyphens | Not allowed |
| Underscores | Not allowed |
| Uppercase | Not allowed (the name is case-insensitive and lowercased for the login server) |
| Scope of uniqueness | Global (across all of Azure) |
| CAF prefix | cr |
These constraints exist because the registry name becomes part of a public hostname: <name>.azurecr.io. That is the endpoint you docker push and docker pull against, so it has to be globally unique and DNS-safe, which rules out hyphens at that position and uppercase.
The CAF pattern for container registries
Because hyphens are not allowed, the CAF convention concatenates the components rather than separating them, exactly like storage accounts:
cr{workload}{environment}{region}{instance}
Examples:
| Workload | Environment | Region | Registry name |
|---|---|---|---|
| payments | prod | eus | crpaymentsprodeus001 |
| hrportal | dev | weu | crhrportaldevweu001 |
| platform | prod | eus | crplatformprodeus001 |
| shared | prod | eus | crsharedprodeus001 |
Notice there is no separator between components, just concatenation. This is intentional and CAF-recommended for hyphen-free resources.
The 5 to 50 character limit in practice
With a 2-character prefix (cr) you have 48 characters left, which is far roomier than the storage account’s 24. You rarely hit the limit. The real challenge is readability: without separators, a long name like crhumanresourcesplatformproductioneastus001 is hard to parse. Abbreviate the workload to keep it scannable:
| Full name | Abbreviated |
|---|---|
humanresources | hr |
platformservices | platform |
datapipelines | data |
Pick an abbreviation scheme, document it, and apply it consistently.
Registry name versus repository name
This is the distinction that trips people up. The strict rules above apply to the registry name only. The repositories and images inside the registry follow relaxed, Docker-standard naming: lowercase, and they can use forward slashes for namespacing, plus hyphens, underscores, and periods.
crpaymentsprodeus001.azurecr.io ← registry (strict: no hyphens)
/payments/api:1.4.0 ← repository and tag (relaxed)
/payments/worker:latest
/shared/base-images/dotnet:8.0 ← slashes namespace the repo
So you cannot put a hyphen in the registry name, but base-images as a repository path is perfectly fine.
Other ACR resources
A registry has several child resources, each with its own rules, all 5 to 50 characters:
| Resource | Characters |
|---|---|
| Scope map | Alphanumerics, hyphens, underscores |
| Token | Alphanumerics, hyphens, underscores |
| Task | Alphanumerics, hyphens, underscores |
| Replication | Alphanumerics only |
| Webhook | Alphanumerics only |
Unlike the registry name, scope maps, tokens, and tasks do allow hyphens, so scope-payments-pull is a valid scope map name.
Checking availability
Because the name is globally unique, check it before you deploy:
az acr check-name --name crpaymentsprodeus001
Output:
{
"nameAvailable": true,
"reason": null,
"message": null
}
Naming in Terraform
The azurerm_container_registry resource enforces the rules at apply time, but building the name defensively avoids a failed deployment:
variable "workload" { default = "payments" }
variable "environment" { default = "prod" }
variable "region" { default = "eus" }
resource "azurerm_container_registry" "main" {
# lowercase, strip any hyphens, enforce the character rules
name = lower(replace("cr${var.workload}${var.environment}${var.region}001", "-", ""))
resource_group_name = azurerm_resource_group.main.name
location = azurerm_resource_group.main.location
sku = "Standard"
}
Naming in Bicep
param workload string = 'payments'
param environment string = 'prod'
param region string = 'eus'
var acrName = take(toLower(replace('cr${workload}${environment}${region}001', '-', '')), 50)
resource acr 'Microsoft.ContainerRegistry/registries@2023-07-01' = {
name: acrName
location: resourceGroup().location
sku: { name: 'Standard' }
}
toLower and replace guard against uppercase and hyphens sneaking in from a variable, and take caps the length at 50.
Common mistakes
Putting a hyphen in the registry name. cr-payments-prod is rejected at deployment. Concatenate instead: crpaymentsprod.
Using uppercase. The name is lowercased for the login server anyway, so design in lowercase from the start.
Assuming the name is private. It is a public hostname the moment you create it. Check availability early.
Confusing registry rules with repository rules. The no-hyphen rule is only on the registry name. Your image repositories can use hyphens and slashes freely.
Summary
- Registry names: 5 to 50 characters, lowercase alphanumeric only, no hyphens, globally unique
- Concatenate the CAF components:
cr{workload}{environment}{region}{instance} - The strict rules apply to the registry name; repositories inside follow relaxed Docker naming
- Use
lower()andreplace()in IaC to guard the character rules, and check availability withaz acr check-name
Full rules are on the container registry naming page. AzureNamer generates compliant registry names automatically, applying the lowercase and no-hyphen rules. Storage accounts share the same hyphen-free style, see the storage account naming guide, and the complete CAF guide covers the pattern behind the prefix.
Keep reading
Azure API Management Naming Conventions: Service, APIs, and Products
CAF naming for Azure API Management. The service is a globally unique azure-api.net endpoint (1 to 50 chars); APIs, products, backends, and named values inside are function-named. Patterns and examples.
Read →Azure Service Bus Naming Conventions: Namespaces, Queues, and Topics
CAF naming for Azure Service Bus. The namespace is a globally unique servicebus.windows.net endpoint (6 to 50 chars); queues, topics, and subscriptions inside are relaxed. Patterns and examples.
Read →Azure Cosmos DB Naming Conventions: Account, Database, and Container
Azure Cosmos DB account names are globally unique DNS endpoints: 3 to 44 characters, lowercase letters, numbers, and hyphens. CAF patterns per API, plus databases and containers.
Read →Try AzureNamer
Generate CAF compliant names for all 200+ Azure resource types, free, no login required.
Open the Generator →