Documentation menu
Package

serez-dotenv

A project-level .env loader for Serez Code. It reads .env, .env.local and .env.<mode>, merges them by priority, and resolves variables read-only — it never mutates the real process environment.

Install

sz install serez-dotenv

serez-dotenv declares the Env permission itself (it only uses it for the fallback to the system environment), so apps that install it do not need to add Env to their own serez.json. Reading the .env files uses File, which needs no permission.

Quick start

Construct a Process with the mode and read variables through process.env. The .env files are read from the current working directory (the project root).

import "serez-dotenv"

let process = new Process("dev")          // mode: dev | qa | local

let host = process.env.get("HOST")        // resolved value, or null if undefined
if (host == null) {
    out "HOST is not set"
} else {
    out "HOST = " + host
}

Modes

The mode passed to new Process(mode) decides which layers are loaded:

ModeLayers loaded
dev.env + .env.local + .env.dev
qa.env + .env.local + .env.qa
local.env + .env.local

Layered resolution

When you read a key, the most specific layer that defines it wins. If none of the .env layers define it, the lookup falls back to the system environment as a last resort. From lowest to highest priority:

System  <  .env  <  .env.local  <  .env.<mode>   (dev | qa)
  • .env — base layer, always loaded if present.
  • .env.local— the developer's personal overrides, always loaded. It always loses to .env.dev / .env.qa — by design, so personal tweaks never harden the deployed config.
  • .env.<mode> — top layer, only in dev or qa mode. In local mode there is no dev/qa layer.

Example — in dev mode, when every layer defines HOST, .env.dev wins:

System      HOST  ✗
.env        HOST  ✗
.env.local  HOST  ✗
.env.dev    HOST  ✓   ← wins

API

CallReturnsDescription
new Process(mode)ProcessLoads the current directory's layers for the given mode (dev | qa | local).
process.env.get(key)string?Value resolved across layers, falling back to System; null if undefined everywhere.
process.env.has(key)booltrue if the key is defined in some .env layer (ignores System).
process.modestringThe mode the Process was constructed with.
loadEnv(dir, mode)EnvResolverLoads the layers from an arbitrary directory — handy for tests or reading another folder's .env.

process.env.get(...) returns null (it does not throw) when the variable exists in no layer and not in the system environment.

The .env file format

# Comments start with '#' (whole line only)
HOST=localhost
PORT=8080
DB_URL=postgres://user:pass@host/db
QUOTED="with spaces"         # surrounding quotes are stripped
SINGLE='also single quotes'
export TOKEN=abc123          # the 'export' prefix is ignored
EMPTY=                       # empty value allowed
  • One variable per line: KEY=VALUE.
  • Blank lines and lines starting with # are ignored.
  • Whitespace around the key and value is trimmed.
  • Surrounding "…" or '…' quotes are removed.
  • An optional export prefix is discarded.
  • If a key repeats within the same file, the last one wins.
  • # is only a comment at the start of a line — there are no inline comments.

A complete example

.env

HOST=base-host
PORT=3000
DB_URL=postgres://localhost/app

.env.dev

HOST=dev-host
DEBUG=true

app.sz

import "serez-dotenv"

let process = new Process("dev")

let host  = process.env.get("HOST")    // "dev-host"  (.env.dev overrides .env)
let port  = process.env.get("PORT")    // "3000"      (only in .env)
let debug = process.env.get("DEBUG")   // "true"      (only in .env.dev)
let user  = process.env.get("USER")    // from the system, or null if unset

Design notes

  • Read-only: it never calls Env.set — the process environment is never polluted.
  • No dependencies: pure .sz on top of the core (File and Env namespaces).
  • The .env files are read from the current working directory (the project root); use loadEnv(dir, mode) to read another folder.
  • Every value resolves to a string (or null) — parse numbers and booleans yourself.