Typed environments
Run envlet login, then run envlet types in a linked repository:
envlet typesThe first run asks for a language and repository-relative output path. It records both under types in .envlet. Later runs use that configuration.
For this schema:
PORT: required integerRATIO: optional numberENABLED: required booleanAPI_URL: required URLSETTINGS: required JSONMODE: enum withdevelopmentandproduction
TypeScript output includes:
declare module "@envlet/sdk" { interface Env { API_URL: string; ENABLED: boolean; MODE: "development" | "production"; PORT: number; RATIO?: number; SETTINGS: unknown; }}Python uses int, float, bool, str, Literal, Any, and Optional. Go uses int64, float64, bool, string, any for json, and pointers for optional values. Rust uses i64, f64, bool, String, envlet::serde_json::Value, and Option.
PHP uses int, float, bool, string, mixed, and nullable properties. Elixir uses integer(), float(), boolean(), String.t(), term(), and a nil union. Ruby writes the same Struct with a generated schema map. The generated loader reads the parsed values the SDK returns and checks each one against the declared type, so it needs no dependency beyond the SDK.
Commit the generated file and .envlet. Check for name or schema drift in CI:
- run: npx envlet types --check env: ENVLET_TOKEN: ${{ secrets.ENVLET_TOKEN }}--check does not fetch values or write files. It exits with status 1 when a name, type, required setting, or enum set differs. Withheld names are reported but remain part of the environment schema.