How do I define the name of image built with docker-compose
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
To name an image built with Docker Compose, add the image key alongside the build key in your service definition. When both are present, Compose builds the image from the specified Dockerfile and tags it with the name you provide in image. Without an explicit image key, Compose auto-generates a name using the pattern {project_name}-{service_name}, which is often unclear in image listings and CI pipelines.
Default Image Naming Behavior
When you only specify build without image, Docker Compose constructs the image name automatically:
Running docker compose build produces an image named {project}-webapp, where {project} defaults to the directory name containing your compose.yaml file. If the directory is called my-app, the image becomes my-app-webapp.
This default name has several problems in practice:
- It changes if you move the project to a different directory
- It is not suitable for pushing to a container registry
- It makes
docker imagesoutput harder to scan when you have many projects
Setting an Explicit Image Name
Add the image key to your service to control the name:
When Compose builds this service, it tags the resulting image as mycompany/webapp:1.0.0. You can then push it directly to a registry without re-tagging:
Name Format Rules
Docker image names must follow specific conventions:
| Rule | Example | Valid? |
| Lowercase only | myapp | Yes |
| With namespace | mycompany/myapp | Yes |
| With registry | ghcr.io/mycompany/myapp | Yes |
| With tag | myapp:v2.1 | Yes |
| Uppercase letters | MyApp | No |
| Spaces | my app | No |
Special characters (except -, _, ., /) | my@app | No |
If no tag is specified, Docker defaults to :latest.
Multiple Services with Custom Names
Each service can have its own image name. This is essential for multi-service applications where you push individual components to a registry:
Running docker compose build builds all three images with distinct, registry-ready names.
Using Environment Variables for Dynamic Names
Hardcoding version tags in your compose file means editing the file for every release. Environment variables solve this:
You can then control the image name at build time:
Using a .env File
For team-shared defaults, put the variables in a .env file alongside your compose file:
Docker Compose reads .env automatically. Individual developers or CI jobs can override these values through environment variables or by specifying an alternate env file:
The image Key Without build
When you specify image without build, Compose pulls the image from a registry instead of building it:
This is how you reference pre-built images. The key distinction:
| Configuration | Behavior |
build only | Builds and auto-names the image |
image only | Pulls from registry |
build + image | Builds and tags with the specified name |
Controlling the Project Name
Since the default image name includes the project name, you can also influence it by setting the project name explicitly:
This produces myproject-webapp instead of using the directory name. You can also set it via the command line:
Or through the COMPOSE_PROJECT_NAME environment variable:
However, this only changes the auto-generated prefix. For registry-ready names, always use the image key explicitly.
Build and Push Workflow
A complete CI workflow for building, naming, and pushing images:
The docker compose push command pushes the image using the name defined in the image key. Without that key, there is no registry-compatible name to push.
Compose V1 vs V2
The naming behavior differs slightly between Compose V1 (docker-compose) and Compose V2 (docker compose):
| Aspect | V1 (docker-compose) | V2 (docker compose) |
| Default separator | _ (underscore) | - (hyphen) |
| Default name | {dir}_{service} | {dir}-{service} |
version key | Required | Optional (ignored) |
| Command syntax | docker-compose build | docker compose build |
If you are migrating from V1 to V2 and scripts depend on the auto-generated image name, the separator change can break things. Using an explicit image key avoids this problem entirely.
Note: the version key (like version: '3.8') is no longer required in Compose V2 and is officially deprecated. You can safely remove it from your compose files.
Common Pitfalls
Forgetting to include both build and image together is the most common mistake. With only build, the image gets an auto-generated name that is not useful for pushing to a registry. With only image, Compose tries to pull from a registry instead of building locally.
Relying on the auto-generated project name makes image names fragile. Renaming or moving the project directory changes the image name, which can silently break deployment scripts.
Using uppercase letters in image names causes Docker to reject the tag. All image name components must be lowercase.
Hardcoding version tags in the compose file means editing YAML for every release. Use environment variables with sensible defaults instead.
Not specifying a tag defaults to :latest, which is problematic for production because it is mutable and does not identify a specific version. Always tag releases with a version number or commit hash.
Forgetting that Compose V1 and V2 use different separators (_ vs -) in auto-generated names can break scripts that parse image names.
Summary
- Add the
imagekey alongsidebuildto name your built image explicitly. - Without
image, Compose auto-generates a name from the project and service name, which is fragile and not registry-ready. - Use environment variables with defaults for dynamic tagging in CI/CD pipelines.
- Each service in a multi-service compose file can have its own image name.
- Prefer explicit
imagenames over relying on project name conventions, especially when pushing to registries. - The
versionkey in compose files is deprecated in Compose V2 and can be removed.
Related reading
- How do I deploy updated Docker images to Amazon ECS tasks?
- How do I Docker COPY as non root?
- How do I edit a file after I shell to a Docker container?
- How do I edit a file after I shell to a Docker container?
- How do I disable log messages from the Requests library?
- How do I discover memory usage of my application in Android?
- How do I force Kubernetes to re-pull an image?
- How do I get into a Docker container's shell?

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.