Every cloud team eventually runs into that moment: You’re staring at a list of resources in AWS, and nothing makes sense.
What’s Your Naming Convention?
A Practical Guide to Naming AWS Resources (That Actually Scales)
Every cloud team eventually runs into that moment:
You’re staring at a list of resources in AWS, and nothing makes sense.
prod-alb-app-01api-dev-main-1234orders-prod-stack2dev-ec2-whatever
And someone in the room inevitably asks:
“What’s our naming convention?, Do we have one?”
You turn and say: "um... not really, but we should!"
It’s a simple question that reveals a complex truth:
Naming patterns shape how your entire cloud ecosystem grows, scales, and stays maintainable.
And let's face it, naming is hard. I'm no exception, and I've found that over time my names have been all over the place. Recently I had to rebuild an entire deployment (pipeline, VPC, ALB, EC2, ASG, LaunchTemplates, ECS, ECR, CloudFront, S3, RDS, etc.), and even as I was building it I found myself using different patterns. And I thought, wait, let me document this, finalize my pattern and then share it with the community.
- It will help me find my own documentation and
- Others might benefit from it as well.
In this post, I'll break down common naming conventions—especially in AWS—explain different patterns and their trade-offs, highlight the limitations you need to plan for, and share my opinionated recommendation that you can adopt or adapt for your own workloads.
AWS doesn't prescribe a single, global "best" naming convention across all services. However if you look at there examples (placeholder) in the AWS console, you'll see some examples like:
When naming a parameter, you can use forward slashes (/) to organize it into a hierarchy. Learn more about hierarchies in the AWS Systems Manager User Guide.
/Environment/Type of computer/Application/Data
Or
prod/AppBeta/Mysqlin the Secrets Manager Console
What follows is the pattern I've standardized on after using different approaches in real systems—not an official AWS standard. The key takeaway: pick a pattern that makes sense for your team and be consistent.
Is This an Official AWS Best Practice? - No (not that I know of anyway)
AWS publishes plenty of guidance on tagging, multi-account strategy, and environment separation, but it does not define a single, canonical naming convention that every team must/should follow.
Personally, I wouldn't mind if they did post a best-practice naming convention, but I don't know of one. I think it's a bit of a missed opportunity.
This post is my opinionated take on a naming pattern that works for me. What matters most isn't which specific pattern you choose, but that you:
- Pick one pattern and stick with it consistently
- Ensure it works with your IaC tools (CDK, Terraform, etc.)
- Make it understandable for your team
- Plan for AWS resource naming limits
Different teams legitimately prefer different patterns. The key is consistency—it makes testing, deployments, and debugging significantly easier.
🎯 Common Naming Patterns: Which One Works for You?
Over the years, I've used both environment-first and workload-first naming in real projects. After living with both, I've standardized on environment-first as my default because it aligns with how I structure AWS accounts and think about deployments.
But here's the important part: both patterns are valid. What matters is picking one and being consistent.
Let's look at the two main approaches:
⭐ My Recommended Pattern: environment-workload-resource
This is the pattern I've standardized on:
environment-workload-resource
Examples:
prod-orders-dynamodb
dev-payments-lambda
stage-webapp-api
Why environment-first works for me:
✔ 1. Single Environment Per AWS Account
In many of my projects, I deploy a single environment to a single AWS account. When that's the case, I can omit the environment prefix entirely:
orders-dynamodb
payments-lambda
webapp-api
This keeps names short and clean while still being clear about what the resource does.
✔ 2. Environment Filtering Comes First
When I need to filter or search resources, I almost always start by thinking: "What environment am I working in?"
- "Show me everything in prod"
- "List all dev resources"
- "Which stage resources need updating?"
Environment-first makes this natural:
prod-*
dev-*
stage-*
✔ 3. It Just Makes Sense to Me
After using both patterns, environment-first aligns better with how I mentally model my systems. When I'm debugging, deploying, or reviewing infrastructure, I think in terms of: environment → workload → specific resource.
This pattern reflects that mental model.
🔄 Extending Environment-First for Multi-Region
It's easy to extend environment-first patterns for multi-region deployments:
environment-workload-region-resource
Examples:
prod-orders-us-east-1-dynamodb
dev-payments-eu-west-1-lambda
stage-webapp-us-west-2-api
For SaaS multi-tenant systems:
prod-orders-tenant123-dynamodb
dev-payments-tenant456-lambda
🟡 Alternative Pattern: workload-environment-resource
This pattern is also widely used and has strong advocates:
workload-environment-resource
Examples:
orders-prod-dynamodb
payments-dev-lambda
webapp-stage-api
Why some teams prefer workload-first:
- Workload grouping: All resources for a workload are grouped together alphabetically
- Service-oriented thinking: Aligns with microservices architecture where you think "service-first"
- IaC structure: Some teams organize their IaC code by workload, not environment
This is a completely valid approach. Many successful teams use it consistently and it works great for them.
🔑 The Real Key: Pick One and Be Consistent
Here's the truth: both patterns work.
What actually matters:
- Consistency - Pick one pattern and use it everywhere
- Team alignment - Your entire team needs to understand and follow it
- Tool compatibility - Make sure it works with your CDK/Terraform setup
- Scalability - Ensure it extends when you add regions, tenants, etc.
Inconsistent naming causes far more problems than choosing the "wrong" pattern. Once you pick a convention:
- Testing becomes easier (you know where things are)
- Deployments become safer (less chance of targeting wrong resources)
- Debugging becomes faster (predictable patterns mean faster searches)
- Onboarding becomes simpler (new team members learn one pattern)
🔄 Namespace Prefixes (Optional but Powerful)
AWS and large enterprises often add org prefixes:
org-environment-workload-resource
Examples:
gc-prod-orders-api
gc-dev-payments-lambda
gc-stage-webapp-worker
Useful when:
- multiple teams share a single AWS account
- you want strict consistency across the organization
- you foresee future re-orgs or acquisitions
Replace org with a short tag, business unit, or platform name (e.g., gc, acme, platform).
🧱 My Full Opinionated Pattern
Here's the complete pattern I use, with all optional components:
[org]-[env]-[workload]-[region]-[resource]
All components are optional—use what makes sense for your setup.
Examples:
Full pattern with all components:
gc-prod-orders-us-east-1-api
gc-dev-payments-eu-west-1-lambda
gc-stage-webapp-us-west-2-worker
Single-account setup (no env needed):
gc-orders-api
gc-payments-lambda
gc-webapp-worker
Single-region setup (no region needed):
gc-prod-orders-api
gc-dev-payments-lambda
This convention handles:
- single and multi-environment setups
- single and multi-region deployments
- multi-tenant SaaS systems
- deep CDK/Terraform stacks
- long-term platform growth
🚨 The Naming Landmines: AWS Resources With Length Limits
Eventually everyone discovers the painful truth:
Some AWS resources have strict (and surprisingly short) naming limits.
Even if your naming convention is perfect, AWS will sometimes respond with:
- “Name too long”
- “Identifier exceeds allowed length”
- “Invalid characters”
Here are the most common problem areas.
⚠️ Common AWS Services With Name-Length Limits
AWS Lambda
- 64 characters max
- CDK adds suffixes (hashes, versions, roles)
S3 Buckets
- 63 characters max
- lowercase only
- must be globally unique
API Gateway
- Stages, route keys, integrations often limited to ~20–40 chars
- Long names break deployments
IAM Roles & Policies
- 64 characters max
- CDK often appends
Role,DefaultPolicy, and hashes
SNS Topics & SQS Queues
- 80 characters
- FIFO queues add
.fifo - State machine integrations add stack prefixes
CloudFront
- No human-readable resource names
- Tags/comments become the “name”
CloudWatch Log Groups
- 512 characters (more generous)
- But frameworks may generate very long paths
🧰 Strategies for Resources With Tight Name Limits
You don't want to abandon your naming convention just because Lambda refuses its 65th character.
Instead, use these patterns.
1. Use Consistent Abbreviations
Instead of:
gc-aplos-calculation-engine-prod-us-east-1-dynamodb
Use:
gc-aplos-calc-prod-use1-ddb
Common abbreviations:
| Full Word | Short |
|---|---|
| dynamodb | ddb |
| lambda | fn |
| application | app |
| service | svc |
| production | prod / prd |
| development | dev |
| us-east-1 | use1 |
| us-west-2 | usw2 |
2. Avoid Name Collisions During Resource Replacement
Here's a painful scenario: Your CDK or Terraform deployment needs to replace a resource (maybe you changed an immutable property). AWS creates the new resource before deleting the old one.
Problem: Both resources can't have the same name at the same time.
Result:
Error: Resource with name 'prod-orders-api' already exists
Deployment failed
This happens frequently with:
- Lambda functions (runtime changes, architecture changes)
- ECS services (capacity provider changes)
- IAM roles (policy changes that require replacement)
- Security groups (certain rule modifications)
Solution: Let AWS auto-generate the resource name and rely on tags for identification.
Instead of:
const lambda = new Function(this, 'OrdersAPI', {
functionName: 'prod-orders-api', // ❌ Can cause replacement issues
...
});
Use:
const lambda = new Function(this, 'OrdersAPI', {
// Let AWS generate the name ✅
...
});
Tags.of(lambda).add('Name', 'prod-orders-api');
Tags.of(lambda).add('Environment', 'prod');
Tags.of(lambda).add('Workload', 'orders');
This way, your resource gets a unique AWS-generated name (like MyStack-OrdersAPI-A1B2C3D4), but you can still filter and identify it using tags.
3. Move Meaning Into Tags Instead of Names
Even beyond replacement conflicts, tags provide more flexibility than names:
Name: aplos-prod-ddb
App: aplos
Environment: prod
Region: us-east-1
Team: platform
Tier: backend
Tags often outlive names.
4. Drop Redundant Prefixes for "Leaf-Level" Resources
If all resources live in the same stack, you can shorten inner resources:
Instead of:
gc-orders-prod-us-east-1-lambda
gc-orders-prod-us-east-1-logs
Use:
orders-lambda
orders-logs
The CloudFormation stack name provides the context.
5. Use Hashed Suffixes When Absolutely Necessary
Example:
calc-prod-lmb-f3a9c2
Where f3a9c2 is a short hash of the full logical name.
Great for:
- autogenerated resources
- tight name limits
- minimizing collisions
6. Let CDK or Terraform Auto-Name Internal Resources
For resources that don’t need human-readable names (e.g., IAM policies or log retention), let your IaC tool generate names automatically.
Add metadata via tags instead.
🧭 So… What Should You Use?
Here's the summary of my recommended approach:
✔ I use environment-first because:
- I often deploy single environments to single AWS accounts (can omit env prefix)
- I think "environment first" when filtering and searching resources
- It matches my mental model of how I structure infrastructure
✔ You might prefer workload-first if:
- You organize IaC code by service/workload
- You think in terms of "all resources for service X"
- Your team has a strong service-oriented architecture
✔ AWS auto-naming is a valid strategy if:
- You don't need human-readable names
- You don't need to filter resources by name
- You don't need to search for resources by name
- You have a service that may need replacement and you don't want to deal with name collisions
✔ Regardless of which you choose, plan for:
- AWS name length limits
- CDK/Terraform suffixes
- Multi-region workloads
- Metadata via tags
- Consistent abbreviations
The key takeaway:
- Pick the pattern that makes sense for how you and your team think about your infrastructure.
- Then be consistent.
- My only caveat is I may mix in AWS auto-naming (which happened the other day when an ECS service needed to be replaced, and there was no way around it w/o downtime), but I still use tags for identification.
Environment-first is my go-to, but it's not a universal law. What matters is that you choose one pattern and stick with it across your entire organization. Consistency makes testing, deployments, and debugging dramatically easier.
💬 Final Thoughts
Naming conventions seem trivial—until they hinder your speed and safety.
Once you’re dealing with:
- multiple regions
- multiple environments
- dozens of workloads
- deep IaC stacks
- strict AWS name limits
…your naming strategy becomes critical.
Start with a simple, consistent pattern.
Extend as you scale.
Stay flexible for AWS’s quirks.
Comments