Skip to content

Dynamic Variables

Template substitutions

Dynaconf has 2 tokens to enable string substitutions, the interpolation works with @format and @jinja.

@format token

Dynaconf allows template substitutions for strings values, by using the @format token prefix and including placeholders accepted by Python's str.format method Dynaconf will call it lazily upon access time.

The call will be like:

"<YOURVALUE>".format(env=os.environ, this=dynaconf.settings)

So in your string you can refer to environment variables via env object, and also to variables defined int the settings object itself via this reference. It is lazily evaluated on access it will use the final value for a settings regardless the order of load.

Example:

export PROGRAM_NAME=calculator

settings.toml

[default]
DB_NAME = "mydb.db"

[development]
DB_PATH = "@format {env[HOME]}/{this.current_env}/{env[PROGRAM_NAME]}/{this.DB_NAME}"
  • {env[HOME]} is the same as os.environ["HOME"] or $HOME in the shell.
  • {this.current_env} is the same as settings.current_env
  • {env[PROGRAM_NAME]} is the same as os.environ["PROGRAM_NAME"] or $PROGRAM_NAME in the shell.
  • {this.DB_NAME} is the same as settings.DB_NAME or settings["DB_NAME"]

so in your program

from dynaconf import settings

settings.DB_PATH == '~/DEVELOPMENT/calculator/mydb.db'

@format token can be used together with tokens like @str, @int, @float, @bool, and @json to cast the results parsed by @format.

Example:

Casting to integer from @format templated values

NUM_GPUS: 4
# This returns the integer after parsing
FOO_INT: "@int @format {this.NUM_GPUS}"
# This returns the string after parsing
FOO_STR: "@format {this.NUM_GPUS}"

@jinja token

If jinja2 package is installed then dynaconf will also allow the use jinja to render string values.

Example:

export PROGRAM_NAME=calculator

settings.toml

[default]
DB_NAME = "mydb.db"

[development]
DB_PATH = "@jinja {{env.HOME}}/{{this.current_env | lower}}/{{env['PROGRAM_NAME']}}/{{this.DB_NAME}}"

so in your program

from dynaconf import settings

settings.DB_PATH == '~/development/calculator/mydb.db'

The main difference is that Jinja allows some Python expressions to be evaluated such as {% for, if, while %} and also supports calling methods and has lots of filters like | lower.

Jinja supports its built-in filters listed in Builtin Filters Page and Dynaconf includes additional filters for os.path module: abspath. realpath, relpath, basename and dirname and usage is like: VALUE = "@jinja {{this.FOO | abspath}}"

@jinja token can be used together with tokens like @str, @int, @float, @bool, and @json to cast the results parsed by @jinja.

Example:

Casting to integer from @jinja templated values

NUM_GPUS: 4
# This returns the integer after parsing
FOO_INT: "@int @jinja {{ this.NUM_GPUS }}"
# This returns the string after parsing
FOO_STR: "@jinja {{ this.NUM_GPUS }}"

Example:

Casting to a json dict from @jinja templated values

MODEL_1:
  MODEL_PATH: "src.main.models.CNNModel"
  GPU_COUNT: 4
  OPTIMIZER_KWARGS:
    learning_rate: 0.002

MODEL_2:
  MODEL_PATH: "src.main.models.VGGModel"
  GPU_COUNT: 2
  OPTIMIZER_KWARGS:
    learning_rate: 0.001

# Flag to choose which model to use
MODEL_TYPE: "MODEL_2"

# This returns the dict loaded from the resulting json
MODEL_SETTINGS_DICT: "@json @jinja {{ this|attr(this.MODEL_TYPE) }}"

# This returns the raw json string
MODEL_SETTINGS_STR: "@jinja {{ this|attr(this.MODEL_TYPE) }}"

Name aliasing

In certain cases you need to reuse some variable value respecting the exact data type it is previously defined in another step of the settings load.

Example:

config.py
from dynaconf import Dynaconf
settings = Dynaconf(settings_files=["settings.toml", "other.toml"])  
settings.toml
thing = "value"
number = 42
other.toml
other_thing = "@get thing"

# providing default if thing is undefined
other_thing = "@get thing 'default value'"

## type casting
# Ensure the aliased value is of type int
other_number = "@get number @int"

# Ensure type and provide default if number is undefined
other_number = "@get number @int 12"

The @get is lazily evaluated and subject to DynaconfFormatError in case of malformed expression, it is recommended to add validators.