Course outline · 0% complete

0/29 lessons0%

Course overview →

App plus database, wired properly

lesson 5-2 · ~12 min · 15/29

Configuration through the environment

Why pass DATABASE_URL as an environment variable instead of hardcoding it in the code? Because the same image from lesson 3-1 must run everywhere: your laptop, the CI server (CI is short for continuous integration: an automated machine that tests every push, and unit 7 is devoted to it), and production. The code stays identical, only the environment changes per machine. This is such a strong convention it has a name, the twelve-factor config rule.

The database side of the pair needs its own env vars. The official postgres image reads these on first boot:

  db:
    image: postgres:16
    environment:
      POSTGRES_USER: shop
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: shop
    volumes:
      - dbdata:/var/lib/postgresql/data

User, password, and database name here must match what the app's DATABASE_URL claims, or connections fail. When you hit a broken compose stack, comparing these two blocks is the first debugging move.

Code exercise · bash

Your turn: connection URLs are assembled from exactly the pieces in the env blocks. Using the five variables, print the DATABASE_URL the app needs, in the form postgres://user:password@host:port/dbname

What depends_on does and does not do

    depends_on:
      - db

This controls start order only: compose launches db before app. It does not wait for Postgres to actually be ready to accept connections, which takes a few seconds after the container starts.

So the app can still boot, try to connect, and fail while the database is warming up. Two real fixes:

  1. The app retries its database connection on startup (good practice regardless)
  2. A healthcheck on the db service, plus depends_on with condition: service_healthy, so compose waits for genuine readiness

Healthchecks get their own treatment in lesson 9-2. For now, remember the trap: started is not ready.

Quiz

With plain `depends_on: [db]`, compose starts db first, yet the app still crashes with "connection refused" on a slow machine. Why?

Problem

In the db service block, POSTGRES_PASSWORD is set to secret, but the app's DATABASE_URL says postgres://shop:hunter2@db:5432/shop. What happens when the app tries to connect: success or failure?