env.loading
import env.loading
envlifts part of this module out to its own top level; each name below is shown with the path that reaches it. Anything still spelledenv.loading.*needsimport env.loading.
The loader: which sources to read, in what order, and what to do with the names that come out of them.
A load is three steps that stay separate. The sources are scanned into
names and values, the $ references among them are resolved, and then
the result is written into the process environment. Calling read()
instead of load() stops after the second, which is what makes a .env
file inspectable without anything being set.
Classes
Result
class env.Result
What a load did.
values is everything the sources defined, after expansion, in the
order the names were first seen. The three lists beside it account for
each name and each file, so a program never has to guess whether its
configuration actually arrived.
var result = env.load()
if result.files.is_empty() {
log.warn('no .env file was found; using the environment as it stands')
}
for name in result.skipped {
log.debug('${name} was already set, so the file did not change it')
}
- printable — has a
@to_string(), soechoandprint()show something useful
Constructor
env.Result()
Result.to_string()
env.Result.to_string()
Loader
class env.Loader
Builds a load: the sources it reads and the four decisions it makes about them.
Every setting returns the loader, so a whole configuration is one expression:
import env
var result = env.loader()
.path('.env')
.path('.env.local')
.override()
.load()
Sources are read in the order they were added and layered on top of one
another, so the last source to define a name is the one that defines it.
That is what makes the pair above work: .env holds what the team
shares and .env.local holds what one machine does differently.
A loader is reusable. Nothing about it changes when load() runs, so
the same one can be kept and run again.
Constructor
env.Loader()
Loader.path()
env.Loader.path(path: string) -> Loader
Adds a file to read.
A leading ~ is expanded to the home directory, and a relative path is
resolved against the current working directory. A file that is not there
is not an error unless required() says so.
Parameters
path(string)
Returns Loader
Loader.paths()
env.Loader.paths(paths: list) -> Loader
Adds several files to read, in the order given.
Parameters
paths(list)
Returns Loader
Loader.source()
env.Loader.source(text: string) -> Loader
Adds text to read, as though it were the contents of a file.
This is how configuration that arrived over the network, out of a secret store, or from a test fixture goes through exactly the same parsing, expansion and precedence as a file on disk.
Parameters
text(string)
Returns Loader
Loader.override()
env.Loader.override(enabled: ?bool) -> Loader
Sets whether a name already present in the process environment is replaced by the one the sources define.
Off by default, which is what makes a .env file a set of defaults:
whatever the shell, the orchestrator or the CI runner already set
survives, and the file fills in the rest. Turn it on and the file wins
instead.
A variable set to the empty string counts as unset either way.
Parameters
enabled(?bool) — Defaults totruewhen the argument is left out.
Returns Loader
Loader.expand()
env.Loader.expand(enabled: ?bool) -> Loader
Sets whether $ references inside values are resolved.
On by default. Turn it off and every value is used exactly as it was written, which is what a file of opaque secrets wants.
Parameters
enabled(?bool) — Defaults totruewhen the argument is left out.
Returns Loader
Loader.required()
env.Loader.required(enabled: ?bool) -> Loader
Sets whether a file that is not there is an error.
Off by default, because the same program usually runs both on a laptop
with a .env file and on a server where the orchestrator supplies the
environment directly. Turn it on where the file is genuinely part of the
deployment and its absence should stop the program rather than surface
later as a missing setting.
Parameters
enabled(?bool) — Defaults totruewhen the argument is left out.
Returns Loader
Raises MissingFile from load() and read() when a file is
absent.
Loader.read()
env.Loader.read() -> Result
Reads the sources and returns what they hold, without touching the process environment.
$ references still resolve, and they resolve the same way they would
during a real load, so what comes back is what load() would have set.
The applied and skipped lists on the result are empty, because
nothing was applied and nothing was skipped.
Returns Result
Raises ParseError when a source is not a valid environment file.
Raises MissingFile when required() is on and a file is absent.
Loader.load()
env.Loader.load() -> Result
Reads the sources and writes what they hold into the process environment.
A name already set to a non-empty value is left alone and recorded in
Result.skipped, unless override() is on. Everything else is set and
recorded in Result.applied.
import env
env.loader().path('.env').required().load()
Returns Result
Raises ParseError when a source is not a valid environment file.
Raises MissingFile when required() is on and a file is absent.
Raises MissingVariable when a ${NAME:?reason} reference finds
nothing.
2026, Richard Ore and Zuri contributors