Quick Start

Install envapt and read your first typed environment variable.

Install

pnpm add envapt

Read a value

Put a variable in your .env:

PORT=8080

Read it as a number, with a fallback for when it is unset:

const port = .('PORT', 3000);
const port: number

The fallback supplies the default and removes undefined from the type. See Envapter for the full reader API and Converters for non-primitive types.

Or bind it to a class

The @Envapt decorator binds a value to a typed field:

class  {
    @('PORT', { : ., : 3000 })
    declare static readonly : number;
}

Decorators need experimentalDecorators enabled, and the property declared with declare and no initializer:

tsconfig.json
{
    "compilerOptions": {
        "experimentalDecorators": true
    }
}
WARNING

Declare the property with declare and no initializer. A real field declaration (or an initializer) emits an assignment that overwrites envapt's getter, so the property reads back as undefined at runtime. See Decorators.

Drop-in for dotenv

For the dotenv/config workflow, import envapt/config. It loads the .env cascade and mirrors every loaded key into process.env in one step, so process.env.PORT works without touching Envapter.

import 'envapt/config';

const  = ..; // the loaded keys are now on process.env

It is the side-effect form of Envapter.syncProcessEnv = true plus an eager load, and follows the same collision rules. Unlike dotenv/config, it loads the whole per-environment cascade, not a single .env.

Preload it without editing your entry file:

node --import envapt/config app.js   # ESM
node -r envapt/config app.js         # CommonJS

For typed reads on top, keep using Envapter.

Requirements

envapt runs on Node >=20, Bun >=1.3, and Deno >=2.5. The functional API needs no build step on any runtime; the decorator API is TypeScript and needs compilation, with one caveat on Bun. See Compatibility.

On this page