DEV Community

SOVANNARO
SOVANNARO

Posted on • Edited on

πŸš€ Full App Lifecycle: Dev, Build & Deploy With a Single Docker Compose Design

When building modern apps, we often juggle multiple environments: development, build pipelines, staging, and production. Wouldn’t it be great to handle them all with a single, unified docker-compose.yml file? Yes, it’s possibleβ€”and powerful!

This article walks you through creating a Compose file that works across the full lifecycle of your application: local development, building, testing, and deployingβ€”even to production with Docker Swarm. Let’s go!


πŸ” Why Use a Single Compose Design?

Managing multiple Compose files (docker-compose.override.yml, docker-compose.prod.yml, etc.) gets messy fast.

Instead, we can:

  • Keep one main docker-compose.yml file.
  • Use profiles, build contexts, and secrets.
  • Control behavior with CLI flags or environment variables.

πŸ—οΈ The App Structure

Let’s imagine a simple full-stack app:

my-app/
β”œβ”€β”€ backend/ (Spring Boot)
β”œβ”€β”€ frontend/ (React + Vite)
β”œβ”€β”€ nginx/ (Reverse Proxy)
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ .env
Enter fullscreen mode Exit fullscreen mode

🧠 Compose Design Overview

Here’s what we want in our single Compose file:

  • Profiles to separate dev-only services (like hot reloading).
  • Build contexts to build images during CI or locally.
  • Secrets and configs for secure production-ready deployment.
  • Deploy block for Swarm mode.

πŸ§ͺ Development Stage

services:
  backend:
    build:
      context: ./backend
    ports:
      - "8080:8080"
    volumes:
      - ./backend:/app
    profiles: ["dev"]

  frontend:
    build:
      context: ./frontend
    ports:
      - "5173:5173"
    volumes:
      - ./frontend:/app
    profiles: ["dev"]
Enter fullscreen mode Exit fullscreen mode

Run development services:

docker compose --profile dev up
Enter fullscreen mode Exit fullscreen mode

πŸ—οΈ Build Stage (CI/CD or Local Image Build)

Still using the same file, just with the build option:

  backend:
    build:
      context: ./backend
    image: my-backend:latest

  frontend:
    build:
      context: ./frontend
    image: my-frontend:latest
Enter fullscreen mode Exit fullscreen mode

Then build with:

docker compose build
Enter fullscreen mode Exit fullscreen mode

Or push to a registry:

docker compose build && docker compose push
Enter fullscreen mode Exit fullscreen mode

πŸš€ Deploy Stage (Swarm or Production)

You can use the same Compose file with Docker Swarm:

services:
  backend:
    image: my-backend:latest
    deploy:
      replicas: 2
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
    secrets:
      - db_password

  frontend:
    image: my-frontend:latest
    deploy:
      replicas: 1

  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
Enter fullscreen mode Exit fullscreen mode

Initialize Swarm:

docker swarm init
Enter fullscreen mode Exit fullscreen mode

Deploy the stack:

docker stack deploy -c docker-compose.yml myapp
Enter fullscreen mode Exit fullscreen mode

πŸ” Add Secrets (For Production)

secrets:
  db_password:
    file: ./secrets/db_password.txt
Enter fullscreen mode Exit fullscreen mode

Use in backend:

services:
  backend:
    ...
    secrets:
      - db_password
Enter fullscreen mode Exit fullscreen mode

⚑ Environment Variables for Flexibility

Use a .env file to switch behavior:

NODE_ENV=development
FRONTEND_PORT=5173
Enter fullscreen mode Exit fullscreen mode

In Compose:

frontend:
  ports:
    - "${FRONTEND_PORT}:5173"
Enter fullscreen mode Exit fullscreen mode

βœ… Benefits of This Pattern

  • One file to rule them all.
  • No more config drift between dev/staging/prod.
  • Can scale from local dev to cloud deployment.
  • Great for teams and CI pipelines.

🎁 Final Tips

  • Use --profile to enable/disable services.
  • Use docker-compose.override.yml only for personal overrides, not team-wide differences.
  • Secure your secrets and configs!
  • Combine with GitHub Actions or GitLab CI for automatic deploys.

🏁 Conclusion

A well-designed, unified docker-compose.yml can streamline your entire app lifecycleβ€”from development to production. With smart use of profiles, secrets, and Swarm deployment blocks, you no longer need to duplicate configs or maintain complex scripts.

This pattern makes Docker work for you, not the other way around. πŸ³πŸ’™

Top comments (0)