Config Files in Containers

Config Files in Containers

The same image should be able to run in development, staging, and production without ever being rebuilt for each — and config files are the mechanism that makes that possible.

Every real application needs some kind of configuration — a database address, a feature flag, logging verbosity, the settings a web server uses to decide which routes to serve. The question is where that configuration should actually live. Baking it directly into the image sounds simple at first, but it quietly breaks one of the most valuable properties of container images: that the exact same image can move from a developer’s laptop to a test environment to production without being rebuilt along the way. If configuration is baked in, “the same image” stops being true the moment two environments need different settings. Config files solve this by keeping configuration completely separate from the image, and handing it to the container only at the moment it starts — through a mounted file rather than something compiled into the picture. This guide covers what that separation actually looks like, how Docker gets a config file into a running container, and the patterns teams use to keep this clean as an application grows.

ACore Concepts

Before the mechanics, it helps to be clear on the underlying principle this whole topic rests on.

What “config files in containers” really means

It refers to the practice of keeping an application’s configuration — a settings file, a server configuration, a set of connection details — outside the container image entirely, and supplying it to the container at runtime as an external file, most commonly through a mount. The application inside the container reads that file from a known path, exactly as it would on any other machine, without needing to know or care where the file actually came from.

Why baking configuration into the image causes real problems

An image with configuration compiled directly into it is no longer one artifact usable everywhere — it becomes one artifact per environment, which multiplies the number of images that need to be built, tested, and kept in sync. Worse, it means the exact image running in production was never the exact image tested in staging, undermining one of the core promises containers are supposed to deliver: that what you tested is what you ship.

The core principle: build once, configure many times

The pattern this guide describes follows a simple rule: an image should contain the application and nothing environment-specific, while everything that differs between environments — addresses, credentials, feature toggles, resource limits — is supplied externally, at the moment a container from that image actually starts.

Everyday Analogy

Think of a container image like a brand-new, unconfigured television fresh from the factory — every unit is physically identical. Configuration is like the remote control settings a specific household applies once they plug it in: channel list, region, language. Nobody manufactures a separate television model for every household’s preferences; the same television accepts different settings depending on where it is plugged in and set up.

BArchitecture & Components

A few distinct mechanisms are commonly used to get a config file from outside a container into a running one.
Bind Mount

A direct host-to-container link

Connects a specific file or folder on the host machine to a path inside the container, so the container always sees whatever currently exists at that host location.

Named Volume

Docker-managed storage for config

A volume that can hold configuration files, useful when the configuration is generated or managed by Docker itself rather than referenced directly from a host path.

docker config (Swarm)

Cluster-managed configuration objects

A dedicated object type in Docker Swarm specifically for distributing configuration files to services, kept separate from images and versioned independently.

Environment Variables

A simpler alternative for small values

Used for individual settings rather than whole files, environment variables are often combined with config files for simple values while structured settings live in the file.

Entrypoint / Startup Script

Where files can be assembled or adjusted

A script run when the container starts, sometimes used to generate or adjust a configuration file from a template combined with environment variables before the main application starts.

Known Config Path

The application’s expectation

The specific file path inside the container the application is written to read its configuration from, which every delivery mechanism above ultimately needs to populate correctly.

What all of these have in common is timing: none of them touch the image itself. Each one supplies the configuration file at the moment a container starts (or, with an entrypoint script, immediately just before the application inside it starts), leaving the underlying image completely unchanged and reusable everywhere.

CInternal Working

Here is what actually happens between the moment a container is told to start and the moment its application reads its configuration.

When a container is started with a bind mount pointing a host file at a specific path inside the container, Docker connects that path before the container’s main process ever runs. From the application’s point of view, the file simply already exists at the expected location the instant it starts — there is no special container-aware code required inside the application itself; it opens the file the same way it would on any ordinary machine.

How template-and-substitute setups work internally

Some applications need configuration that is assembled from several small pieces — a handful of environment variables combined into a larger configuration file format the application expects. In these cases, a small startup script runs first, reads the provided environment variables, fills them into a template file, writes the completed configuration file to the expected path, and only then hands control to the actual application. The application itself still just reads a finished, ordinary file; the assembly step happens transparently just before it starts.

What happens if the configuration is missing or wrong

Because the application does not distinguish between a file that arrived through a mount and one that was always part of the image, a missing or malformed configuration file produces exactly the same failure the application would show on any machine with a broken config — usually a startup error or crash, which is why validating configuration before deploying it matters as much as validating application code itself.

i
Key Distinction

The image defines what the application is. The mounted or injected configuration defines how that particular running instance should behave. Keeping these two firmly separate is what allows one image to serve every environment correctly.

DData Flow & Lifecycle

Tracing one configuration file from a host machine into a running application makes the separation concrete.

Imagine an nginx web server container that needs different routing rules in staging than in production, using the exact same underlying image in both places.

flowchart TD
    A["staging.conf exists on staging host"] --> B["docker run mounts staging.conf into container at /etc/nginx/nginx.conf"]
    C["production.conf exists on production host"] --> D["docker run mounts production.conf into same path in a separate container"]
    B --> E["nginx process starts, reads /etc/nginx/nginx.conf"]
    D --> F["nginx process starts, reads same path, different content"]
    E --> G["Staging container serves staging routing rules"]
    F --> H["Production container serves production routing rules"]
    G --> I["Both containers built from the identical, unmodified image"]
    H --> I
    

Fig. 1 — The same image produces different, correctly configured behavior in each environment, because the configuration file — not the image — differs between them.

Notice that nothing about the image changed between the two environments. If a new version of the application needs to be deployed, exactly one new image is built and tested, and it can be rolled out to staging and production alike, each simply picking up its own existing configuration file the moment the new container starts.

Updating configuration without rebuilding anything

Because the configuration lives outside the image, a routing rule or setting can often be changed by editing the external file and restarting the container, with no image rebuild, no registry push, and no image version bump required for what is purely a configuration change.

EAdvantages, Disadvantages & Trade-offs

Strengths

  • One image genuinely serves every environment, preserving the guarantee that what was tested is what actually runs in production
  • Configuration changes do not require rebuilding, retesting, or redistributing the image
  • Keeps environment-specific details, including anything sensitive, out of the image itself and out of any registry the image is pushed to

Limitations

  • Requires the operator to correctly supply the right configuration file for each environment, which is an extra coordination responsibility
  • A missing or malformed mounted file causes the same kind of failure a truly broken config file would, and the underlying cause is not always immediately obvious
  • Configuration and image versions can drift out of sync if the two are not tracked and changed together deliberately

The trade-off in one sentence: externalizing configuration trades a small amount of operational coordination for a large, durable improvement in how reusable, testable, and portable the image itself becomes.

FSecurity

Keeping configuration outside the image has real security upside — but only if the configuration itself is still handled carefully.

One of the most valuable side effects of externalizing configuration is that nothing environment-specific ever gets baked into an image layer, which means an image pushed to a registry, even a shared or public one, does not inadvertently carry a production database address, an internal hostname, or other operationally sensitive details along with it. This alone closes off a surprisingly common way sensitive information leaks — through an image layer nobody thought to check.

!
Config Files Are Not Automatically Secrets Management

A mounted configuration file is more careful than baking values into an image, but it is still, in most setups, a plain-text file sitting on disk. If that file contains genuine secrets — passwords, API keys, private certificates — it deserves the same protections a dedicated secrets mechanism would provide: restricted file permissions, restricted access to whatever host or storage holds it, and, ideally, a purpose-built secrets tool rather than a general configuration file at all.

A reasonable line to draw is separating genuinely non-sensitive configuration — routing rules, log levels, feature flags — from anything that grants access to something, and routing the sensitive category through a dedicated secrets mechanism instead of a general-purpose configuration file, even though both might technically arrive in a container the same way, through a mount.

GDesign Patterns & Anti-patterns

PATTERN-01 Recommended
Pattern

Build once, configure per environment: create a single image with no environment-specific values baked in, and supply a different configuration file for each environment at deploy time.

Why it works

It guarantees the exact artifact tested in one environment is the exact artifact running in another, eliminating an entire class of “it worked in staging” surprises caused by subtly different images.

PATTERN-02 Recommended
Pattern

Template-and-substitute at startup: keep a configuration template inside the image, and have a small entrypoint script fill it in from environment variables before the application starts.

Why it works

It combines the simplicity of environment variables for individual values with the structure a real configuration file format requires, without needing a separate file to be mounted for every small setting.

ANTI-01 Avoid
Anti-pattern

Building a separate image per environment, each with its own configuration file copied in at build time.

Why it causes problems

It multiplies the number of images that must be built, scanned, and kept in sync, and it breaks the guarantee that the image validated in one environment is identical to the one running in another.

ANTI-02 Avoid
Anti-pattern

Mounting a configuration file that includes genuine secrets, with no additional access restriction, the same way an ordinary, non-sensitive settings file would be handled.

Why it causes problems

It treats sensitive credentials with the same casual handling as harmless settings, increasing the chance they end up readable by more people, processes, or systems than actually need access to them.

HBest Practices & Common Mistakes

Do

Keep images environment-agnostic

Nothing in the image itself should assume it is running in any particular environment — all of that belongs in the externally supplied configuration.

Do

Validate configuration before deployment

Checking a configuration file’s correctness ahead of time catches problems before they surface as a confusing application crash at container startup.

Do

Version configuration alongside the application

Tracking which configuration version was used with which image version, even informally, makes it far easier to reason about what changed after an incident.

Avoid

Copying secrets into a configuration file inside the image

Anything copied into the image during the build becomes part of every layer that references it — treat secrets as something injected at runtime, never baked in.

Avoid

Relying on undocumented default paths

If the exact path an application expects its configuration file at is not clearly documented and consistently used, mounting the wrong path silently leaves the application running with defaults nobody intended.

Avoid

Mixing structural config with individual toggles inconsistently

Splitting related settings arbitrarily between a config file and scattered environment variables makes a system harder to reason about than picking one clear convention and sticking to it.

IReal-World & Industry Examples

1

Web server configuration

It is extremely common to run the official nginx image unmodified while mounting a custom configuration file over its default configuration path, letting the same nginx image serve completely different routing setups across projects.

2

Docker Swarm configuration objects

Docker Swarm’s dedicated config object type is used specifically so configuration files can be versioned, updated, and distributed to running services independently of the image itself, without secrets-level access control.

3

Kubernetes ConfigMaps

Kubernetes provides a dedicated resource type for exactly this purpose, letting a configuration file be defined once in the cluster and mounted into any pod that needs it, following the same build-once-configure-many principle at a larger orchestration scale.

4

The twelve-factor app methodology

A widely referenced set of principles for building cloud-friendly applications explicitly calls for storing configuration separately from code, a guideline that container-based config file mounting is a direct, practical implementation of.

JFrequently Asked Questions

Q1Why not just build a separate image for each environment?
It multiplies the number of images that need building, scanning, and maintaining, and it breaks the guarantee that the exact artifact tested somewhere is the exact artifact deployed elsewhere. Externalized configuration keeps one image genuinely reusable everywhere.
Q2Can a configuration change take effect without rebuilding the image?
Yes, that is one of the main benefits. Since the configuration file lives outside the image, updating it and restarting the container is usually enough — no image rebuild, retest, or redistribution is required for a purely configuration-level change.
Q3Should secrets be handled the same way as ordinary configuration files?
Not ideally. While both can technically be delivered through a mount, genuine secrets deserve stricter handling — tighter access controls and, where possible, a dedicated secrets mechanism — rather than being treated identically to non-sensitive settings.
Q4What happens if the mounted configuration file is missing?
The application behaves exactly as it would on any machine with a missing configuration file — typically failing to start or falling back to whatever default behavior it has built in, which is why the mount itself needs to be verified as part of a reliable deployment process.
Q5Is a template-and-substitute startup script the same thing as baking configuration into the image?
No. The image contains only a template with placeholders, not any actual environment-specific values. The real values are supplied as environment variables at runtime and combined with the template only at startup, so the image itself remains reusable across environments.
Q6Do Kubernetes ConfigMaps and Docker Swarm configs work the same way as a simple bind-mounted file?
The underlying idea is the same — configuration kept separate from the image and delivered to the container at runtime — but each orchestrator manages, versions, and distributes that configuration through its own dedicated resource type rather than a plain host file mount.

KSummary and Key Takeaways

The essentials, in one place

  • Configuration lives outside the image, supplied at container startup rather than baked in during the build.
  • Bind mounts, volumes, and orchestrator-specific config objects are the common mechanisms for delivering a config file into a running container.
  • The application never needs to know whether its configuration file was always part of the image or was mounted in — it just reads a file at a known path.
  • One image can genuinely serve every environment, preserving the guarantee that what was tested is what actually runs elsewhere.
  • Configuration changes without rebuilding the image, which speeds up routine environment-specific adjustments significantly.
  • Config files are not automatically secure secrets storage. Anything genuinely sensitive deserves stricter handling than a general-purpose configuration file.
  • This principle scales up cleanly into orchestrator-native mechanisms like Kubernetes ConfigMaps and Docker Swarm configs as systems grow larger.