Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.envless.cloud/llms.txt

Use this file to discover all available pages before exploring further.

The schema lives in Envless

Every variable in the dashboard has a type, a required/optional flag, and a visibility. envless reads that schema and generates a TypeScript declaration file. You don’t repeat it in code.

Dashboard fieldEffect in code
NameBecomes a property on env
Type (string, number, boolean)Becomes the property type and triggers coercion
RequiredRequired-ness in the type, throws if missing
DefaultUsed when the value isn’t set
Visibility (server / client)Determines which import surface includes it

Generate types

envless types
Writes envless-env.d.ts next to your package.json:
// envless-env.d.ts (generated)
declare module '@goenvless/envless/server' {
    export const env: {
        DATABASE_URL: string;
        PORT: number;
        STRIPE_SECRET: string;
        FEATURE_X_ENABLED: boolean;
        NEXT_PUBLIC_API_URL: string;
    };
}

declare module '@goenvless/envless/client' {
    export const env: {
        NEXT_PUBLIC_API_URL: string;
    };
}
Commit this file. It contains no secrets, only the shape — and committing it means teammates get autocomplete without running anything.

Keep types in sync

Run envless types whenever you add or rename a variable in the dashboard. Or wire it up so it runs automatically:
{
    "scripts": {
        "postinstall": "envless types",
        "dev": "envless types && next dev"
    }
}

Coercion

Values are stored as strings in the encrypted bundle. The proxy coerces them on read based on the schema type:
env.PORT              // number    — "3000"  → 3000
env.FEATURE_X         // boolean   — "true"  → true
env.DATABASE_URL      // string
Coercion happens once and is cached. There’s no Number(env.PORT) ceremony.

Missing variables throw loudly

env.NOT_A_REAL_KEY    // throws: "Missing env var: NOT_A_REAL_KEY (env: development)"
This is intentional — silent undefined is the single worst thing about process.env. If you genuinely want optional, mark the variable optional in the dashboard and the type becomes string | undefined.

Test overrides

For tests, you can override values without mutating global state:
import { env, __override } from '@goenvless/envless/server';

test('feature X enabled', () => {
    using _ = __override({ FEATURE_X_ENABLED: true });
    expect(env.FEATURE_X_ENABLED).toBe(true);
});
The using declaration scopes the override to the block — no cleanup needed.

Why this beats t3-env / hand-rolled Zod

Hand-rolled validationenvless
Schema locationLives in code, drifts from .envLives in the dashboard, single source
Add a variableEdit env.ts, edit .env, edit .env.example, commitAdd it in the dashboard, run envless types
Required/defaultRe-declared in ZodAlready in the schema
Client/server splitManual client: / server: blocksVisibility flag in dashboard
Runtime valuesManually mapped via runtimeEnv: { ... }Automatic