Workers
Bind a PortableSource from the Cloudflare env object once at module load, then read typed config with the same API as everywhere else.
On Cloudflare Workers (workerd) there is no filesystem and no ambient process.env. Your configuration is the env object the runtime exposes. Bind a PortableSource from it once, then read with the same typed API as everywhere else.
Import from envapt. The package export conditions resolve a node-free portable build on Workers automatically, so the same import works in local dev and on the Worker.
The filesystem-only config APIs have nothing to do on Workers, so they warn and no-op by default. Readers work as normal. See Compatibility for fileApiMode and Errors for the codes.
import { } from 'cloudflare:workers';
import { , } from 'envapt';
.(new ());
.('PORT', 3000); // readers work once a source is bound
. = ['.env']; // warns once and no-ops on WorkersBind once at module load
Env vars and secrets are readable at module scope through cloudflare:workers, and they are constant for a deployment. Bind the source in a config module and export the typed values the Worker needs, so binding happens once per isolate instead of on every request.
import { } from 'cloudflare:workers';
import { , , } from 'envapt';
.(new ());
const = .(
{
: .,
: .
},
'camelCase'
);
export const = {
...,
: .('CACHE_TTL', ., '1m')
};import { } from './config';
export default {
async (: ): <Response> {
if (..('authorization') !== `Bearer ${.}`) {
return new ('Unauthorized', { : 401 });
}
const = new (.);
return (new (. + ., .), );
}
} satisfies ;useSource sets process-global state shared across the isolate. That is safe here because a Worker's env is
constant for a deployment, so binding it once is idempotent. Do not put per-request data, the request or a user
id, into the source.
If you cannot import env
On an older compatibility date, or anywhere env is not importable at module scope, bind it at the top of the handler instead. The env is the same on every request, so the re-bind is idempotent.
import { , , } from 'envapt';
export default {
async (: , : <string, unknown>): <Response> {
.(new ());
const = .('ORIGIN_URL', .);
return (new (new (.)., ), );
}
} satisfies <<string, unknown>>;Non-string bindings
A Cloudflare vars entry can be JSON, not only a string. PortableSource JSON-stringifies any non-string binding so the converters parse it the same way. A binding whose value stringifies to undefined is dropped, and anything you read this way must be JSON-serializable.
declare const : { : { : boolean } }; // a JSON `vars` binding
.(new ());
const = .('FEATURE_FLAGS', .); // parsed back from the stringified bindingNo filesystem
There is no .env cascade and no custom profiles on workerd. Bind the source before your first read, an unbound read throws NoSourceBound. See Sources.
Decorators
A decorated property caches its value on first read, and Cloudflare env scalars are stable per isolate, so the cached value matches the binding. The default accessor decorators work on Workers, the legacy envapt/legacy form needs a compile step.
Configure Worker vars and bindings through Cloudflare's environment variables docs. For the providers and the contract see Sources.