v9.1.0

Templates

Build one environment variable from others by referencing them inside its value, and assemble strings from several keys with the resolve() tagged template.

A database URL needs a host and a port, and each can come from a different place, such as a default in .env and an override from your platform. Without references, every place that sets one of them has to write out the whole URL again. With ${VAR} references in the URL, Envapter joins whichever values are set when you read it. To build a string from several keys in your code, use the resolve tagged template.

.env
DB_HOST=localhost
DB_PORT=5432
DATABASE_URL=postgres://${DB_HOST}:${DB_PORT}/app
const  = .('DATABASE_URL');
// "postgres://localhost:5432/app"
// with DB_HOST=db.internal set by your platform: "postgres://db.internal:5432/app"

get('DATABASE_URL') expands both references. Every other reader does too, except getRaw, which returns the raw string as written. A converter or schema receives the expanded text. A decorated field expands once, on its first access, because it caches the result (Decorators). Expansion works on any source, including one you bind with useSource.

Nested references

A variable you reference can hold references of its own. envapt expands them until it reaches a cycle or a missing variable.

PROTOCOL=https
HOST=api.example.com
BASE_URL=${PROTOCOL}://${HOST}
HEALTHCHECK=${BASE_URL}/health

Reading HEALTHCHECK returns https://api.example.com/health.

Unresolved references

If a variable you reference is unset or empty, envapt leaves its ${VAR} text in the value. A cycle stays as text too. When a referenced variable's own value holds references and none of them resolve, the outer reference stays as text. If some of them resolve, the outer reference becomes the partly resolved text, such as x-${C}.

DB_HOST=localhost
DATABASE_URL=postgres://${DB_HOST}:${DB_PORT}/app

CACHE_URL=redis://${CACHE_HOST}
CACHE_HOST=${REDIS_HOST}

PRIMARY_URL=${REPLICA_URL}
REPLICA_URL=${PRIMARY_URL}

With DB_PORT and REDIS_HOST unset, the three reads return:

DATABASE_URL  ->  postgres://localhost:${DB_PORT}/app
CACHE_URL     ->  redis://${CACHE_HOST}
PRIMARY_URL   ->  ${REPLICA_URL}

${DB_HOST} resolves, but ${DB_PORT} stays as written. CACHE_URL shows ${CACHE_HOST}, a variable that is set, because CACHE_HOST can't finish expanding. PRIMARY_URL and REPLICA_URL reference each other, so the read stops at the first reference and returns ${REPLICA_URL}. Code that uses a value with an unresolved reference fails later. Set Envapter.debug = 'warn' to log each unresolved reference when it's read (Debug logging).

TIP

Set Envapter.strict = true (strict mode) to make a reference to a missing variable throw EnvaptError with code MissingEnvValue. A cycle still stays as text. Under strict mode a whitespace-only variable counts as unset too.

Syntax limits

envapt recognizes ${NAME}, where NAME is letters, digits, and underscores. A reference like ${VAR:-fallback} or an empty ${} doesn't match that pattern, so it stays in the value as written. envapt logs nothing for it, even with Envapter.debug = 'warn'. To default a missing variable, pass a fallback to the method, as in Envapter.get('VAR', 'fallback').

A $ that isn't followed by {...} stays as it is, as in price: $5. No escape sequence exists. To read a value that contains a literal ${...}, use getRaw, which skips expansion for the whole value.

The resolve tagged template

If you build a string from two reads by hand and a key is unset, a template literal prints the text undefined, because Envapter.get without a fallback returns undefined. resolve builds the string from the keys you list in the template. Each ${...} slot takes an env var name, or an ordered key list, and the first name with a value wins. A slot has no fallback. If a value contains ${VAR} references, envapt expands them first.

// API_HOST=api.example.com, API_PORT=8080
const endpoint = .`https://${'API_HOST'}:${'API_PORT'}`;
const endpoint: string
// reads READONLY_URL when present, otherwise DATABASE_URL const = .`Connecting to ${['READONLY_URL', 'DATABASE_URL']}`;

endpoint is a plain string. target uses READONLY_URL when it has a value and DATABASE_URL otherwise. It holds an empty string when neither has a value. A slot with a missing key behaves differently from a ${VAR} reference inside a value.

Key unset or empty${VAR} inside a valueresolve slot
Strict mode offkeeps the text ${VAR}inserts an empty string
Strict mode onthrows MissingEnvValuethrows MissingEnvValue

An empty string can hide a missing key inside a message that looks fine. If the string is a URL or a path, turn strict mode on or check the key with require first.

If your platform sets DATABASE_URL itself, that value wins over the templated line in .env by default, so DB_HOST and DB_PORT no longer affect it. A resolve call reads DB_HOST and DB_PORT directly, so it uses their values whatever DATABASE_URL holds.

On this page