Containers for Backend Developers
Packaging an app with everything it needs to run, so "it works on my machine" stops being a real problem.
2 min read
"It works on my machine" is a real, common failure mode in backend development — a service runs fine locally but breaks in production because of a different OS version, a missing system library, or a different runtime version. Containers solve this by packaging an application together with its entire runtime environment into one portable unit.
What a container actually is
A container bundles an application's code, its dependencies, and a minimal filesystem — everything it needs to run — into a single image that behaves identically wherever it's run: a developer's laptop, a CI pipeline, or a production server. Unlike a full virtual machine, a container shares the host machine's kernel, which makes it far lighter weight and faster to start.
Virtual Machine Container
┌─────────────────┐ ┌─────────────────┐
│ Application │ │ Application │
│ Guest OS (full) │ │ (shares host │
│ Hypervisor │ │ kernel) │
│ Host OS │ │ Host OS │
└─────────────────┘ └─────────────────┘
Slow to start, Fast to start,
GBs in size MBs in size
A minimal example
Most containerized backends are defined by a small configuration file describing how to build the image:
FROM node:20-slim
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm install --production
COPY . .
CMD ["node", "server.js"]$ docker build -t my-backend .
$ docker run -p 3000:3000 my-backend
That image now runs identically anywhere Docker (or a compatible runtime) is available — the exact same Node version, the exact same installed dependencies, every time.
Why this matters for a backend specifically
- Environment parity — the same image that passed tests in CI is the exact image deployed to production, not a rebuild that might drift.
- Dependency isolation — a service needing Python 3.9 and another needing Python 3.12 can run side by side on the same host without conflicting.
- Easier horizontal scaling — spinning up another instance of a containerized service is just running another copy of the same image, which orchestration tools (Kubernetes, or a simpler platform's autoscaler) can do automatically based on load.
- Local development matching production —
docker composecan spin up a backend alongside a real Postgres and Redis instance locally, much closer to production than mocking them out.
What containers are not
A container isn't a substitute for good application design — a backend that isn't stateless doesn't become horizontally scalable just because it's containerized (see the previous lesson). Containers make it easy to run many identical instances; the application still has to be built in a way that makes running many instances correct.
Containers make a backend easy to build and run consistently. The next lesson covers automating that build-test-deploy sequence itself, with CI/CD.