LibraryFirst Way: FlowTools & TechniquesEnvironment Parity

FT-03TOOLFirst Way: Flow

Environment Parity

Why dev, test, and prod must be identical — and how containers make that guarantee enforceable.

Sources:12-Factor AppDevOps HandbookDocker Documentation

Video Lesson

A video lesson for this topic is in development. The library articles and mission exercises cover the same material in the meantime.

01

The 'works on my machine' problem

A developer pushes code that works perfectly locally. The CI build fails. Or worse: CI passes, staging passes, and production breaks. The cause is almost always environment drift — differences in runtime versions, dependencies, configuration, or operating system behavior between environments.

Every environment difference is a source of risk. When dev, test, and prod differ, passing tests in one environment gives false confidence. Bugs that only exist in production are the hardest and most expensive to fix.

At Nexus Corp, developers used Node 18 locally, CI ran Node 20, and production ran Node 22. A timing bug only appeared on Node 22. It was invisible in development and CI for months.

02

The three environments — and why they must match

Without parity

Dev

Node 18 / SQLite

Test

Node 20 / Postgres 14

Prod

Node 22 / Postgres 16

Three different stacks. Three different failure modes.

With parity

Dev

Node 22 / Postgres 16

Test

Node 22 / Postgres 16

Prod

Node 22 / Postgres 16

One spec. If it works in dev, it works in prod.

03

Infrastructure as code

The 12-Factor App methodology (Heroku, 2011) states: keep development, staging, and production as similar as possible. The way to achieve this is to define environments in code — not in wikis, not in runbooks, not in tribal knowledge.

When environment configuration lives in version-controlled files, it gets the same treatment as application code: reviewed, tested, and deployed consistently. Manual environment setup is a form of waste — it is unrepeatable, undocumented, and drift-prone.

Dockerfile

Defines the runtime environment. Every developer and every CI run builds from the same image.

docker-compose.yml

Defines the full local stack: app, database, cache. One command to start the entire environment.

.env files

Environment-specific config injected at runtime. The image is identical; only config differs.

04

Containers and Docker

A Docker container packages the application and its entire runtime — OS libraries, language version, dependencies — into a single portable unit. The container runs identically on a developer's laptop, in CI, and in production.

This is the key insight: the container is not just a deployment mechanism. It is a parity contract. When you build the image once and promote it through environments without rebuilding, you guarantee that what you tested is exactly what you ship.

Build once, deploy many times. The artifact that passes tests in CI is the exact artifact that runs in production. Never rebuild between environments.

05

The Nexus Corp solution

In Mission 02, you containerized the Nexus Corp application using Docker and Docker Compose. The setup included three services:

appnode:22-alpineThe Express API, built from the project Dockerfile
postgrespostgres:16Identical database version across all environments
redisredis:7-alpineSession cache, same version in dev and prod

Any developer who clones the repo and runs docker compose up gets an identical environment in under two minutes.

06

Further reading

The Twelve-Factor App — Heroku

Factor X: Dev/Prod Parity. The definitive statement of why environment parity is non-negotiable.

DevOps Handbook — Chapter 11

Enable and Practice Continuous Testing. How environment parity enables reliable automated testing.

Docker Documentation — Compose

The official Docker Compose documentation. The reference for defining multi-container environments in code.

Continuous Delivery — Humble & Farley

Chapter 11: Managing Infrastructure and Environments. The full treatment of environment management.