Stop 15 · DevOps & DeploymentTopics · 1/8

Docker for Full-Stack Apps

Part of the Full Stack Developer Roadmap

In short

'It works on my machine' gets worse with three moving parts: React, Express and Postgres. Docker Compose starts all three with one command, the same way on every laptop.

Containerizing both your frontend and backend (and often the database) so your whole stack runs identically on any machine — usually orchestrated together with Docker Compose for local development.

The blob character stands in a mini food court of three side-by-side stalls, each with its own stove.

Think of it like this

Stalls in one food court

A food court has separate stalls, each with its own stove and staff, but they share one walkway and one power line, and the mall opens them in order. Each container is a stall, the Compose network is the walkway, and docker compose up is the mall opening for the day.

Watch it happen

docker compose up, in order

db
healthy?
api
web
Browser

1/5Compose starts Postgres first, with a named volume so the data survives restarts.

The big ideas

What you need to know

One container per service

web, api and db each get their own image and process. Rebuild or restart one without touching the others.

Service names are hostnames

Inside the Compose network the API connects to db:5432. localhost inside a container means that same container.

Volumes keep data

Without a volume, removing the db container loses your rows. A named volume keeps them between runs.

Wait for healthy

depends_on with condition: service_healthy stops the API from crashing because Postgres isn't ready yet.

See it in code

Walk through the code

yaml
1services:2  db:3    image: postgres:174    environment: { POSTGRES_PASSWORD: dev }5    healthcheck: { test: ["CMD", "pg_isready", "-U", "postgres"], interval: 5s }6    volumes: ["pgdata:/var/lib/postgresql/data"]7  api:8    build: ./api9    ports: ["4000:4000"]10    environment: { DATABASE_URL: "postgres://postgres:dev@db:5432/postgres" }11    depends_on: { db: { condition: service_healthy } }12  web:13    build: ./web14    ports: ["3000:3000"]15    depends_on: [api]16volumes: { pgdata: {} }

1/4Postgres with a dev password, a readiness check and a named volume for its data folder.

compose.yaml at the repo root. The browser runs on your machine, outside the Compose network, so the React app still calls localhost:4000. Only the API uses the db hostname.

Save yourself the pain

Common mistakes

Oops

Using localhost:5432 in the API's DATABASE_URL inside Docker.

Do this instead

Use the service name, db:5432. Inside a container, localhost is the container itself.

Oops

Baking secrets into the image with ENV in the Dockerfile.

Do this instead

Pass them at runtime through environment or env_file in Compose, and keep .env out of the image with .dockerignore.

Your mission

One command, whole stack

~40 min

Quick check

Inside the api container, which host in DATABASE_URL reaches the Postgres container?

Go deeper

  1. 1Write Dockerfiles for both your frontend and backend.
  2. 2Use Docker Compose to run frontend, backend and database together with one command.
  3. 3Confirm a teammate could clone your repo and run the whole stack with zero manual setup.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge