Search code examples
dockerdocker-composeyaml

Can you have variables in docker compose files? (Not environment variables)


services:
  backend:
    environment:
      DB_NAME: ${DB_NAME:-SOME_DB_NAME}

  postgres:
    image: postgres:
    environment:
      POSTGRES_DB: ${DB_NAME:-SOME_DB_NAME}

I have a docker compose file that I want to set defaults for unset environment variables, is there any way to ensure that someone doesn't accidentally change the default on one of them but not the other?

Ideally I would want to be able to have variables within the same file like

vars:
   DEFAULT_DB_NAME: SOME_DB_NAME

# USE vars: to change default config, don't touch below
services:
 backend:
   environment:
     DB_NAME: ${DB_NAME:-DEFAULT_DB_NAME}

 postgres:
   image: postgres:
   environment:
     POSTGRES_DB: ${DB_NAME:-DEFAULT_DB_NAME}

Or something similar but I couldn't find anything in the docker compose docs for this.


Solution

  • The easiest thing you can do in this space is to create a .env file that holds the default values.

    # .env
    DB_NAME=some_db_name
    
    services:
      backend:
        environment:
          DB_NAME:
    
      postgres:
        image: postgres:
        environment:
          POSTGRES_DB: ${DB_NAME}
    

    (It's intentional that I haven't provided a value for the backend container's DB_NAME. This syntax passes through $DB_NAME from the containing environment, which will default to what's in the .env file.)

    If you want to provide a different value, the shell environment overrides the .env file.

    DB_NAME=other_db_name docker-compose up -d
    

    There's no syntax in the Compose "specification" file format or any of its predecessors for declaring default values in the Compose file itself. The closest thing is awkward syntax using YAML fragments, but this can only replace (technically share) an entire YAML string value at the YAML level, it can't replace part of a string or participate in environment-variable interpolation at all. In principle something like this might work

    services:
      backend:
        environment:
          DB_NAME: &dbname ${DB_NAME:-some_db_name}
    
      postgres:
        image: postgres:
        environment:
          POSTGRES_DB: *dbname
    

    and you'd only have written the default value once, but I find YAML anchor syntax a little confusing and wouldn't usually recommend it. Compose does support arbitrary top-level extension blocks with YAML anchors and this might be closest to what you're after

    version: "3.8"  # minimum versions 2.1, 3.4, 4.0+composespecification
    x-vars:
      - &dbname ${DB_NAME:-some_db_name}
    
    services:
      backend:
        environment:
          DB_NAME: *dbname
    
      postgres:
        image: postgres:
        environment:
          POSTGRES_DB: *dbname
    

    This isn't really standard syntax though, and it won't work well if you wind up doing things like splitting your Compose setup into multiple files.