Cloudflare Workers
Varlock provides a robust solution for managing environment variables in Cloudflare Workers, offering validation, type safety, and security features that go beyond Cloudflare’s built-in environment variable and secrets handling.
Our integration relies on using varlock-wrangler — a thin wrapper around wrangler that automatically resolves and uploads your env vars as Cloudflare secrets and vars during deployment, and injects them into miniflare during local dev.
Choosing an approach
Section titled “Choosing an approach”All paths use the same .env.schema and varlock-wrangler deploy for production uploads — the difference is how env reaches your worker during local dev and build:
| Approach | Best when | Dev / build |
|---|---|---|
varlock-wrangler | Plain Workers, minimal tooling | varlock-wrangler dev injects env via FIFO and watches .env files; varlock-wrangler deploy uploads vars + secrets |
| Vite plugin | Already using @cloudflare/vite-plugin | vite dev injects into miniflare automatically; vite build + varlock-wrangler deploy |
| SvelteKit adapter plugin | SvelteKit with @sveltejs/adapter-cloudflare | vite dev via an SSR entry loader; vite build + varlock-wrangler deploy |
Approach 1: Using varlock-wrangler
Section titled “Approach 1: Using varlock-wrangler”Replace your wrangler commands with varlock-wrangler and initialize varlock in your worker code with a single import. It’s a thin wrapper that wires up your env vars correctly, and passes everything else through unchanged.
-
Install packages
Terminal window npm install @varlock/cloudflare-integration varlockTerminal window pnpm add @varlock/cloudflare-integration varlockTerminal window bun add @varlock/cloudflare-integration varlockTerminal window yarn add @varlock/cloudflare-integration varlockTerminal window vlt install @varlock/cloudflare-integration varlock -
Run
varlock initto set up your.env.schemafileThis will guide you through setting up your
.env.schemafile, based on your existing.envfile(s). Make sure to review it carefully.Terminal window npm exec -- varlock initTerminal window pnpm exec -- varlock initTerminal window bunx varlock initTerminal window vlx -- varlock initTerminal window yarn exec -- varlock init -
Add the varlock init import to your worker entry point
This initializes varlock’s
ENVproxy and applies console redaction and response leak detection (unless disabled):src/index.ts import '@varlock/cloudflare-integration/init';import { ENV } from 'varlock/env';export default {async fetch(request, env, ctx) {// both work:console.log(ENV.MY_VAR); // varlock (recommended)console.log(env.MY_VAR); // native Cloudflarereturn new Response('Hello!');},}; -
Update your package.json scripts to use
varlock-wranglerUse
varlock-wrangleras a drop-in replacement forwrangler:package.json {"scripts": {"dev": "varlock-wrangler dev","deploy": "varlock-wrangler deploy","types": "varlock-wrangler types",}}If you deploy via Cloudflare Workers Builds instead of a local/CI script, override the deploy command in your Cloudflare dashboard under Settings → Build → Deploy command — see Workers Builds below.
How it works
Section titled “How it works”- In dev:
varlock-wrangler devresolves your env and injects it intowranglerusing--env-filewith a named pipe (unix/mac) or temp file (windows). It also watches your.envfiles and automatically restarts wrangler when they change - somethingwrangler devdoesn’t do. - In production:
varlock-wrangler deploy(andvarlock-wrangler versions upload) attaches non-sensitive values as Cloudflare vars (via--var) and sensitive values as Cloudflare secrets via--secrets-file. The worker reads them at runtime viaimport { env } from 'cloudflare:workers'.
Approach 2: With the Vite plugin
Section titled “Approach 2: With the Vite plugin”If you’re building with Vite, varlockCloudflareVitePlugin wraps the Cloudflare Workers Vite plugin and adds env var + varlock init injection — no extra init import needed, and both ENV.MY_VAR and native env.MY_VAR work in dev and production.
For SvelteKit on Cloudflare, use the dedicated varlockSvelteKitCloudflarePlugin from @varlock/cloudflare-integration/sveltekit instead.
-
Install packages
Terminal window npm install @varlock/cloudflare-integration @cloudflare/vite-plugin varlockTerminal window pnpm add @varlock/cloudflare-integration @cloudflare/vite-plugin varlockTerminal window bun add @varlock/cloudflare-integration @cloudflare/vite-plugin varlockTerminal window yarn add @varlock/cloudflare-integration @cloudflare/vite-plugin varlockTerminal window vlt install @varlock/cloudflare-integration @cloudflare/vite-plugin varlock@cloudflare/vite-pluginis an (optional) peer dependency — this plugin wraps it, so you need it installed in the same project. SvelteKit users should omit it (see the SvelteKit callout at the top of this page). -
Run
varlock initto set up your.env.schemafileTerminal window npm exec -- varlock initTerminal window pnpm exec -- varlock initTerminal window bunx varlock initTerminal window vlx -- varlock initTerminal window yarn exec -- varlock init -
Update your Vite config
Replace the
cloudflare()plugin withvarlockCloudflareVitePlugin()— it is a thin wrapper of the Cloudflare vite plugin and passes through all config:vite.config.ts import { defineConfig } from 'vite';import { cloudflare } from '@cloudflare/vite-plugin';import { varlockCloudflareVitePlugin } from '@varlock/cloudflare-integration';export default defineConfig({plugins: [cloudflare(),varlockCloudflareVitePlugin(),// other plugins ...],});Any options you were passing to
cloudflare()can be passed directly tovarlockCloudflareVitePlugin()at the top level. -
Deploy with
varlock-wranglerUse
varlock-wrangler deployinstead ofwrangler deployin your deploy script:package.json {"scripts": {"dev": "vite dev","build": "vite build","deploy": "npm run build && varlock-wrangler deploy"}}If you deploy via Cloudflare Workers Builds instead of a local/CI script, override the deploy command in your Cloudflare dashboard under Settings → Build → Deploy command — see Workers Builds below.
How it works
Section titled “How it works”- In dev: Resolved vars are automatically injected into miniflare’s bindings.
- In production: Non-sensitive values are statically replaced at build time by vite.
varlock-wrangler deploysets non-sensitive values as Cloudflare vars and sensitive values as secrets.
Upgrading from @varlock/vite-integration
Section titled “Upgrading from @varlock/vite-integration”If you were previously using varlockVitePlugin() from @varlock/vite-integration with Cloudflare Workers:
- Install
@varlock/cloudflare-integration(you can remove@varlock/vite-integration— it’s included) - In
vite.config.ts, replace bothvarlockVitePlugin()andcloudflare()withvarlockCloudflareVitePlugin() - Replace
wrangler deploywithvarlock-wrangler deployin your deploy script
import { varlockVitePlugin } from '@varlock/vite-integration';import { cloudflare } from '@cloudflare/vite-plugin';import { varlockCloudflareVitePlugin } from '@varlock/cloudflare-integration';
export default defineConfig({ plugins: [ varlockVitePlugin(), cloudflare(), varlockCloudflareVitePlugin(), ],});Your secrets will no longer be bundled into the JS artifact — they’ll be stored in Cloudflare’s secret management instead.
varlock-wrangler CLI
Section titled “varlock-wrangler CLI”varlock-wrangler is a thin wrapper around wrangler. It enhances the commands below; everything else (tail, secret list, etc.) is passed through unchanged, so you can use varlock-wrangler everywhere or just for these commands.
varlock-wrangler dev
Section titled “varlock-wrangler dev”Wraps wrangler dev with automatic env injection. Resolves your environment variables, injects them into miniflare, and watches your .env files to restart wrangler when they change.
varlock-wrangler deploy / versions upload
Section titled “varlock-wrangler deploy / versions upload”Resolves your environment variables from .env.schema + .env files, then uploads non-sensitive values as Cloudflare vars (--var), sensitive values as Cloudflare secrets (--secrets-file), and includes a __VARLOCK_ENV secret containing the full resolved env graph for the varlock runtime.
varlock-wrangler types
Section titled “varlock-wrangler types”Generates Cloudflare Worker types (the Env interface) including all varlock-managed environment variables, so your env.MY_VAR access is properly typed alongside other Cloudflare bindings (KV, D1, etc.).
Log redaction and leak prevention
Section titled “Log redaction and leak prevention”Both integration approaches automatically enable log redaction (sensitive values are masked in console output) and response leak detection (responses are scanned for accidentally exposed secrets). These are enabled by default and can be disabled in your .env.schema using root decorators:
# @redactLogs=false# @preventLeaks=falseFor more details, see the root decorators reference.
Managing Multiple Environments
Section titled “Managing Multiple Environments”Varlock can load multiple environment-specific .env files (e.g., .env.development, .env.preview, .env.production) by using the @currentEnv root decorator.
The simplest approach is to use the built-in VARLOCK_ENV variable, which auto-detects the deployment environment on most CI platforms — including Cloudflare Workers Builds (via WORKERS_CI_BRANCH), Vercel, Netlify, and others. Locally it resolves to development, and during tests to test.
# @currentEnv=$VARLOCK_ENV# ---If you need more control — for example mapping specific branches to specific environments — you can define your own env-selection var instead:
# @currentEnv=$APP_ENV# ---WORKERS_CI_BRANCH=# @type=enum(development, preview, production, test)APP_ENV=remap($WORKERS_CI_BRANCH, "main", production, /.*/, preview, undefined, development)For more information, see the environments guide.
Cloudflare Workers Builds (CI/CD)
Section titled “Cloudflare Workers Builds (CI/CD)”If you deploy via Cloudflare Workers Builds, two pieces of setup are required in the dashboard — neither can be configured from a file in the repo:
-
Override the Deploy command
Under Settings → Build → Deploy command, replace the default
npx wrangler deploywith:Terminal window npx varlock-wrangler deployWithout this override, Cloudflare runs stock
wrangler deploy, which skips varlock’s env resolution and leaves your worker without its resolved vars/secrets at runtime. -
Set any secret-zero vars under Build variables
Any env vars that varlock itself needs during load — for example a 1Password service account token, a GCP key — must be set under Settings → Build → Variables and Secrets. These are made available to the build step, where
varlock-wrangler deployresolves your full env graph and uploads the result to the worker runtime as regular vars/secrets.Vars that only your worker needs at runtime (not varlock itself) don’t need to be set here — they’ll be resolved by varlock and set automatically by
varlock-wrangler deploy.
Deploying from your own CI
Section titled “Deploying from your own CI”Deploying from your own CI (GitHub Actions, GitLab CI, a self-hosted runner) instead of Cloudflare Workers Builds works the same way — and isn’t really Cloudflare-specific. The same secret-zero rule applies: any var varlock needs to resolve your secrets (a 1Password service account token, a GCP key, etc.) must be present in the job environment before varlock-wrangler deploy runs.
jobs: deploy: permissions: id-token: write # required for OIDC-backed plugins contents: read steps: - uses: actions/checkout@v4 - run: npm ci - run: npm run build - run: npx varlock-wrangler deploy env: # Only vars varlock needs to *resolve* secrets — not every worker var OP_SERVICE_ACCOUNT_TOKEN: ${{ secrets.OP_SERVICE_ACCOUNT_TOKEN }}For supported providers, varlock can authenticate with short-lived OIDC tokens from your CI instead of long-lived keys — see the OIDC workload identity guide. Run varlock load in an earlier step to fail fast on schema errors without exposing values.
Multi-worker and auxiliary Workers
Section titled “Multi-worker and auxiliary Workers”Cloudflare supports running multiple Workers in one dev session — a primary Worker plus auxiliary Workers reachable via service bindings. The Vite plugin exposes this through auxiliaryWorkers in vite.config.ts.
When things go wrong
Section titled “When things go wrong”Cannot resolve 'node:...' at worker startup
Section titled “Cannot resolve 'node:...' at worker startup”Your worker is missing the Node.js compatibility layer. Add nodejs_compat to compatibility_flags — see the nodejs_compat caution near the top of this page.
.dev.vars conflicts with the Vite plugin
Section titled “.dev.vars conflicts with the Vite plugin”Delete .dev.vars and .dev.vars.<environment> files when using the Vite plugin or varlock-wrangler dev. Varlock owns env injection; leftover Wrangler env files cause hard errors.
Vars or secrets missing after deploy
Section titled “Vars or secrets missing after deploy”- Confirm you deploy with
varlock-wrangler deploy, not stockwrangler deploy— especially on Workers Builds - Check that secret-zero CI vars are set for any plugin-backed items varlock must resolve at deploy time
- Remember that
varlock-wrangler deployreplaces all Cloudflare vars and secrets with schema-defined ones — manually added dashboard secrets not in your schema are removed
Non-wrangler deploy tools (Alchemy, SST, Pulumi)
Section titled “Non-wrangler deploy tools (Alchemy, SST, Pulumi)”If you deploy Workers with IaC tools other than wrangler — Alchemy, SST, Pulumi, Terraform, etc. — you can still use varlock for fail-fast validation and secret resolution via varlock run, which injects resolved values into process.env for the deploy tool to read.
What you cannot get today without varlock-wrangler: the in-worker runtime layer (@varlock/cloudflare-integration/init) that provides console redaction and response leak detection. That layer reads a __VARLOCK_ENV binding that only varlock-wrangler produces today.
A public API to build __VARLOCK_ENV bindings for non-wrangler deploy tools is planned but not available yet. Until then, teams on Alchemy/SST/Pulumi typically rely on varlock for validation + env injection at deploy time and skip the in-worker runtime protections.
Varlock vs Cloudflare’s built-in env management
Section titled “Varlock vs Cloudflare’s built-in env management”Cloudflare Workers have built-in support for vars and secrets, but managing them across environments quickly becomes painful. Here’s what Varlock adds:
- Single source of truth — Instead of scattering config across the Cloudflare dashboard,
wrangler.toml,.dev.vars, and your code, everything is defined in one.env.schemafile that works across local dev, preview, and production. - Validation before deploy — Cloudflare only has basic required var validation. Varlock catches missing vars, wrong types, and invalid values before your worker starts — not when it crashes at runtime.
- Pull secrets from vaults — Instead of manually running
wrangler secret putor copy-pasting values in the dashboard, pull secrets directly from 1Password, AWS Secrets Manager, HashiCorp Vault, and more. - Log redaction & leak prevention — Cloudflare doesn’t prevent you from accidentally
console.log-ing a secret or including one in a response body. Varlock automatically redacts sensitive values in logs and scans outgoing responses for leaked secrets. - Simpler multi-environment setup — Wrangler’s
[env.staging]/[env.production]blocks duplicate config and don’t support.envfile overrides. Varlock uses familiar.env.production/.env.previewfiles with a single schema, and auto-detects the current environment in CI. - Local dev that matches production —
.dev.varsis completely disconnected from your production secrets. With Varlock, local dev resolves from the same schema and same secret sources, so there’s no drift between environments. - AI-safe by design — Your
.env.schemagives AI coding tools full context on your config (names, types, descriptions) without ever exposing secret values.