Overview

A reusable convention for naming cloud and Kubernetes resources consistently across a project. Adopt it as-is, or adjust the handful of project-specific choices listed in How to adapt this to your project. Everything else is generic.


Why have a naming convention

A good name tells you what a resource is at a glance — in the cloud console, in kubectl, in Terraform state, and in the repo — without opening anything. A shared convention makes resources predictable and searchable, lets the same string serve as the Terraform identifier, the file path, and the runtime name, supports cost allocation and automation through consistent tags, and avoids collisions between environments, regions, and tenants.

How to adapt this to your project

Before using the patterns, your team makes a few decisions. The rest of the document doesn’t change.

DecisionWhat to pickValue used in this doc
Project codeShort identifier for the product/project, 2–4 charactersacme
EnvironmentsThe set of environment tokens you usedev, stg, prod
Cloud + regionsProvider and the short region tokensAWS · euc1, use1, …
Multi-tenant?Whether resources are shared or dedicated per tenantboth patterns shown
SeparatorCharacter between segments-
CasingCasing for all segmentslowercase kebab-case

Throughout this document, acme is a stand-in project code and tenant-a / tenant-b are stand-in tenant identifiers. Replace them with your own.

Single-tenant projects: ignore the tenant segment and Patterns 2–3 entirely. Pattern 1 alone covers everything you need.

General rules

  • Lowercase letters, digits, and the separator only — no spaces, underscores, or uppercase.
  • Segments always appear in the fixed order shown; never reorder them.
  • Keep tokens compact. Region and resource tokens are abbreviated specifically so they don’t contain the - separator and confuse parsing.
  • Respect provider limits. Some names have hard caps and uniqueness rules (for example, S3 bucket names are 3–63 characters and globally unique). Keep the purpose segment short.
  • One name everywhere: the same string in Terraform, in the repo path, and on the running resource.

Pattern 1 — Shared resources

Resources that serve the whole project or all tenants: VPC, the cluster, shared object storage, a shared database, container registries, and so on.

<project>-<env>-<region>-<resource>[-<purpose>]

Examples (project code acme):

acme-dev-euc1-eks            # Kubernetes cluster (dev) — shared across all tenants
acme-dev-euc1-vpc            # VPC for the dev environment
acme-prod-euc1-rds           # primary database
acme-prod-use1-rds           # same kind of database in a second region
acme-dev-r53-example-com     # DNS hosted zone — global, no region segment

purpose is optional. If there is only one resource of a given type in the environment (like the cluster), you can omit it.

Pattern 2 — Tenant-specific resources (multi-tenant projects only)

Resources dedicated to a single tenant/customer: dedicated buckets, IAM roles, secrets, and the like.

<project>-<tenant>-<env>-<region>-<resource>-<purpose>

Examples:

acme-tenant-a-dev-euc1-s3-backoffice      # storage bucket for tenant-a
acme-tenant-a-dev-euc1-sm-db-creds        # secret holding DB credentials
acme-tenant-b-prod-use1-s3-user-uploads   # uploads bucket for tenant-b

Pattern 3 — Tenant-scoped objects inside shared resources (multi-tenant only)

When you create a tenant-scoped logical object inside a shared resource (a database inside the shared DB server, a namespace inside the shared cluster, and so on), use the tenant identifier directly — no project, env, or resource prefix.

Container resourceTenant-scoped objectName
Shared cluster (acme-prod-euc1-eks)Kubernetes namespacetenant-a
Shared DB server (acme-prod-euc1-rds)Databasetenant-a
Shared DB serverDB user / roletenant-a

Examples:

# Inside acme-prod-euc1-eks
namespace: tenant-a
namespace: tenant-b

# Inside acme-prod-euc1-rds
CREATE DATABASE "tenant-a";
CREATE USER  "tenant-a" WITH PASSWORD '...';

If the same tenant has multiple objects of the same kind inside one shared resource, append a purpose segment:

tenant-a-app          # main app DB
tenant-a-analytics    # analytics DB for the same tenant

Segments

PartMeaningExample
projectProject/product code, 2–4 charactersacme
tenantTenant identifier (Patterns 2 & 3 only)tenant-a, tenant-b
envEnvironmentdev, stg, prod
regionCloud region code, short formeuc1, euw1, use1, usw2, apse1
resourceResource type, 2–4 characterss3, rds, eks, lam
purposeWhat the resource is for (kebab-case)backoffice, user-uploads

Region tokens

Compact region codes, with dashes removed so they don’t collide with the - separator. The table below is for AWS; keep only the regions you actually use.

AWS regionToken
eu-central-1 (Frankfurt)euc1
eu-west-1 (Ireland)euw1
eu-west-2 (London)euw2
eu-north-1 (Stockholm)eun1
us-east-1 (N. Virginia)use1
us-east-2 (Ohio)use2
us-west-2 (Oregon)usw2
ap-south-1 (Mumbai)aps1
ap-southeast-1 (Singapore)apse1
ap-southeast-2 (Sydney)apse2
ap-northeast-1 (Tokyo)apne1
ca-central-1 (Canada)cac1
sa-east-1 (São Paulo)sae1

Other clouds: apply the same idea — pick a short, dash-free token per region. For example, usc1 for GCP us-central1, or weu for Azure West Europe.

Resource type tokens

Common abbreviations. Extend the list for your stack; keep each token 2–4 characters and unique within your naming scheme.

Cloud (AWS)TypeKubernetesType
vpcVPCnsNamespace
sgSecurity groupcmConfigMap
eksKubernetes clustersecSecret
ec2EC2 instancesvcService
asgAuto Scaling groupdepDeployment
rdsRelational databasestsStatefulSet
s3Object storage bucketdsDaemonSet
ecrContainer registryingIngress
lamLambda functionsaServiceAccount
smSecrets Manager secrethpaHorizontalPodAutoscaler
ssmSSM parameterpvcPersistentVolumeClaim
iamIAM role / policycrClusterRole
r53Route 53 hosted zonecrbClusterRoleBinding
cfCDN distributionroleRole
sqs / snsQueue / topicrbRoleBinding
ddbNoSQL table
alb / nlbLoad balancers
kmsEncryption key

Global (region-less) resources

Some services are global — they don’t live in a region. For these, omit the region segment entirely:

acme-dev-r53-example-com         # DNS hosted zone
acme-prod-iam-eks-admin          # IAM role
acme-prod-cf-static-assets       # CDN distribution

Exceptions — keep upstream/canonical names

The convention above applies to infrastructure you build and own. For third-party tools you deploy from upstream, keep their canonical names as-is. Don’t add your project prefix. This applies to:

  • Helm releasesnginx-ingress, cert-manager, external-dns, argocd, prometheus, grafana, external-secrets, and so on.
  • Kubernetes operators and controllers — use their default install names.
  • Open-source services deployed into your infra — keep the upstream project name.
  • System namespaceskube-system, ingress-nginx, cert-manager (you don’t rename these anyway).

Kubernetes resources (ConfigMaps, Secrets, etc.)

In-namespace Kubernetes objects you manage follow the same convention as cloud resources. This keeps Terraform file names, repo structure, and actual cluster resources aligned — eks-resources/config-maps/acme-dev-euc1-cm-backoffice.tf produces a ConfigMap named acme-dev-euc1-cm-backoffice. One name everywhere — in the repo and in kubectl.

Shared (Pattern 1):

<project>-<env>-<region>-<resource>-<purpose>

Tenant-specific (Pattern 2):

<project>-<tenant>-<env>-<region>-<resource>-<purpose>

Examples:

# Shared — in kube-system, monitoring, or any shared namespace
acme-dev-euc1-cm-backoffice            # ConfigMap
acme-prod-euc1-cm-fluent-bit-config    # shared logging config
acme-prod-euc1-sec-pull-secret         # shared image-pull secret
acme-prod-euc1-cr-platform-admin       # ClusterRole

# Tenant-specific — inside namespace tenant-a
acme-tenant-a-prod-euc1-cm-backoffice      # ConfigMap
acme-tenant-a-prod-euc1-sec-db-creds       # Secret with DB credentials
acme-tenant-a-prod-euc1-svc-backoffice     # Service
acme-tenant-a-prod-euc1-dep-backoffice     # Deployment
acme-tenant-a-prod-euc1-ing-backoffice     # Ingress
acme-tenant-a-prod-euc1-sa-backoffice      # ServiceAccount
acme-tenant-a-prod-euc1-hpa-backoffice     # HorizontalPodAutoscaler

Tags

The name is for humans browsing the cloud console. Tags are for cost allocation, filtering, and automation. Standardize one tag set and fill the values per resource.

# Shared
tags = {
  company     = "<company>"
  project     = "<project>"
  environment = "<env>"
  region      = "<region>"
  scope       = "shared"
  terraform   = "true"
}
 
# Tenant-specific
tags = {
  company     = "<company>"
  project     = "<project>"
  environment = "<env>"
  region      = "<region>"
  scope       = "tenant"
  tenant      = "<tenant>"
  terraform   = "true"
}