Install
npm install @goenvless/envTwo ways to load
Loading is asynchronous: variables are fetched as ciphertext and decrypted locally, so env can only be read after the loader has run. Both options below guarantee that before your code executes.
Preload with /register (recommended)
@goenvless/env/register is a side-effect-only module. Importing it eagerly runs the loader with a top-level await, so every variable is populated before the rest of your entrypoint evaluates. Put the import first, in an ESM entry file:
import '@goenvless/env/register';
import express from 'express';
const app = express();
// ... env is already populatedThe loader fetches → decrypts → writes into process.env and into the store behind the env proxy, without overwriting anything already set in the ambient environment.
Names that change how a process or its children execute code are the exception. NODE_OPTIONS, NODE_PATH, NODE_REPL_EXTERNAL_MODULE, ELECTRON_RUN_AS_NODE, LD_PRELOAD, LD_LIBRARY_PATH, LD_AUDIT, DYLD_INSERT_LIBRARIES, DYLD_LIBRARY_PATH, DYLD_FRAMEWORK_PATH, PATH, BUN_INSPECT, BUN_INSPECT_CONNECT_TO, RUBYOPT, RUBYLIB, BUNDLE_GEMFILE, GEM_HOME, GEM_PATH, PYTHONPATH, PYTHONHOME, PYTHONSTARTUP, PYTHONUSERBASE, PHPRC, PHP_INI_SCAN_DIR, ENVLESS_CLIENT_ENV and ENVLESS_INJECTED are fetched, decrypted and readable through env, but deliberately never written into process.env. The match is on the whole name and without regard to case, since the Windows process environment ignores case, so path and Node_Options are refused exactly like PATH and NODE_OPTIONS. Storing one of those would turn write access to a variable into code execution. The loader prints a warning listing every name it refused.
--import flag
If you can't put the import first, or your entry is CommonJS, preload it from the launcher instead. require('@goenvless/env/register') throws on purpose, because a require cannot block and would hand control back before a single variable is loaded:
node --import @goenvless/env/register server.jsSame effect, no source changes. Useful for adding Envless to existing apps or third-party scripts.
Use it
import '@goenvless/env/register';
import { env } from '@goenvless/env/server';
const port = env.PORT; // number when PORT is declared as a number
const db = new Database(env.DATABASE_URL);
app.listen(port);Nothing auto-loads. Without the /register preload or an awaited load() from @goenvless/env/server, the first read throws Envless env is not loaded yet. Import '@goenvless/env/register' or await load() first. Once loaded, reading a name the environment doesn't have throws Missing env var: DATABASE_URL.
/server exposes every variable, server and client visibility alike, each coerced to the type declared in Envless. A variable is a string unless it was declared otherwise, number values go through Number(), and boolean is true only for the exact values true and 1. There is no required or default metadata, a missing variable throws on read. Import optional alongside env when a read is allowed to come back empty: it is the same proxy typed Partial<EnvlessServerEnv>, returning undefined for a name the store does not hold.
Process management
With pm2, forever, or systemd, provide the machine credential set in the service definition. The loader reads it on each restart:
# /etc/systemd/system/myapp.service
Environment=ENVLESS_TOKEN=ev_sk_xxxxxxxxxxxx
Environment=ENVLESS_KEY=xxxxxxxxxxxx
Environment=ENVLESS_PROJECT=my-app
Environment=ENVLESS_ENV=production
ExecStart=/usr/bin/node --import @goenvless/env/register /srv/app/server.jsENVLESS_TOKEN must be a machine key (ev_sk_…) and fetches the ciphertext; ENVLESS_KEY (or ENVLESS_PASSPHRASE) decrypts it locally. ENVLESS_PROJECT and ENVLESS_ENV are both required unless a .envless file sits in the process working directory. See Machine & CI access for the complete reference.
Workers and child processes
Variables populated in process.env are inherited by child_process.spawn / fork by default, with no extra setup. The refused names above are not, since they never reach process.env. For Worker threads, pass env: process.env explicitly if you've customized the worker's env.