Using Docker Compose Profiles to unit tests part of the application

Published: (February 20, 2026 at 04:26 AM EST)
3 min read
Source: Dev.to

Source: Dev.to

Overview

Compose profiles let you group services so you can start only a subset of your stack for specific scenarios (e.g., lightweight testing vs. full production).

In your docker‑compose.yml, add a profiles list to each service you want to group:

services:
  postgres:
    profiles: ["core"]
    ...

  jobrunner:
    profiles: ["core"]

  nextjs:
    profiles: ["full"]

  authserver:
    profiles: ["full"]

How it works

CommandWhat starts
docker compose up (no --profile)Only services without a profiles key. In the example above, nothing would start unless you define a default (non‑profiled) service.
docker compose --profile core upServices tagged with core (postgres, jobrunner). Ideal for a lightweight testing stack.
docker compose --profile full upServices tagged with full (nextjs, authserver).
docker compose --profile core --profile full upBoth core and full services.

Tip: If a service should always run, omit the profiles key. It will start regardless of profile flags.

Multiple Databases and Profiles

Docker Compose does not allow multiple services with the same name—even across different profiles.
If you need both a production database and a unit‑test database, give them unique service names and assign each to its own profile:

services:
  app-db:
    profiles: ["prod"]

  unit-test-db:
    profiles: ["test"]

Database Configuration Strategy

  • Your application containers use one DATABASE_URL at a time.
  • Each profile startup determines which database the app connects to.
ProfileDATABASE_URL
testunit-test-db
prodapp-db

There is no runtime toggling – the profile you spin up decides which database your app connects to based on the environment variables provided at startup.

Alternative Approach

Instead of profiles, you can maintain separate Compose files:

  • docker-compose.test.yml
  • docker-compose.prod.yml

Each file can hard‑code the correct database host. This provides clearer separation but requires maintaining multiple files.

Concrete Example with unit-test-db and app-db

Below is a clean, complete working example.

1️⃣ docker-compose.yml

services:
  # -----------------
  # Databases
  # -----------------
  unit-test-db:
    image: postgres:15
    container_name: unit-test-db
    profiles: ["test"]
    environment:
      POSTGRES_USER: test
      POSTGRES_PASSWORD: test
      POSTGRES_DB: testdb
    ports:
      - "5433:5432"

  app-db:
    image: postgres:15
    container_name: app-db
    profiles: ["prod"]
    environment:
      POSTGRES_USER: prod
      POSTGRES_PASSWORD: prod
      POSTGRES_DB: proddb
    ports:
      - "5432:5432"

  # -----------------
  # Application
  # -----------------
  app:
    build: .
    depends_on:
      - unit-test-db
      - app-db
    environment:
      DATABASE_URL: ${DATABASE_URL}

2️⃣ What DATABASE_URL Should Look Like

Inside Docker, the hostname is the service name.

Test profile → connect to unit-test-db

postgresql://test:test@unit-test-db:5432/testdb

Prod profile → connect to app-db

postgresql://prod:prod@app-db:5432/proddb

3️⃣ Running with Different Environment Variable Sets

.env.test

DATABASE_URL=postgresql://test:test@unit-test-db:5432/testdb

.env.prod

DATABASE_URL=postgresql://prod:prod@app-db:5432/proddb

Start the test stack

docker compose --profile test --env-file .env.test up

Start the prod stack

docker compose --profile prod --env-file .env.prod up

✅ Option B — Inline Environment Variables

Test

DATABASE_URL=postgresql://test:test@unit-test-db:5432/testdb \
docker compose --profile test up

Prod

DATABASE_URL=postgresql://prod:prod@app-db:5432/proddb \
docker compose --profile prod up

4️⃣ What Actually Starts

docker compose --profile test up

Starts only:

  • unit-test-db
  • app
docker compose --profile prod up

Starts only:

  • app-db
  • app

Clean Mental Model

ProfileDB ContainerDATABASE_URL host
testunit-test-dbunit-test-db
prodapp-dbapp-db

The service name becomes the DNS hostname inside Docker’s network. Each profile launch defines:

  • Which database container runs
  • Which DATABASE_URL the application receives

Happy composing!

0 views
Back to Blog

Related posts

Read more »

Warm Introduction

Introduction Hello everyone! I'm fascinated by the deep tech discussions here. It's truly amazing to see the community thrive. Project Overview I'm passionate...