Description
varlock audit compares keys defined in .env.schema against environment-variable references found in source code. Today it works well for direct process.env.VAR usage and ENV.VAR from varlock/env, but it reports false positives ("unused in schema") for several common deployment patterns — especially Cloudflare Workers deployed via IaC tools other than varlock-wrangler.
In a monorepo using Alchemy for Cloudflare Workers + D1 + Astro:
- Deploy time: secrets and vars are declared as Worker bindings via
alchemy.env.VAR / alchemy.secret.env.VAR in alchemy.run.ts. Alchemy reads resolved values from process.env (injected by varlock run --), but audit does not scan those binding declarations.
- Worker runtime: application code reads
env.VAR from cloudflare:workers (sometimes via a thin package re-export). Audit does not trace property access on that import.
- Astro marketing site: public vars are consumed via
astro:env/client imports, not process.env.
Running varlock audit from the infra package entry point flags every binding key (e.g. BETTER_AUTH_SECRET, PUBLIC_SERVER_URL, ALCHEMY_PASSWORD) as unused, even though they are actively used.
We currently work around Alchemy-only keys with # @auditIgnore per the audit hint ("If this is used by an external tool…"), but Worker and Astro keys are genuinely referenced in code — audit just cannot see them yet.
Motivation
Accurate varlock audit is important for:
- Solo developers using AI coding agents (detecting drift between schema and code)
- Monorepos where schema lives in
packages/infra but consumption is spread across apps/packages
- Alchemy / better-t-stack adopters who use
varlock run -- <deploy> without varlock-wrangler
Without improved detection, audit either fails noisily or teams blanket @auditIgnore, which defeats the purpose.
Proposed Solution
Extend varlock audit (and/or document first-class patterns) for:
cloudflare:workers env access — detect env.VAR, destructuring from cloudflare:workers, and common re-export wrappers (e.g. @talkiva/env/server).
- IaC binding declarations — optional detectors for known patterns such as
alchemy.env.VAR, alchemy.secret.env.VAR, and potentially SST/Pulumi equivalents.
- Framework env modules — e.g.
import { VAR } from "astro:env/client" mapped back to schema keys.
- Monorepo-aware scanning — when
varlock.loadPath spans multiple packages, default audit scan roots could include sibling app/package directories referenced by the schema entry point.
If full static analysis is out of scope for some patterns, documenting recommended @auditIgnore categories (external CLI tools vs. runtime bindings) would still help.
Alternatives
@auditIgnore on all binding keys — works today but removes audit coverage for real drift.
- Wait for
@varlock/cloudflare-integration + varlock-wrangler only — does not help Alchemy/SST/Pulumi deploy paths where Worker code still uses cloudflare:workers without migrating imports to varlock/env.
- Custom audit scripts — possible but duplicates logic Varlock already owns.
Additional Information
Example binding declaration audit should recognize:
export const server = await Worker("server", {
bindings: {
BETTER_AUTH_SECRET: alchemy.secret.env.BETTER_AUTH_SECRET!,
CORS_ORIGIN: alchemy.env.CORS_ORIGIN!,
},
});
Example runtime usage audit should recognize:
import { env } from "cloudflare:workers";
// or: import { env } from "@talkiva/env/server";
const origin = env.CORS_ORIGIN;
Description
varlock auditcompares keys defined in.env.schemaagainst environment-variable references found in source code. Today it works well for directprocess.env.VARusage andENV.VARfromvarlock/env, but it reports false positives ("unused in schema") for several common deployment patterns — especially Cloudflare Workers deployed via IaC tools other thanvarlock-wrangler.In a monorepo using Alchemy for Cloudflare Workers + D1 + Astro:
alchemy.env.VAR/alchemy.secret.env.VARinalchemy.run.ts. Alchemy reads resolved values fromprocess.env(injected byvarlock run --), but audit does not scan those binding declarations.env.VARfromcloudflare:workers(sometimes via a thin package re-export). Audit does not trace property access on that import.astro:env/clientimports, notprocess.env.Running
varlock auditfrom the infra package entry point flags every binding key (e.g.BETTER_AUTH_SECRET,PUBLIC_SERVER_URL,ALCHEMY_PASSWORD) as unused, even though they are actively used.We currently work around Alchemy-only keys with
# @auditIgnoreper the audit hint ("If this is used by an external tool…"), but Worker and Astro keys are genuinely referenced in code — audit just cannot see them yet.Motivation
Accurate
varlock auditis important for:packages/infrabut consumption is spread across apps/packagesvarlock run -- <deploy>withoutvarlock-wranglerWithout improved detection, audit either fails noisily or teams blanket
@auditIgnore, which defeats the purpose.Proposed Solution
Extend
varlock audit(and/or document first-class patterns) for:cloudflare:workersenv access — detectenv.VAR, destructuring fromcloudflare:workers, and common re-export wrappers (e.g.@talkiva/env/server).alchemy.env.VAR,alchemy.secret.env.VAR, and potentially SST/Pulumi equivalents.import { VAR } from "astro:env/client"mapped back to schema keys.varlock.loadPathspans multiple packages, default audit scan roots could include sibling app/package directories referenced by the schema entry point.If full static analysis is out of scope for some patterns, documenting recommended
@auditIgnorecategories (external CLI tools vs. runtime bindings) would still help.Alternatives
@auditIgnoreon all binding keys — works today but removes audit coverage for real drift.@varlock/cloudflare-integration+varlock-wrangleronly — does not help Alchemy/SST/Pulumi deploy paths where Worker code still usescloudflare:workerswithout migrating imports tovarlock/env.Additional Information
__VARLOCK_ENVfor non-wrangler deploy tools.varlock run -- alchemy dev; schema atpackages/infra/.env.schemaimportingapps/server/.env.schema; audit run frompackages/infrawith explicit scan paths still reports all binding keys unused.Example binding declaration audit should recognize:
Example runtime usage audit should recognize: