From f7cd4943cae05dc4045239a767c50ab8b86bf7be Mon Sep 17 00:00:00 2001 From: Theo Ephraim Date: Thu, 23 Apr 2026 00:14:04 -0700 Subject: [PATCH] fix(nextjs): bundle varlock and skip CLI exec at runtime on serverless MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two issues caused "Cannot find module 'varlock'" and "Unable to find varlock executable" errors on Vercel with recent Next.js versions: 1. Vercel's builder now always uses the bundled server path, which inlines @next/env so @vercel/nft no longer traces its dependencies. Fix: split tsup config so next-env-compat bundles varlock modules directly (noExternal), eliminating external require('varlock') calls. 2. The varlock CLI binary is not available at runtime on serverless platforms. Fix: call execSyncVarlock with exitOnError:false and handle errors in loadEnvConfig's catch block — when the binary is not found in production, defer to the init bundle injected into the webpack/turbopack runtime. Also removes stale exports (varlock-env-inline, edge-env). Fixes #584 --- .bumpy/fix-nextjs-vercel-584.md | 5 +++++ .../integrations/nextjs/src/next-env-compat.ts | 15 +++++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 .bumpy/fix-nextjs-vercel-584.md diff --git a/.bumpy/fix-nextjs-vercel-584.md b/.bumpy/fix-nextjs-vercel-584.md new file mode 100644 index 00000000..c92aebbf --- /dev/null +++ b/.bumpy/fix-nextjs-vercel-584.md @@ -0,0 +1,5 @@ +--- +"@varlock/nextjs-integration": patch +--- + +bundle varlock into next-env-compat and skip CLI exec at runtime on serverless platforms diff --git a/packages/integrations/nextjs/src/next-env-compat.ts b/packages/integrations/nextjs/src/next-env-compat.ts index 63d7049a..0690688e 100644 --- a/packages/integrations/nextjs/src/next-env-compat.ts +++ b/packages/integrations/nextjs/src/next-env-compat.ts @@ -329,9 +329,9 @@ export function loadEnvConfig( const cleanEnv = { ...initialEnv }; delete cleanEnv.DEBUG_VARLOCK; const varlockLoadedEnvStr = execSyncVarlock(`load --format json-full --env ${envFromNextCommand}`, { - showLogsOnError: true, - // Never use exitOnError here — we handle all error cases in the catch block - // below, including the "binary not found" case on serverless platforms. + // We handle all error display and exit logic ourselves in the catch block + // so we can silently defer on serverless platforms where the binary is missing. + showLogsOnError: false, exitOnError: false, env: cleanEnv as any, }); @@ -362,10 +362,13 @@ export function loadEnvConfig( process.exit(1); } - // showLogsOnError already printed the formatted CLI output above, - // so we only add a short note here (err.message duplicates stderr) - // eslint-disable-next-line no-console + // For real errors (validation failures, etc.) show the CLI output + /* eslint-disable no-console */ + const errAny = err as any; + if (errAny.stdout) console.log(errAny.stdout.toString()); + if (errAny.stderr) console.error(errAny.stderr.toString()); console.error('[varlock] ⚠️ failed to load env — see error above'); + /* eslint-enable no-console */ // In a build, we want to fail hard so broken env doesn't get deployed if (!dev) {