Skip to main content
92 Nodes
All resources
Free tool

Free Docker Compose Generator

Build a production-aware Docker Compose file visually.

Build a production-aware Docker Compose file visually. Choose a complete stack or add individual services, customize the configuration, validate common mistakes, and download your compose.yaml and .env.example.

Loading Docker Compose Generator…
Overview

What is a Docker Compose generator?

A Docker Compose generator turns a set of choices — which services you need, how they're configured, how they depend on each other — into a valid compose.yaml file, without you having to remember the exact YAML syntax, indentation rules, or which healthcheck command each database expects.

This one goes further than joining text templates together: it models your services as structured data, then generates healthchecks, dependency wiring, and internal hostnames based on what you've actually selected — the same way you'd write it by hand, just faster and harder to get wrong.

Usage

How to generate a Compose file

  1. 1. Start from a recipe or an empty project. Pick a Quick Stack Recipe for a common setup, or start empty and add services one at a time from the Service Library.
  2. 2. Customize each service. Adjust ports, environment variables, volumes, and dependencies — advanced fields like resource limits and bind mounts are tucked under "Advanced settings".
  3. 3. Fix anything flagged. The validation panel catches duplicate ports, missing volumes, and other common mistakes as you go.
  4. 4. Copy or download. Grab compose.yaml and .env.example, or check the Commands tab for exactly what to run next.
Modern syntax

Why compose.yaml instead of an obsolete versioned format?

Older Compose files started with a top-level version: "3.8" field. Under the modern Compose Specification — the format every current version of Docker Compose actually implements — that field is obsolete and ignored. Compose behavior is now determined by which top-level keys and options you use, not a version number.

This generator never adds a version: key, and strips it (with a warning) from anything you import.

Structure

Docker Compose file structure explained

Top-level keyWhat it defines
nameAn optional project name, used to prefix networks and volumes.
servicesEvery container your app runs — images or build contexts, ports, environment, volumes.
networksNamed networks services can share — often left to Compose's implicit default network.
volumesNamed, Docker-managed storage that persists independently of any single container.
secrets / configsSensitive or configuration files mounted into containers — used only when you explicitly need them.
Core concepts

Services, networks, and volumes

Services are your containers. Each one is either built from a Dockerfile (build:) or pulled from a registry (image:), and each gets a hostname on the network matching its service name.

Networks let services talk to each other. Most projects need nothing more than Compose's default network — this generator only adds a named one when you turn it on.

Volumes keep data alive independently of any container. Recreate the container and the data in its named volumes survives; delete the volume (down -v) and it doesn't.

Startup order

Healthchecks and startup dependencies

A plain depends_on only waits for a container to start— not for the database inside it to actually accept connections. That gap causes a huge share of "works sometimes" startup bugs.

A healthcheck fixes this by defining a real readiness command (pg_isready for PostgreSQL, redis-cli pingfor Redis, and so on). Combined with depends_on: condition: service_healthy, dependent services wait for the real thing, not just a process starting. This generator wires both together automatically for every supported service type.

Configuration

Environment variables and secrets

Environment variables configure a container without baking values into an image — database credentials, feature flags, API base URLs. Compose lets you reference a shell/`.env` variable from inside the file with ${VAR} syntax, which is resolved when the file is parsed.

Keep real secrets out of compose.yaml entirely: reference ${DB_PASSWORD} in the file, and put the actual value only in a local, git-ignored .env. This generator's .env.example output mirrors every variable your services reference, with clearly-labeled placeholder values.

Environments

Development vs production configurations

In development, it's normal to expose a database port to your host so a GUI client can connect, and to bind-mount source code for live reload. In production, both of those become liabilities: an exposed database port is an attack surface, and bind-mounted source usually isn't how you ship a built image.

Setting Environment to Production in the global settings doesn't change your YAML by itself — it changes which warnings the validator surfaces, like flagging exposed database ports, so you catch dev-only choices before they ship.

Pitfalls

Common Docker Compose mistakes

  • • Connecting to localhost from one container to reach another, instead of the service name.
  • • Forgetting a named volume on a database, then losing all data on the next docker compose down and recreate.
  • • Using depends_on without a healthcheck, so the app starts before its database is actually ready.
  • • Committing real passwords directly into compose.yaml instead of a git-ignored .env file.
  • • Exposing a database's port to the host in a production deployment "just to check something" and forgetting to remove it.
  • • Running docker compose down -v out of habit and permanently deleting data that was never backed up.
Reference

Docker Compose commands cheat sheet

docker compose config      # validate and print the resolved configuration
docker compose up -d      # start every service in the background
docker compose ps         # list services and their health status
docker compose logs -f    # follow logs from every service
docker compose build      # rebuild images after a Dockerfile change
docker compose pull       # download the latest matching image for each tag
docker compose down       # stop and remove containers (volumes are kept)
docker compose down -v    # also delete named volumes — destructive, deletes data

The generator's own Commands tab only shows the commands that are actually relevant to your current configuration.

AI & Automation

Generate Docker Compose Files for AI and Automation

Launch local AI tools, RAG systems, workflow automation, vector databases, and AI development environments with ready-to-customize Docker Compose recipes.

The AI & Automation section of the Quick Stack Recipes covers the tools most local AI setups actually need: self-hosted n8n automation (including Queue Mode for scaling), Ollama for running local models, Open WebUI for a ChatGPT-style interface, vector databases like Qdrant and Weaviate for embeddings and semantic search, and workflow builders like Flowise and Langflow.

Every AI recipe uses persistent named volumes for model and data storage, internal Docker service names instead of localhost, and CPU-only mode by default — GPU passthrough (NVIDIA or AMD) is only ever generated when you explicitly choose it. Model files are never downloaded automatically; the Commands tab gives you the exact ollama pull command to run afterward. These recipes generate infrastructure, not finished AI applications — document ingestion, embeddings pipelines, and workflow logic are still yours to build.

Examples

Practical Docker Compose examples

Real, valid examples you can copy directly or load straight into the generator.

Node.js + PostgreSQL

A Node.js API with a relational database.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
  api:
    build:
      context: .
    ports:
      - 3000:3000
    environment:
      DATABASE_URL: postgresql://${DB_USERNAME}:${DB_PASSWORD}@db:5432/${DB_DATABASE}
    command: node server.js
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network
name: node-postgres-example
volumes:
  postgres_data: {}
networks:
  app-network: {}

The api service waits for db to report healthy before starting, and connects to it using the service name db — never localhost.

docker compose config
docker compose up -d

Laravel + Nginx + MySQL + Redis

A classic Laravel stack: Nginx in front of PHP-FPM, MySQL for storage, Redis for cache/sessions.

services:
  db:
    image: mysql:8.4
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - mysqladmin ping -h localhost -p${DB_ROOT_PASSWORD}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s
    networks:
      - app-network
  redis:
    image: redis:7
    volumes:
      - redis_data:/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD
        - redis-cli
        - ping
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network
  app:
    build:
      context: .
    environment:
      DB_HOST: db
      REDIS_HOST: redis
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - app-network
  nginx:
    image: nginx:1.30-alpine
    ports:
      - 8080:80
    restart: unless-stopped
    depends_on:
      app:
        condition: service_started
    networks:
      - app-network
name: laravel-example
volumes:
  mysql_data: {}
  redis_data: {}
networks:
  app-network: {}

nginx depends on app, and app depends on both db and redis being healthy before it starts.

docker compose config
docker compose up -d

WordPress + MySQL

A WordPress site backed by MySQL, with data persisted in named volumes.

services:
  db:
    image: mysql:8.4
    environment:
      MYSQL_DATABASE: ${DB_DATABASE}
      MYSQL_USER: ${DB_USERNAME}
      MYSQL_PASSWORD: ${DB_PASSWORD}
      MYSQL_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
    volumes:
      - mysql_data:/var/lib/mysql
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - mysqladmin ping -h localhost -p${DB_ROOT_PASSWORD}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s
    networks:
      - app-network
  wordpress:
    image: wordpress:7-php8.3-apache
    ports:
      - 8000:80
    environment:
      WORDPRESS_DB_HOST: db
      WORDPRESS_DB_USER: ${DB_USERNAME}
      WORDPRESS_DB_PASSWORD: ${DB_PASSWORD}
      WORDPRESS_DB_NAME: ${DB_DATABASE}
    volumes:
      - wordpress_data:/var/www/html
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network
name: wordpress-example
volumes:
  mysql_data: {}
  wordpress_data: {}
networks:
  app-network: {}

wordpress connects to MySQL using the service name db, and both services keep their data in named volumes.

docker compose config
docker compose up -d

Django + PostgreSQL + Redis

A Django application with a database and a cache.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
  redis:
    image: redis:7
    volumes:
      - redis_data:/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD
        - redis-cli
        - ping
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network
  web:
    build:
      context: .
    ports:
      - 8000:8000
    environment:
      DATABASE_URL: postgres://${DB_USERNAME}:${DB_PASSWORD}@db:5432/${DB_DATABASE}
      REDIS_URL: redis://redis:6379
    command: python manage.py runserver 0.0.0.0:8000
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - app-network
name: django-example
volumes:
  postgres_data: {}
  redis_data: {}
networks:
  app-network: {}

The web service reads DATABASE_URL and REDIS_URL pointing at the db and redis service names.

docker compose config
docker compose up -d

MongoDB + Mongo Express

A MongoDB database with a web-based admin UI.

services:
  mongo:
    image: mongo:7
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_USERNAME}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_PASSWORD}
    volumes:
      - mongo_data:/data/db
    restart: unless-stopped
    healthcheck:
      test:
        - CMD
        - mongosh
        - --eval
        - db.adminCommand('ping')
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
  mongo-express:
    image: mongo-express:1.0.2
    ports:
      - 8083:8081
    environment:
      ME_CONFIG_MONGODB_SERVER: mongo
      ME_CONFIG_MONGODB_ADMINUSERNAME: ${MONGO_USERNAME}
      ME_CONFIG_MONGODB_ADMINPASSWORD: ${MONGO_PASSWORD}
      ME_CONFIG_BASICAUTH: "false"
    restart: unless-stopped
    depends_on:
      mongo:
        condition: service_healthy
    networks:
      - app-network
name: mongo-express-example
volumes:
  mongo_data: {}
networks:
  app-network: {}

mongo-express connects to MongoDB using the service name mongo and waits for it to start first.

docker compose config
docker compose up -d

Nginx reverse proxy

Nginx sitting in front of an application service, without exposing the app's port directly.

services:
  app:
    build:
      context: .
    restart: unless-stopped
    networks:
      - app-network
  nginx:
    image: nginx:1.30-alpine
    ports:
      - 8080:80
    restart: unless-stopped
    depends_on:
      app:
        condition: service_started
    networks:
      - app-network
name: nginx-reverse-proxy-example
networks:
  app-network: {}

Only nginx publishes a host port — the app service is reachable exclusively through the Docker network.

docker compose config
docker compose up -d

PostgreSQL with a persistent named volume

A standalone PostgreSQL database whose data survives container restarts and recreation.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
name: postgres-volume-example
volumes:
  postgres_data: {}
networks:
  app-network: {}

The named volume postgres_data is declared at the top level and mounted into the database's data directory.

docker compose config
docker compose up -d

Application with a healthcheck and healthy dependency

An application service that only starts once its database has passed its healthcheck.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
  app:
    build:
      context: .
    ports:
      - 3000:3000
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network
name: healthcheck-dependency-example
volumes:
  postgres_data: {}
networks:
  app-network: {}

db has a pg_isready healthcheck, and app's depends_on uses condition: service_healthy instead of just service_started.

docker compose config
docker compose up -d

n8n with PostgreSQL

A persistent, self-hosted n8n instance backed by PostgreSQL instead of SQLite.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
  n8n:
    image: n8nio/n8n:2.39.8
    ports:
      - 5678:5678
    environment:
      N8N_HOST: localhost
      N8N_PORT: "5678"
      N8N_PROTOCOL: http
      WEBHOOK_URL: http://localhost:5678/
      GENERIC_TIMEZONE: UTC
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: db
      DB_POSTGRESDB_DATABASE: ${DB_DATABASE}
      DB_POSTGRESDB_USER: ${DB_USERNAME}
      DB_POSTGRESDB_PASSWORD: ${DB_PASSWORD}
    volumes:
      - n8n_data:/home/node/.n8n
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - wget -qO- http://localhost:5678/healthz || exit 1
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s
    depends_on:
      db:
        condition: service_healthy
    networks:
      - app-network
name: n8n-postgres-example
volumes:
  n8n_data: {}
  postgres_data: {}
networks:
  app-network: {}

n8n's DB_POSTGRESDB_HOST points at the db service name, and both services keep their data in named volumes.

docker compose config
docker compose up -d

n8n Queue Mode with PostgreSQL and Redis

Scaling n8n workflow execution across a main instance and worker containers.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
  redis:
    image: redis:7
    volumes:
      - redis_data:/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD
        - redis-cli
        - ping
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network
  n8n:
    image: n8nio/n8n:2.39.8
    ports:
      - 5678:5678
    environment:
      N8N_HOST: localhost
      N8N_PORT: "5678"
      N8N_PROTOCOL: http
      WEBHOOK_URL: http://localhost:5678/
      GENERIC_TIMEZONE: UTC
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: db
      EXECUTIONS_MODE: queue
      QUEUE_BULL_REDIS_HOST: redis
    volumes:
      - n8n_data:/home/node/.n8n
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - wget -qO- http://localhost:5678/healthz || exit 1
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - app-network
  n8n-worker:
    image: n8nio/n8n:2.39.8
    environment:
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      EXECUTIONS_MODE: queue
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: db
      QUEUE_BULL_REDIS_HOST: redis
    volumes:
      - n8n_data2:/home/node/.n8n
    command: worker
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    networks:
      - app-network
name: n8n-queue-mode-example
volumes:
  n8n_data: {}
  n8n_data2: {}
  postgres_data: {}
  redis_data: {}
networks:
  app-network: {}

Redis distributes executions from the main n8n instance to the worker, and both share the same N8N_ENCRYPTION_KEY and PostgreSQL database.

docker compose config
docker compose up -d

Ollama with Open WebUI

A private, ChatGPT-style interface for chatting with local models.

services:
  ollama:
    image: ollama/ollama:0.34.2
    ports:
      - 11434:11434
    volumes:
      - ollama_data:/root/.ollama
    restart: unless-stopped
    networks:
      - app-network
  open-webui:
    image: ghcr.io/open-webui/open-webui:main
    ports:
      - 3000:8080
    environment:
      OLLAMA_BASE_URL: http://ollama:11434
    volumes:
      - open_webui_data:/app/backend/data
    restart: unless-stopped
    depends_on:
      ollama:
        condition: service_started
    networks:
      - app-network
name: ollama-open-webui-example
volumes:
  ollama_data: {}
  open_webui_data: {}
networks:
  app-network: {}

Open WebUI's OLLAMA_BASE_URL points at http://ollama:11434 — the Ollama service name, not localhost.

docker compose config
docker compose up -d

Ollama with Qdrant for a local RAG foundation

Infrastructure for local retrieval-augmented generation experiments.

services:
  ollama:
    image: ollama/ollama:0.34.2
    ports:
      - 11434:11434
    volumes:
      - ollama_data:/root/.ollama
    restart: unless-stopped
    networks:
      - app-network
  qdrant:
    image: qdrant/qdrant:v1.19.1
    ports:
      - 6333:6333
    volumes:
      - qdrant_data:/qdrant/storage
    restart: unless-stopped
    networks:
      - app-network
name: ollama-qdrant-rag-example
volumes:
  ollama_data: {}
  qdrant_data: {}
networks:
  app-network: {}

This provides a local model server and a vector database only — document ingestion, embeddings, and retrieval logic are not generated for you.

docker compose config
docker compose up -d

n8n with Ollama

Building AI-powered workflows in n8n using a locally hosted model.

services:
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
  ollama:
    image: ollama/ollama:0.34.2
    ports:
      - 11434:11434
    volumes:
      - ollama_data:/root/.ollama
    restart: unless-stopped
    networks:
      - app-network
  n8n:
    image: n8nio/n8n:2.39.8
    ports:
      - 5678:5678
    environment:
      N8N_HOST: localhost
      N8N_PORT: "5678"
      N8N_PROTOCOL: http
      WEBHOOK_URL: http://localhost:5678/
      GENERIC_TIMEZONE: UTC
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: db
    volumes:
      - n8n_data:/home/node/.n8n
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - wget -qO- http://localhost:5678/healthz || exit 1
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 15s
    depends_on:
      db:
        condition: service_healthy
      ollama:
        condition: service_started
    networks:
      - app-network
name: n8n-ollama-example
volumes:
  n8n_data: {}
  ollama_data: {}
  postgres_data: {}
networks:
  app-network: {}

n8n reaches Ollama's OpenAI-compatible API at http://ollama:11434 from inside an HTTP Request node.

docker compose config
docker compose up -d

FastAPI with PostgreSQL, Redis, and Qdrant

An AI-backed API with relational storage, caching, and vector search.

services:
  api:
    build:
      context: .
    ports:
      - 8000:8000
    environment:
      DATABASE_URL: postgresql://${DB_USERNAME}:${DB_PASSWORD}@db:5432/${DB_DATABASE}
      REDIS_URL: redis://redis:6379
      QDRANT_URL: http://qdrant:6333
    command: uvicorn main:app --host 0.0.0.0 --port 8000
    restart: unless-stopped
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
      qdrant:
        condition: service_started
    networks:
      - app-network
  db:
    image: postgres:16
    environment:
      POSTGRES_USER: ${DB_USERNAME}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_DATABASE}
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD-SHELL
        - pg_isready -U ${DB_USERNAME} -d ${DB_DATABASE}
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 10s
    networks:
      - app-network
  redis:
    image: redis:7
    volumes:
      - redis_data:/data
    restart: unless-stopped
    healthcheck:
      test:
        - CMD
        - redis-cli
        - ping
      interval: 10s
      timeout: 5s
      retries: 5
    networks:
      - app-network
  qdrant:
    image: qdrant/qdrant:v1.19.1
    ports:
      - 6333:6333
    volumes:
      - qdrant_data:/qdrant/storage
    restart: unless-stopped
    networks:
      - app-network
name: fastapi-ai-example
volumes:
  postgres_data: {}
  qdrant_data: {}
  redis_data: {}
networks:
  app-network: {}

The api service depends on all three backing services being healthy, and connects to each by service name.

docker compose config
docker compose up -d
Getting started

New to Docker Compose?

What is Docker Compose, in plain English?+

A way to describe every container your app needs — the app itself, a database, a cache — in one file, and start them all together with one command instead of many.

Dockerfile vs Docker Compose+

A Dockerfile builds one image. Docker Compose runs one or more containers from images (built or pulled) together, wired up to talk to each other.

Container vs image+

An image is a packaged, read-only template (like a class). A container is a running instance of that image (like an object created from it).

Host port vs container port+

The container port is what the app listens on inside the container. The host port is what you type in your browser on your own machine — `8080:80` means "my machine's 8080 forwards to the container's port 80".

Volume vs bind mount+

A named volume is storage Docker manages for you — good for database data. A bind mount links a specific folder on your machine into the container — good for live-editing source code or config files.

What's an environment variable, here?+

A configuration value passed into a container at start time — a database password, a port number, a feature flag — without hard-coding it into the image.

How do services find each other?+

By service name. Compose gives every service a hostname matching its name in the file, resolvable from any other service in the same project.

Why does my app fail to connect to "localhost"?+

Because localhost inside a container means that container — never another one. Use the other service's name instead.

What's a healthcheck for?+

A command Docker runs periodically to decide if a service is actually ready to use, not just "started" — so dependent services can wait for a database to be genuinely accepting connections, not just booting.

When should I run docker compose down -v?+

Only when you want to permanently delete the data in your named volumes too — a fresh start for a database, or clearing out old test data. Never on a whim in a project you care about.

FAQ

Frequently asked questions

What is Docker Compose?+

Docker Compose is a tool for defining and running multi-container Docker applications from a single YAML file. Instead of running several `docker run` commands by hand, you describe your services, networks, and volumes once and start everything with `docker compose up`.

Is this Docker Compose generator free?+

Yes. Every recipe, service preset, and export is free with no signup, account, or usage limit.

Is my configuration uploaded to a server?+

No. The generator runs entirely in your browser. Your services, ports, and environment variables are never sent to 92 Nodes, and sharing a link encodes a sanitized copy of your configuration in the URL itself — nothing is stored server-side.

What is the difference between compose.yaml and docker-compose.yml?+

They're both valid filenames for the same modern Compose Specification — `compose.yaml` is the name the spec itself recommends going forward, while `docker-compose.yml` is the older, still-supported filename most existing projects use. Pick whichever matches your project's convention; the generator supports both.

Do I still need a version property?+

No. The top-level `version:` key is obsolete under the modern Compose Specification and is ignored by current Docker Compose versions. This generator never includes it, and if you import a file that has one, it's dropped with a warning.

How do containers connect to each other?+

Every service in a Compose file can reach every other service by its service name over the default Docker network — for example, an app service reaches a database service at the hostname `db`, not an IP address or `localhost`.

Why should I not use localhost between containers?+

Inside a container, `localhost` (or `127.0.0.1`) always refers to that container itself, not to other containers in your Compose project. An app container trying to reach a database at `localhost:5432` will fail even though the database is running fine — it needs to use the database's service name instead, e.g. `db:5432`.

How do I persist database data?+

Attach a named volume to the path where the database stores its files (for example `/var/lib/postgresql/data` for PostgreSQL) and declare that volume at the top level of the Compose file. This generator does this automatically for every stateful service you add, and warns you if a stateful service has no volume.

How do I validate a Compose file?+

Run `docker compose config` in the same directory as your compose.yaml. It parses the file, resolves environment variable interpolation, and prints the fully resolved configuration — or a clear error if something is invalid.

What does docker compose up -d do?+

It creates and starts every service defined in the Compose file in the background (detached mode), so your terminal is free to keep working while the containers run.

How do I stop the containers without deleting data?+

Run `docker compose down`. It stops and removes the containers and the default network, but named volumes — and therefore your data — are kept.

What does docker compose down -v remove?+

The `-v` flag additionally removes named volumes declared in the Compose file. This permanently deletes any data stored in them — database contents, downloaded AI models, uploaded files — so only run it when you actually intend to wipe that data.

Can I use the generated file in production?+

It's a solid, production-aware starting point — but review it first. Check credentials and secret management, resource limits, backups, TLS/reverse proxy setup, and your specific deployment platform's requirements before using it in production. Nothing here is a substitute for that review.

How should I handle passwords and secrets?+

Never write real credentials directly into compose.yaml. Use variable placeholders like `${DB_PASSWORD}` in the Compose file and put the actual value in a local `.env` file that's excluded from version control — this generator's `.env.example` output does exactly that, with placeholder values instead of real ones.

What is the difference between a Dockerfile and a Compose file?+

A Dockerfile describes how to build a single image (install dependencies, copy code, set a start command). A Compose file describes how to run one or more containers together — which images or Dockerfiles to use, what ports and volumes they need, and how they depend on each other.

92 Nodes

Have a project in mind? Let's build it.

Tell us about your goals and we'll get back to you within one business day with next steps.

Book a free call