ToolsOps

Docker Compose examples: real stacks explained

A Docker Compose example library by stack (PostgreSQL, Redis, Nginx, Node, WordPress, Prometheus + Grafana) with healthchecks, .env.example, safe ports and the real errors each one avoids.

Copying a compose.yaml from anywhere is easy; understanding why it is written that way is what saves you an afternoon. This library gathers the stacks people set up most often locally and, for each one, explains the decisions that actually matter: where the data lives, how Docker knows a service is ready, where passwords go and which ports you should not open. Every example runs in your browser through the generator; nothing is sent to a server.

Pick your stack

StackUse caseLevelHealthcheckMain risk
PostgreSQLDatabase for an app in developmentBeginnerYesChanging the password without removing the old volume
PostgreSQL + pgAdminManage the database with a web interfaceBeginnerYesExposing pgAdmin to the Internet unprotected
Redis with a passwordCache or queue for an appBeginnerYesLeaving Redis with no password and an open port
Node.js + PostgreSQLYour own app starting alongside its databaseIntermediateYesECONNREFUSED from starting before the DB is ready
Nginx as a reverse proxyPut an app behind a proxy on an internal networkIntermediateYes502 errors from pointing at the wrong host or port
WordPress + MariaDBLocal WordPress with its databaseIntermediateYesLosing uploads by not giving them their own volume
Prometheus + GrafanaMetrics and dashboards locallyIntermediateNoBelieving this already is production observability

What to choose if...

  • You only need a database: start with PostgreSQL. It is the most common case and the one that best teaches volumes and healthchecks.
  • You want to see and edit data by clicking: add pgAdmin with PostgreSQL + pgAdmin.
  • Your app and its database start together: use Node.js + PostgreSQL to learn how to wait until the DB accepts connections.
  • You need cache or queues: Redis with a password covers persistence and authentication.
  • You put an app behind a proxy: Nginx as a reverse proxy explains the internal network and how to diagnose a 502.

What all these examples share

Three decisions repeat in every guide because they prevent the most mistakes. Once you understand these three, the rest is per-service detail.

  • Data in named volumes. Without a volume, docker compose down takes your database with it. With one (postgres_data:/var/lib/postgresql/data), the data survives. Remember: a volume is not a backup.
  • Health before order. A healthcheck tells Docker whether a service is ready, not just that it started. That is what lets depends_on truly wait, as explained in the healthchecks and depends_on guide.
  • Secrets via variables. No passwords in compose.yaml: they go through ${VARIABLE} and live in a .env kept out of git. Version only a .env.example with CHANGE_ME.

Next steps

Generate any of these stacks with the Docker Compose generator and validator and paste your own file to review it. If you want to fully understand how services wait for each other, read the healthchecks, depends_on and secrets guide.

Frequently asked questions

Are these compose.yaml files production-ready?
No. They are starting points meant for local development and learning. They cover what gets forgotten most (named volumes, healthchecks, secrets via variables, ports not exposed by default), but production needs more: tested backups, TLS, secrets managed outside git, resource limits and, almost always, an orchestrator or a managed provider. Each guide states explicitly what it is missing for production.
Which stack should I start with?
If you just need a database for your app, start with PostgreSQL. If you want to manage it by clicking, PostgreSQL + pgAdmin. If your app lives in the same compose as the database, Node.js + PostgreSQL teaches you to wait until the DB is ready. For cache or queues, Redis with a password. The table above summarizes the use case and the main risk of each one.
Why does almost none of them expose the database port?
Because inside Compose services talk to each other by name on the internal network (for example app connects to postgres:5432) without publishing anything to the host. Publishing 5432 or 3306 opens the database to your whole machine's network. In the guides we only publish a port when you truly need host access, and then we bind it to 127.0.0.1 so it does not leave your computer.
Can I generate these files instead of copying them by hand?
Yes. Each guide links to the Docker Compose generator with its preset already selected: you pick options (healthcheck, volumes, local port) and get the compose.yaml and the .env.example. You can also paste your own file into the validator to catch plaintext secrets, exposed database ports, :latest image tags and depends_on without a health condition.
Are the passwords in the examples real?
No. Every .env.example uses the CHANGE_ME placeholder on purpose. You must replace it with your own value in a .env file that you never push to git. Version only the .env.example to document which variables are needed, not their values.