Docker Compose for Small Projects

Abstract generated cover for Docker Compose for Small Projects.

Docker Compose lets you define multiple containers for a project in one file. That is useful when a project needs more than one process. For example:

  • web app
  • database
  • background worker
  • Redis
  • local mail catcher
  • admin tool Instead of starting each piece manually, Compose gives you one command to bring the stack up.
docker compose up

That can make local development and small deployments much more repeatable.

The Mental Model

Think of Docker Compose as a project-level process map. It says:

  • what services exist
  • what image or build each service uses
  • what ports are exposed
  • what volumes are mounted
  • what environment variables are provided
  • which services depend on each other A small Compose file might describe: ```plain text web -> database worker -> database
The point is not containers for their own sake.
The point is making the project environment explicit.
## A Small Compose Example
A simple web plus database setup might look like:
```yaml
services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: postgres://app:app@db:5432/app
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      POSTGRES_DB: app
      POSTGRES_USER: app
      POSTGRES_PASSWORD: app
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

This defines two services:

  • `web`
  • `db` It also defines a volume so database data persists when the database container restarts.

Services

Each top-level entry under `services` is a containerized process. Common examples: ```plain text web db redis worker nginx

The service name becomes useful inside the Compose network.
For example, the web container can connect to the database using hostname \`db\`.
That is why the database URL used:
```plain text
postgres://app:app@db:5432/app

The host is `db`, not `localhost`. Inside Compose, `localhost` usually means the current container.

Ports

Ports expose a container to your machine.

ports:
  - "8000:8000"

The left side is the host port. The right side is the container port. That means: ```plain text localhost:8000 on your machine -> port 8000 inside the container

Not every service needs public ports.
A database may only need to be reachable by other containers. In that case, you may skip exposing it to the host unless you need direct access for development.
## Volumes
Containers are disposable.
Data is not.
Volumes are how you keep important data outside the container lifecycle.
For PostgreSQL:
```yaml
volumes:
  - postgres_data:/var/lib/postgresql/data

This keeps the database files in a named Docker volume. If the `db` container is recreated, the volume can remain. This is critical for anything stateful. Do not treat a container filesystem like a backup.

Environment Variables

Compose can pass environment variables into services. Example:

environment:
  DEBUG: "1"
  DATABASE_URL: postgres://app:app@db:5432/app

For secrets, be careful. Local development values may be fine in a local Compose file. Production secrets should be managed deliberately and should not be committed accidentally. A common pattern is using an `.env` file for local values, with a separate production secret strategy.

Common Mistakes

Mistake 1: Using Docker before understanding the app

Docker does not fix unclear project setup. Make sure you understand how the app runs before containerizing it.

Mistake 2: Forgetting persistent volumes

If a database runs in a container without persistent storage, you can lose data when containers are removed. Stateful services need volumes and backups.

Mistake 3: Confusing container networking with host networking

Inside Compose, service names are hostnames. Use `db` from another container, not `localhost`, when connecting to the database service.

Where This Shows Up in Real Projects

Compose is useful for small projects that have multiple moving pieces. Examples:

  • Django plus PostgreSQL
  • Go API plus Redis
  • local worker plus queue
  • integration testing stack
  • internal tool with database and web UI For a static site, Docker Compose may be unnecessary. For a database-backed application, it can make setup much easier. The test is simple:

Does Compose make the project easier to run on another machine? If yes, it is worth considering.

Key Takeaways

  • Docker Compose defines multiple project services in one file.
  • Services can talk to each other by service name.
  • Ports expose containers to the host machine.
  • Volumes keep stateful data outside disposable containers.
  • Compose is useful when it makes project setup more repeatable.

    Related Articles

  • VPS Deployment Basics for Developers

  • PostgreSQL Backups for Small Projects
  • Nginx Basics for Developers

← Back to Blog Index