Environment variables
Server apps such as Ktor and Spring Boot read their configuration from environment variables. Kargo starts kargo run and kargo test programs with a project environment, built from three places: the [env] table in kargo.toml, .env files next to it, and your shell. Tasks and hook plugins get the same variables.
Set variables in kargo.toml
Section titled “Set variables in kargo.toml”A variable is a string, a number or a boolean. Use the table form when you need more than a value:
[env]APP_NAME = "demo"PORT = 8080LOG_LEVEL = { value = "debug", force = false } # the default: a value already set in the shell winsCONFIG_DIR = { value = "config", relative = true } # resolved against the package rootDATABASE_URL = { required = true } # no default: it must come from the shell or a .env file
[profile.release.env] # replaces [env] for release builds, variable by variableLOG_LEVEL = "info"| Key | Meaning |
|---|---|
value |
The value. Required unless required = true |
force |
true makes value win over the shell and the .env files too |
relative |
true resolves value against the package’s directory, so config becomes an absolute path |
required |
true fails kargo run, kargo test and kargo task before anything runs when neither the shell nor a .env file sets the variable. Can’t be combined with value |
env-files and expose are not variables; they are described below.
Use .env files
Section titled “Use .env files”Put settings that differ between machines or profiles in .env files in the package’s directory:
| File | Read by | Priority |
|---|---|---|
.env |
every profile | lowest of the files |
.env.dev, .env.release, .env.<name> for a custom profile |
that profile only | above .env |
.env.local |
every profile | above the profile files |
.env.dev.local, .env.release.local, .env.<name>.local |
that profile only | highest of the standard files |
A missing file is skipped. kargo new adds .env.local and .env.*.local to .gitignore, so machine-specific values and secrets stay out of the repository. Commit a .env with safe defaults if your team wants one.
# Defaults shared by every profileAPP_NAME=demo-appDATABASE_URL=postgres://localhost/devAPI_TOKEN="s3cret"# This machine only, ignored by gitAPI_TOKEN=local-tokenThe format is the usual dotenv:
- Lines are
KEY=value. Anexportprefix, empty values and#comments on their own lines are fine. An unquoted value ends at a#comment. - Single quotes take the value literally. Double quotes understand
\n,\t,\"and\\, and can span several lines. ${NAME}and${NAME:-default}insert another variable: a key set earlier in the same file or in a file read before it, otherwise the shell’s value. Variables from kargo.toml are not used. An unset name becomes the default, or nothing. Single-quoted values are not expanded.
BASE_URL=http://localhost:${PORT:-8080}LOG_FILE=${LOG_DIR:-logs}/app.logMore files with env-files
Section titled “More files with env-files”env-files in [env] names more .env files, relative to the package root. They are read after the standard ones, so they win over them. A profile can add its own list in [profile.<name>.env], read after the [env] list and only for that profile:
[env]env-files = ["config/shared.env"]
[profile.release.env]env-files = ["config/release.env"]A file named in env-files must exist; a missing one is an error that names the key. --no-env-file skips these files too.
Precedence
Section titled “Precedence”From the highest priority to the lowest, the first source that sets a variable wins:
- A variable in kargo.toml with
force = true - The shell’s environment
--env-filefiles, the last one given first.env.<profile>.local.env.local.env.<profile>.envenv-filesof[profile.<name>.env], the last one firstenv-filesof[env], the last one first[profile.<name>.env][env]
Without force, a variable you export in your shell beats everything in the project, so you can override any value for one run:
$ LOG_LEVEL=trace kargo runRequired variables
Section titled “Required variables”required = true says the program can’t work without the variable. kargo run, kargo test and kargo task check for it before they build or run anything:
$ kargo runerror: required environment variable not set: `DATABASE_URL` (declared in [env])set it in your shell or in a .env file, or give it a `value` in kargo.tomlBuilds don’t check. kargo build, kargo check, kargo package and kargo publish go ahead without it, and the build hooks they run get only the variables that are set. Android and Wasm browser programs don’t get the environment at all, so they don’t need the check either.
Check the result with kargo env
Section titled “Check the result with kargo env”kargo env lists every variable the program gets, the source that won, and the value. Values are hidden by default because they often hold secrets:
$ kargo envAPI_TOKEN .env.local:1 ********APP_NAME .env:1 ********CONFIG_DIR [env] ********DATABASE_URL .env.dev:1 ********LOG_LEVEL [env] ********note: values are hidden; pass --show-values to print them--show-values prints them, and --release (or --profile <name>) shows that profile’s variables instead of the dev ones. The source is shell, a section of kargo.toml such as [env] or [profile.release.env], or a .env file with its line number. A required variable that nothing sets is listed as missing (required). kargo env itself succeeds, so you can look at a machine that isn’t ready yet.
Checks for CI
Section titled “Checks for CI”kargo env --check is the check for a CI job or a new machine. It fails and lists every problem when:
- a required variable is not set, and
- a key of
.env.exampleis neither set in the shell nor declared by any source.
# Every variable a developer must set; values are examples onlyDATABASE_URL=API_TOKEN=$ kargo env --checkerror: the environment is incomplete: `DATABASE_URL` is required but not set (declared in [env]) `API_TOKEN` is listed in .env.example but not setWithout a .env.example, --check looks at the required variables only.
Secrets in git
Section titled “Secrets in git”Kargo warns when a .env file that git tracks sets a variable whose name looks like a secret (it contains SECRET, TOKEN, PASSWORD, PASSWD or CREDENTIAL, or it is KEY or ends in _KEY) with a value. The warning is printed by kargo run, kargo test, kargo task and kargo env, and it is listed in the warnings reference. Move the secret into a .local file, which is git-ignored, or into your shell.
Choose the files for one command
Section titled “Choose the files for one command”--env-file <path> reads one more .env file after the standard ones, so its values win over them. Repeat it for several files. --no-env-file reads none of the .env files; the variables in kargo.toml and the shell still apply. The two flags can’t be combined.
$ kargo run --env-file .env.staging$ kargo test --no-env-file$ kargo env --env-file .env.staging --show-valuesTasks take the same flags, either before the task name or right after it:
$ kargo task --env-file .env.staging deploy$ kargo deploy --env-file=.env.stagingFlags after the task name are taken only from the front of its arguments, so kargo deploy --env-file .env.staging --dry-run passes --dry-run on to the task. Workspace tasks run at the root, which has no [env] of its own, so they get no project environment.
Build commands don’t take these flags. Their hooks read the standard files.
Compile variables into the code
Section titled “Compile variables into the code”Some values belong in the program itself, such as a version or a build identifier. List them in expose in [env], and Kargo generates a Kotlin object with one property for each:
[env]expose = ["APP_NAME", "BUILD_ID"]APP_NAME = "demo"The object is BuildConfig in a package made from the group and name of the package (my-app becomes my_app; with group = "com.example", it is com.example.my_app):
import my_app.BuildConfig
fun main() { println("${BuildConfig.APP_NAME}")}A variable that is set becomes a const val with its value, and one that is not set becomes a nullable val with null, so a build doesn’t fail for a variable only some machines have. The file is written to target/<profile>/<target>/generated/env/BuildConfig.kt, and it is rewritten only when its contents change.
A build-config generator can also write the package’s version and Git commit. When a project has one, the expose variables go into its object instead of a second BuildConfig.
expose applies to the JVM, Native and Wasm (Node.js) targets. It is not generated for Android, which has its own build-config in [target.android], nor for Wasm browser apps.
Where the variables go
Section titled “Where the variables go”| Program | Gets the project environment | Required variables checked |
|---|---|---|
kargo run on the JVM, Native, and Wasm with node |
Yes | Yes |
kargo test on the JVM, Native, and Wasm tests on Node.js |
Yes | Yes |
kargo task and kargo <task> (package tasks) |
Yes; a task’s own env still wins |
Yes |
| Build hooks and hook plugins | Yes, the variables that are set | No |
| Wasm browser apps and browser tests | No: the browser doesn’t read process variables | No |
Android (kargo run -t android, kargo test -t android) |
No: Gradle installs the app, which gets no process variables | No |
The variables are not written into your build output, except those you list in expose. Read the others at run time with System.getenv (JVM), platform.posix.getenv (Native) or process.env (Node.js).
Only the variables themselves are listed in kargo.toml, and kargo env is in the command reference.