š Executive Summary
TL;DR: Hardcoded container names in Docker Compose lead to collisions and lost productivity in shared development environments because Docker Compose is declarative and performs only one-time variable substitution. Solutions involve using environment variables via a .env file for static differentiation, wrapper shell scripts for true runtime dynamism (e.g., based on Git branch), or templating engines for complex, conditional configurations.
šÆ Key Takeaways
- Docker Compose is declarative, performing a one-time variable substitution, and lacks inherent dynamic logic for
container\_namewithout external scripting. - Environment variables, particularly loaded from a
.envfile, offer a simple, Docker-native way to provide static but differentiated container names for local development. - Wrapper shell scripts enable truly dynamic container naming by calculating and exporting environment variables (e.g., current Git branch) before executing the
docker-compose upcommand. - For complex scenarios requiring conditional logic or extensive configuration, templating engines like Gomplate or Jinja2 can pre-process a template into a final
docker-compose.ymlfile.
Learn why Docker Compose struggles with dynamic container names and discover three practical solutions, from simple environment variables to powerful shell scripts, to manage your services effectively.
How to Name Your Containers Dynamically in Docker Compose (Without Losing Your Mind)
I still remember the day. It was about 3 PM on a Tuesday. Two of our best junior engineers were practically at each otherās throats. One minute, Janeās feature was working perfectly on our shared dev-integration-01 server. The next, it was completely broken, throwing weird database connection errors. Meanwhile, Mike, working on a different feature, was complaining that his changes werenāt showing up at all. It took us a solid hour to figure out what happened: they both ran docker-compose up from the same project directory for their respective feature branches. Since the container\_name was hardcoded, Mikeās deployment simply killed and replaced Janeās containers. An hour of productivity, gone. All because of a static name in a YAML file. Thatās when I made it a team rule: we never hardcode container names for non-production environments again.
First, Why Is This So Annoying?
Before we dive into the fixes, letās understand the root of the problem. A docker-compose.yml file is declarative, not procedural. Itās a blueprint that says, āthis is the state I want the world to be in.ā Itās not a script that runs commands. When you run docker-compose up, it does a simple, one-time variable substitution from your environment and then builds its plan. It has no concept of loops, functions, or dynamic logic like āget the current git branch nameā on its own. Itās a feature, not a bug, designed for simplicity and predictability. But that simplicity is exactly what causes this headache.
The Solutions: From Quick Hack to Enterprise-Grade
Iāve seen this problem tackled in a few ways over the years. Here are my three go-to methods, ranging from the simplest to the most robust.
1. The Quick Fix: Environment Variables and a .env File
This is the most common and āDocker-nativeā way to handle this. Docker Compose will automatically look for a file named .env in the same directory and load its contents as environment variables. This is perfect for differentiating between a userās local machine or different static environments.
Step 1: Modify your docker-compose.yml
Instead of a hardcoded name, use variable substitution syntax ${VARIABLE_NAME}. You can even provide a default fallback value with ${VARIABLE:-default_value}.
version: '3.8'
services:
web:
image: nginx:latest
container_name: ${PROJECT_NAME:-myproject}-web
ports:
- "8080:80"
db:
image: postgres:14
container_name: ${PROJECT_NAME:-myproject}-db
environment:
- POSTGRES_PASSWORD=supersecret
Step 2: Create a .env file
In the same directory, create a file named .env. This file should not be committed to source control (add it to your .gitignore!).
# .env file for Darian's local setup
PROJECT_NAME=darian-feature-x
Now, when I run docker-compose up, my containers will be named darian-feature-x-web and darian-feature-x-db. If Jane creates her own .env file with PROJECT\_NAME=jane-bugfix-y, her containers wonāt collide with mine. Simple and effective.
Pro Tip: Create a
.env.examplefile and commit that to your repository. It shows other developers what variables they need to create in their own local.envfile to get the project running.
2. The āIn the Trenchesā Fix: A Wrapper Shell Script
The .env file is great, but itās static. What if you want the name to be truly dynamic, based on something like the current Git branch, the username, or a timestamp? Thatās where a simple shell script comes in. This is my personal favorite for complex development environments.
The idea is to use a script to set the environment variables just before running the Docker Compose command.
Step 1: Keep your docker-compose.yml the same as above.
Make sure itās expecting an environment variable, like ${PROJECT_NAME}.
Step 2: Create a wrapper script (e.g., start-dev.sh)
This script will calculate the dynamic name and then execute the compose command.
#!/bin/bash
# Clean up branch name to be Docker-friendly (remove slashes, etc.)
BRANCH_NAME=$(git rev-parse --abbrev-ref HEAD | sed 's/[^a-zA-Z0-9]/-/g')
# Export the variable so docker-compose can see it
export PROJECT_NAME="myapp-${BRANCH_NAME}"
echo "Starting environment for project: ${PROJECT_NAME}"
# Pass all other arguments to docker-compose
docker-compose up "$@"
Now, instead of running docker-compose up, the team runs bash start-dev.sh. If Iām on the feature/user-auth branch, my containers will be named myapp-feature-user-auth-web, etc. This completely solved the āstomping on each otherās workā problem on our shared dev servers.
3. The āWeāve Outgrown Composeā Option: Templating Engines
Sometimes, even a shell script isnāt enough. You might have complex logic, conditional service inclusion, or just a deep-seated hatred for bash scripting. When you reach this point, youāre essentially outgrowing what Docker Compose was designed for. The next logical step is a templating engine.
Tools like gomplate or even just using Python with Jinja2 can pre-process a template file into a final docker-compose.yml.
How it works:
- You create a template file, letās call it
docker-compose.yml.tpl, with its own logic. - You run the templating tool, feeding it data (like a values.yaml file).
- The tool generates a standard, static
docker-compose.ymlfile. - You then run
docker-compose -f generated-compose.yml up.
This approach gives you maximum power and is essentially a āliteā version of what tools like Helm do for Kubernetes. Itās overkill for most local development, but for managing multiple complex, semi-permanent environments, itās a lifesaver.
Warning: This adds a layer of abstraction. If you go this route, make sure the process is well-documented. A new developer should be able to understand that the
docker-compose.ymlis an ephemeral, generated file and not the source of truth.
Which One Should You Choose?
As with most things in DevOps, the answer is āit depends.ā Hereās my simple breakdown:
| Solution | Best For | Pros | Cons |
| .env File | Individual local development, simple environment splits (dev/staging). | Extremely simple, built-in functionality. | Static; requires manual changes for different contexts. |
| Wrapper Script | Shared dev servers, CI/CD, pull request environments. | Truly dynamic, flexible, automates naming conventions. | Adds another file/script to maintain. |
| Templating Engine | Complex deployments with conditional logic or many configurable parts. | Maximum power and logic, prepares you for Kubernetes-style thinking. | Overkill for most projects, adds a build step and complexity. |
My advice? Start with the .env file. When you find yourself wishing it could do more, graduate to the wrapper script. Itās the sweet spot for 90% of the use cases Iāve encountered. And if youāre managing dozens of microservices with complex interdependencies⦠well, it might be time to start learning Helm.
Happy containerizing,
Darian Vance
Senior DevOps Engineer & Lead Cloud Architect, TechResolve
š Read the original article on TechResolve.blog
ā Support my work
If this article helped you, you can buy me a coffee:

Top comments (0)