Compose Service Config
Compose Service Config defines Docker service settings, dependencies, and runtime options for reliable container deployment
Compose service configuration defines the declarative properties of an individual service within a Docker Compose application. A service represents a component that can be instantiated as one or more containers, while its configuration describes the image to use, the execution environment to establish, the resources to make available, and the conditions governing its operation.
Within a Compose file, service definitions appear under the top-level services element. Each service is identified by a name and associated with a collection of configuration attributes that describe how Compose should create and manage its containers.
These attributes can address several distinct aspects of container execution. They may identify an existing image or describe how to build one, provide environment variables, configure network connectivity, attach persistent storage, establish resource limits, define dependencies, or specify how containers should behave when their main processes terminate.
The resulting service definition acts as a declarative description of the intended operating conditions rather than a sequence of commands that must be executed manually.
A service does not need to declare every available configuration attribute. The appropriate configuration depends on the component's responsibilities, its runtime requirements, and its relationship with the rest of the application.
A service that runs a prebuilt image using its default settings may require only an image reference. A custom application that communicates with a database, maintains persistent data, and exposes an HTTP interface may require a more extensive definition.
Understanding Compose service configuration therefore involves recognizing both the individual responsibilities of its attributes and the relationships among them.
The Structure of a Compose Service Definition
A Compose service is declared as a named mapping beneath the services element.
The service name identifies the component within the Compose application, while the attributes nested beneath it describe the component's configuration.
A minimal example is:
services:
api:
image: myapi:2.3.0
The services element introduces the collection of application services. The api key identifies one service within that collection, and the image attribute specifies the container image associated with it.
The configuration does not explicitly define networking, storage, environment variables, restart behavior, or resource limits. Compose and the container runtime apply their respective defaults wherever the configuration does not establish a different requirement.
Additional attributes can be introduced as the service's needs become more specific:
services:
api:
image: myapi:2.3.0
ports:
- "8080:8080"
environment:
LOG_LEVEL: info
restart: unless-stopped
The service still represents the same logical application component. Its definition now establishes additional requirements concerning port publication, container environment variables, and restart behavior.
This illustrates an essential property of Compose service configuration: it is extensible without requiring a different structural model for every type of application component.
The same basic service definition can describe a web server, database, message broker, background worker, or custom application, provided that its attributes accurately express the relevant execution requirements.
Service Identity and Container Identity
The name assigned to a Compose service is not necessarily the name of its image or the name of an individual container.
Consider:
services:
api:
image: myapi:2.3.0
Here, api identifies the service within the Compose application, while myapi:2.3.0 identifies the Docker image used to create its containers.
Compose also assigns identities to the container instances associated with the service.
For example, a project named myapp may create a container named:
myapp-api-1
These identities serve different purposes.
The service name allows Compose to refer to a logical application component. The image reference identifies the artifact from which containers are created. The container name identifies a particular container instance.
This distinction becomes especially relevant when a service is scaled to multiple containers.
Several container instances may belong to the same Compose service and use the same image while retaining distinct container identities.
The service configuration describes the common operating requirements of those instances rather than requiring a separate service definition for each container.
The Main Configuration Responsibilities
The available service attributes can be understood through the responsibilities they fulfill.
Some attributes determine what software will run. Others define how that software interacts with its environment, what resources it can access, and how the container runtime should manage its execution.
The following diagram groups these responsibilities around the individual service definition.
The diagram does not imply that every service must define every group of attributes or that Compose processes them in the displayed order.
Instead, it illustrates how configuration properties contribute to different aspects of the service's intended operating conditions.
A service definition becomes more extensive when its requirements demand additional configuration, not simply because more attributes are available.
Image Selection and Build Configuration
Every container requires an image from which its filesystem and initial execution environment can be established.
A Compose service can identify an existing image through the image attribute:
services:
cache:
image: redis:7
The image reference establishes the software artifact that the service will use.
When the image is not already available locally, Compose can obtain it according to the applicable image acquisition behavior.
A service that must be built from application source can instead declare a build configuration:
services:
api:
build:
context: ./api
dockerfile: Dockerfile
The build attribute establishes how the image can be constructed. The build context identifies the source material made available to the builder, while the Dockerfile describes the image construction instructions.
Both attributes may also appear together:
services:
api:
build:
context: ./api
dockerfile: Dockerfile
image: myapi:2.3.0
In this arrangement, the service possesses both a build definition and an explicit image reference.
The pull_policy attribute can further influence whether Compose retrieves an existing image or builds it from source.
These attributes belong to the service configuration because they determine the software artifact from which the service's containers are created.
Process Execution Configuration
An image provides a default execution configuration, but individual services may need to adjust how their application processes start.
Compose supports attributes that influence the command, entrypoint, working directory, and user identity associated with a container.
For example:
services:
worker:
image: myapp:2.3.0
command: ["python", "-m", "app.worker"]
working_dir: /app
user: "1000:1000"
The command attribute overrides the image's default command. The working_dir attribute establishes the working directory for the container's main process, and user specifies the user identity under which that process runs.
These options do not change the underlying image. They customize the execution conditions of containers created from it.
This allows different services to use the same image while performing different application responsibilities.
For example, an API service and a background worker might share an application image but start different processes:
services:
api:
image: myapp:2.3.0
command: ["python", "-m", "app.api"]
worker:
image: myapp:2.3.0
command: ["python", "-m", "app.worker"]
The example assumes the image contains both application modules and the required Python environment.
The service configurations distinguish the components by their execution commands rather than requiring separate images for each responsibility.
Environment Configuration
Applications frequently need runtime settings that vary between installations or operating environments.
Compose provides environment-related attributes so these values can be supplied without modifying the application's source code or rebuilding its image.
The environment attribute declares variables that will be available inside the service's containers.
services:
api:
image: myapi:2.3.0
environment:
LOG_LEVEL: info
APP_MODE: production
The application can read these variables during execution and adjust its behavior accordingly.
When several variables are required, the env_file attribute allows them to be supplied through an external file:
services:
api:
image: myapi:2.3.0
env_file:
- ./api.env
The referenced file might contain:
LOG_LEVEL=info
APP_MODE=production
Both approaches provide environment variables to the container, but they organize the source of those values differently.
A service can also combine them:
services:
api:
image: myapi:2.3.0
env_file:
- ./api.env
environment:
LOG_LEVEL: warning
When the same variable is declared through both attributes, the value provided by environment takes precedence over the corresponding value from the service's env_file.
Compose Variable Interpolation
Environment variables supplied to a container should be distinguished from variables used to resolve the Compose configuration itself.
For example:
services:
api:
image: "myapi:${APP_VERSION:-2.3.0}"
Here, Compose evaluates the variable expression while processing the configuration.
If APP_VERSION is available through an applicable interpolation source, its value is used in the image reference. Otherwise, the declared default is used.
The resulting image reference does not automatically cause APP_VERSION to become an environment variable inside the container.
That would require an appropriate service configuration declaration.
Similarly, a Compose .env file used for interpolation is not equivalent to declaring that file through a service's env_file attribute.
These mechanisms serve related but distinct purposes: one helps resolve the Compose model, while the other supplies variables to the container environment.
Sensitive configuration values also require appropriate handling. Environment variables should not automatically be considered confidential storage, and Compose provides secret-related configuration mechanisms for applications that need access to sensitive data.
Network Connectivity and Port Publication
Network configuration determines how service containers communicate with other components and how selected container ports become accessible outside their network environment.
A service can declare published ports through the ports attribute:
services:
api:
image: myapi:2.3.0
ports:
- "8080:8080"
This mapping publishes container port 8080 through host port 8080.
By default, when no host IP address is specified, Docker publishes the port on the host's available network interfaces, subject to the applicable container engine and host networking configuration.
A service intended to be reached only through the host's loopback interface can specify that address explicitly:
services:
api:
image: myapi:2.3.0
ports:
- "127.0.0.1:8080:8080"
The distinction matters because port publication determines an access path from the host environment to the container.
It is not the same as communication between services connected to the same Compose network.
Service Network Membership
Services can declare network membership using the networks attribute:
services:
api:
image: myapi:2.3.0
networks:
- app-net
db:
image: postgres:17
networks:
- app-net
networks:
app-net:
Both services are connected to the same declared network.
Within that network, Compose provides service-name-based discovery, allowing the API to address the database using the service name db.
The database does not need a published host port merely to communicate with the API through their shared Compose network.
The top-level networks element defines the named network resource, while each service's networks attribute declares its membership in that resource.
This illustrates the relationship between service-level configuration and the broader application model.
Storage and Filesystem Configuration
Containers have writable filesystems, but data stored exclusively in a container's writable layer is tied to that container's lifecycle.
Services that require persistent data or access to host files can declare mounts through the volumes attribute.
A database service, for example, may use a named volume:
services:
db:
image: postgres:17
volumes:
- db-data:/var/lib/postgresql/data
volumes:
db-data:
The service-level volumes attribute identifies the mount required by the container.
The top-level volumes element declares the named volume resource.
These two declarations are related but have different responsibilities.
The service configuration establishes how the container accesses storage. The top-level resource declaration establishes the volume that Compose can create or reference.
This distinction also helps explain why the complete configuration of an application cannot always be represented exclusively within its individual service definitions.
Some requirements involve shared resources that exist independently of any single service.
Bind Mounts and Named Volumes
A service may also mount a directory from the host filesystem:
services:
api:
image: myapi:2.3.0
volumes:
- ./config:/app/config:ro
The example mounts the local config directory into the container at /app/config.
The ro suffix establishes a read-only mount.
Unlike a named volume managed through the container engine, this bind mount references a path in the host filesystem.
Both forms are declared through the service's storage configuration, but their underlying storage relationships differ.
The appropriate choice depends on whether the service requires persistent application data, access to host-managed files, or another specific filesystem arrangement.
Service Dependencies and Startup Conditions
Applications commonly contain components whose successful operation depends on other services.
An API may require a database, while a worker may require an application-specific messaging service.
Compose provides the depends_on attribute to express dependencies among services.
services:
api:
image: myapi:2.3.0
depends_on:
- db
db:
image: postgres:17
This configuration tells Compose that the db service is a dependency of the api service.
Compose uses the dependency relationship when determining service creation and removal order.
However, starting a container does not necessarily mean that the application inside it is ready to accept requests.
A database process may still be initializing after its container has entered the running state.
Dependency Readiness
A dependency can be associated with a health condition:
services:
api:
image: myapi:2.3.0
depends_on:
db:
condition: service_healthy
db:
image: postgres:17
environment:
POSTGRES_USER: app
POSTGRES_DB: appdb
POSTGRES_PASSWORD: "${DB_PASSWORD:?Set DB_PASSWORD}"
healthcheck:
test:
- CMD-SHELL
- 'pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"'
interval: 5s
timeout: 3s
retries: 5
The healthcheck attribute defines a command used to evaluate the database container's health.
The service_healthy dependency condition instructs Compose to wait for the database's health condition before starting the dependent API service.
The double dollar signs in the health check preserve the variable references for evaluation inside the container rather than allowing Compose to interpolate them while reading the YAML configuration.
This readiness check addresses the dependency's startup condition. It does not guarantee that the dependency will remain healthy indefinitely or that the application will never experience connection failures later.
Service dependency configuration therefore provides a means of coordinating startup behavior, while applications remain responsible for handling operational failures appropriately.
Resource Allocation and Constraints
A service may need explicit constraints concerning its access to CPU, memory, or other computing resources.
Resource configuration becomes relevant when multiple containers share the same host or when an application must operate within defined capacity boundaries.
For example:
services:
api:
image: myapi:2.3.0
cpus: 0.5
mem_limit: 512m
The cpus attribute establishes a CPU allocation limit expressed as a fractional number of CPUs.
The mem_limit attribute establishes a memory allocation limit for the service container.
Such settings help express the intended resource constraints of a component.
They do not independently establish that the component will perform adequately within those limits. Actual resource requirements depend on the application's behavior and workload.
Deploy Resource Configuration
Compose also supports resource declarations through the Deploy Specification:
services:
api:
image: myapi:2.3.0
deploy:
resources:
limits:
cpus: "0.5"
memory: 512M
This configuration expresses resource limits using the deploy.resources.limits structure.
The Deploy Specification also defines resource reservations and other deployment-related attributes.
The extent to which deployment attributes are supported or enforced depends on the Compose implementation and target platform.
Resource settings should therefore be selected according to the environment in which the service will actually run, rather than assuming that every deployment implementation handles all configuration attributes identically.
Container Lifecycle and Restart Behavior
Service configuration can influence what happens when a container terminates.
The restart attribute establishes a restart policy that the container runtime applies under the conditions defined by that policy.
For example:
services:
api:
image: myapi:2.3.0
restart: unless-stopped
The unless-stopped policy allows the runtime to restart the container after termination while respecting the policy's stopped-container behavior.
Other supported policies include no, always, and on-failure.
The appropriate policy depends on the role of the service.
A continuously operating API may require different restart behavior from a short-lived task intended to execute successfully and terminate.
Lifecycle configuration also includes attributes that influence shutdown behavior.
For example:
services:
api:
image: myapi:2.3.0
restart: unless-stopped
stop_grace_period: 30s
The stop_grace_period attribute establishes the period Compose allows for graceful termination before forcefully stopping a container that has not exited.
These settings describe how the runtime should manage the service's containers around process termination and shutdown.
They do not replace the application's responsibility to handle termination signals, complete necessary cleanup, or preserve important data.
A Representative Service Configuration
The preceding attributes can be combined into a more substantial definition.
Consider an application containing a custom API service and a PostgreSQL database.
The API must be built from local source, exposed through a host port, supplied with runtime settings, connected to a database network, and configured with resource and lifecycle requirements.
The following example illustrates how these requirements can be expressed within a single Compose application.
services:
api:
build:
context: ./api
dockerfile: Dockerfile
image: myapi:2.3.0
pull_policy: build
ports:
- "127.0.0.1:8080:8080"
env_file:
- ./api.env
environment:
LOG_LEVEL: info
DATABASE_HOST: db
DATABASE_PORT: "5432"
volumes:
- api-data:/data
networks:
- app-net
depends_on:
db:
condition: service_healthy
cpus: 0.5
mem_limit: 512m
restart: unless-stopped
db:
image: postgres:17
environment:
POSTGRES_USER: app
POSTGRES_DB: appdb
POSTGRES_PASSWORD: "${DB_PASSWORD:?Set DB_PASSWORD}"
volumes:
- db-data:/var/lib/postgresql/data
networks:
- app-net
healthcheck:
test:
- CMD-SHELL
- 'pg_isready -U "$$POSTGRES_USER" -d "$$POSTGRES_DB"'
interval: 5s
timeout: 3s
retries: 5
restart: unless-stopped
volumes:
api-data:
db-data:
networks:
app-net:
The example assumes the local API build directory and api.env file exist, that DB_PASSWORD has been supplied, and that the API image contains an application that listens on container port 8080. The application's database credentials and any additional requirements must also be configured appropriately.
The API definition contains several configuration responsibilities, but these are not independent fragments.
The image and build settings establish the artifact used by the service. The port mapping creates an access path from the host. The environment attributes provide runtime settings, while the named volume establishes a persistent storage mount.
Network membership allows the API and database to communicate through their shared Compose network.
The dependency condition coordinates API startup with the database health check, and the resource and restart attributes express additional runtime requirements.
The database service has a separate configuration because it represents a different application component with different responsibilities.
The top-level volume and network declarations define resources referenced by the individual services.
The result is a coherent application model assembled from distinct service definitions and shared resource declarations.
Minimal and Extensive Service Definitions
A service configuration should be no more extensive than its actual requirements demand.
Consider a cache service that uses an existing image and requires no customization beyond its default execution behavior:
services:
cache:
image: redis:7
This is a valid and meaningful service definition.
Compose supplies the default network when no explicit network configuration is provided, and the image contributes its default execution settings.
Adding an explicit network, custom command, environment variables, or persistent storage would only be necessary if the intended behavior required them.
A custom application may have substantially different needs:
services:
api:
build: ./api
image: myapi:2.3.0
environment:
APP_MODE: production
ports:
- "127.0.0.1:8080:8080"
restart: unless-stopped
The second service requires more configuration because its image construction, runtime environment, external accessibility, and lifecycle expectations are more specific.
The difference in configuration length does not indicate that one service is inherently better configured than the other.
The relevant question is whether each definition accurately describes the requirements of the component it represents.
A minimal service is appropriate when defaults satisfy its requirements. A more extensive service is appropriate when those defaults must be modified or additional operating conditions must be established.
Configuration Organization and Readability
As service definitions become more extensive, their readability becomes an important maintenance concern.
Compose does not require all service attributes to appear in one universally prescribed order. This allows configurations to be organized according to conventions that make sense for the project.
Related attributes can be placed near one another to make their relationships easier to recognize.
For example:
services:
api:
# Image construction and identification
build:
context: ./api
dockerfile: Dockerfile
image: myapi:2.3.0
# Runtime configuration
environment:
APP_MODE: production
LOG_LEVEL: info
# Network accessibility
ports:
- "127.0.0.1:8080:8080"
# Container lifecycle
restart: unless-stopped
The comments describe the responsibility of each configuration group.
Comments are particularly useful when they explain a non-obvious decision rather than simply repeat the meaning of the adjacent attribute.
For example, explaining why a port is restricted to the loopback interface provides useful operational context.
By contrast, a comment stating that image specifies the image contributes little information to a reader who already understands the Compose syntax.
Consistency across service definitions also helps readers compare components and locate particular settings without examining every attribute individually.
The objective is to make the configuration understandable as a description of the component's operating requirements.
Configuration Resolution and Validation
A Compose file is a declarative input that must be processed before the corresponding application resources can be created.
Compose interprets the YAML structure, resolves supported variable expressions, processes applicable configuration files, and constructs a normalized application model.
This distinction matters because the text written in a Compose file is not always identical to the resolved configuration used for execution.
For example:
services:
api:
image: "myapi:${APP_VERSION:-2.3.0}"
The image reference depends on the value available during configuration resolution.
If no applicable APP_VERSION value is supplied, the declared default produces:
image: myapi:2.3.0
The command:
docker compose config
allows the resolved Compose configuration to be examined.
It can expand supported shorthand forms, resolve environment variable interpolation, and display the normalized application model.
Because the resolved output may contain environment variable values, it should be handled carefully when sensitive information is present.
Validating Without Printing the Configuration
Compose also supports a validation-only operation:
docker compose config --quiet
This checks the configuration without rendering the normalized model to standard output.
Configuration validation is valuable because it can detect structural problems and certain inconsistencies before the application is started.
However, a valid Compose configuration does not guarantee that every image exists, every build succeeds, every required port is available, or every application can operate correctly.
Those conditions depend on the container runtime, external resources, application behavior, and the environment in which the services execute.
From Service Configuration to Runtime Execution
A Compose service definition connects the intended operating requirements of a component with the container resources created to satisfy them.
The following diagram illustrates this relationship.
The process begins with a declarative service definition.
Compose resolves that definition into the application model it will use. When the application is started, the required images and supporting resources are prepared, and the relevant container configuration is applied.
The container runtime then executes and manages the resulting containers according to their configured operating conditions.
The distinction between the written configuration and the actual runtime state is important.
Declaring a resource limit does not establish that the application will remain within it. Declaring a health check does not guarantee application health. Declaring a dependency does not eliminate the possibility of subsequent connection failures.
Service configuration establishes intended behavior and constraints, while execution reveals how the component behaves under actual operating conditions.
When the observed behavior differs from the intended requirements, the configuration may need to be revised.
This relationship makes Compose service configuration both a description of the desired runtime environment and a maintainable reference for understanding the component's operational expectations.