Skip to main content

Dotenv Config

Read a project-local .env file with File::Read, decode scalar values at the boundary with Decode<T>, and reshape the result into a typed runtime config.

Source

examples/dotenv-config/.env
APP_ENV=prod
PORT=9000
DEBUG=true
APP_NAME="Rank Docs"
examples/dotenv-config/main.rank
/// Reads a project-local dotenv file through File::Read with Decode<T>
/// at the flat text boundary and reshapes it into a typed runtime config.

use std::Decode
use std::File
use std::Path

AppEnv = `dev` | `prod`
Port = 8080 | 9000

DotenvConfig = Object {
APP_ENV: AppEnv,
PORT?: Decode<Port>,
DEBUG?: Decode<bool>,
APP_NAME: string,
...: string,
}

AppConfig = Object {
name: string,
env: AppEnv,
port: number,
debug: bool,
source: Object {
path: string,
format: `dotenv`,
},
}

response = File::Read<DotenvConfig> {
path: Path::join([`.env`]),
format: `dotenv`,
}

raw = response.body

config: AppConfig = {
name: raw.APP_NAME,
env: raw.APP_ENV,
port: raw.PORT ?? 8080,
debug: raw.DEBUG ?? false,
source: {
path: response.ctx.path,
format: `dotenv`,
},
}

pub main = || config

Output

{
"name": "Rank Docs",
"env": "prod",
"port": 9000,
"debug": true,
"source": {
"path": ".env",
"format": "dotenv"
}
}

Key concepts

  • format: dotenvFile::Read can decode .env-style flat text files as an explicit file dependency rather than ambient host environment.
  • Boundary decoding with Decode<T>PORT?: Decode<Port> and DEBUG?: Decode<bool> turn dotenv text into typed scalar values as the file is read.
  • Flat text model — each dotenv entry stays one key/value text boundary; nested objects and lists are not decoded from a single entry.
  • response.ctx — file provenance stays explicit, so the resulting config can still carry the source path and format.
  • Defaults after decode — optional decoded fields combine cleanly with ?? once the boundary parsing has succeeded.

Run it

rank examples/dotenv-config