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
| Stack | Use case | Level | Healthcheck | Main risk |
|---|---|---|---|---|
| PostgreSQL | Database for an app in development | Beginner | Yes | Changing the password without removing the old volume |
| PostgreSQL + pgAdmin | Manage the database with a web interface | Beginner | Yes | Exposing pgAdmin to the Internet unprotected |
| Redis with a password | Cache or queue for an app | Beginner | Yes | Leaving Redis with no password and an open port |
| Node.js + PostgreSQL | Your own app starting alongside its database | Intermediate | Yes | ECONNREFUSED from starting before the DB is ready |
| Nginx as a reverse proxy | Put an app behind a proxy on an internal network | Intermediate | Yes | 502 errors from pointing at the wrong host or port |
| WordPress + MariaDB | Local WordPress with its database | Intermediate | Yes | Losing uploads by not giving them their own volume |
| Prometheus + Grafana | Metrics and dashboards locally | Intermediate | No | Believing 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 downtakes 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
healthchecktells Docker whether a service is ready, not just that it started. That is what letsdepends_ontruly 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.envkept out of git. Version only a.env.examplewithCHANGE_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.