Guides

Vallkey on Vercel: Next.js, Node.js, Bun, Python and Ruby

Step by step for each runtime Vercel runs, tested on real deployments: where the hook goes, how to check it works, and how to fix a failed build.

Updated October 2026

Tested on Vercel, October 29, 2026 · Next.js 16 · Node.js 24 · Bun 1.3 · Python 3.12 · Ruby 3.3

Vallkey's startup hook sends every request that carries a ghost key to Vallkey, which checks it against your rules and swaps in the real key. Requests without a ghost key are left alone, and your code calls the API exactly as the provider's docs show. This guide sets it up on Vercel for each runtime Vercel runs, the way we tested it on real deployments.

Before you start

  • A ghost key from the dashboard, or from npx vallkey init in your project.
  • In Vercel, under Project → Settings → Environment Variables, put the ghost key where the real key was, under the same name, such as OPENAI_API_KEY. Then the real key is no longer in Vercel at all.
  • Never in a variable that starts with NEXT_PUBLIC_: those are copied into the browser.

Do not put NODE_OPTIONS or RUBYOPT in Vercel's variables

Vercel uses your project's variables while it builds your app too. With NODE_OPTIONS=--require vallkey/auto there, every Node.js process in the build loads the hook before it is installed, and the deploy stops with Command "npm install" exited with 1. RUBYOPT breaks Ruby builds the same way. On Vercel, the hook is loaded from your code instead, as below. Only Python uses a variable, which is safe.

Set it up

Choose what your project runs. Each tab is complete on its own.

Tested: Next.js 16.4 on Node.js 24, fetch and node:https

  1. Install the package

    Terminal
    npm install vallkey
  2. Add the instrumentation file

    Next.js runs register() once when a server starts, on your own machine and on Vercel. npx vallkey hook writes the file for you: instrumentation.ts, or .js in a JavaScript project, inside src/ if your app lives there.

    Terminal
    npx vallkey hook --yes
    instrumentation.ts
    export async function register() {  // Sends server requests that carry a ghost key to Vallkey.  if (process.env.NEXT_RUNTIME === 'nodejs') {    await import('vallkey/auto');  }}

    Already have an instrumentation file? Add the if block inside your register(). The check on NEXT_RUNTIME matters: the hook is for the Node.js runtime only.

  3. Deploy

    Push, or run vercel deploy --prod. Nothing else changes in your code.

Edge routes are not covered

Routes with export const runtime = 'edge' do not load the hook: in our test the provider received the ghost key and refused it. For those, set the SDK's API address to Vallkey instead, such as baseURL: 'https://api.vallkey.com/v1' for OpenAI. Each key's Connect tab in the dashboard has the exact line.

Check that it works

Every answer that went through Vallkey carries an x-guard-request-id header. With one real request from your deployed app, the CLI confirms it was that request, through that key:

Terminal
# 1. Call your deployed app once, then copy the x-guard-request-id#    header from the response Vallkey sent back to your function.# 2. Check that exact request:npx vallkey verify KEY_ID --request-id REQUEST_ID ✓ Verified  This exact request went through Vallkey and got a successful answer.
  • On a test key, make a harmless request your rules block, and check it with --expect denied. Seeing it refused proves your rules apply to the deployed app.
  • npx vallkey status lists every place the key is used from. A working Vercel deployment shows up by itself, such as Vercel · Node.js 24.21 · production. Name it with VALLKEY_ENV=production in the project's variables.

If something is off

The build fails at npm install, or at gem install bundler

NODE_OPTIONS or RUBYOPT is set in Vercel's variables. Remove it there, load the hook in code as above, and deploy again.

The provider says the API key is invalid

The request went straight to the provider with the ghost key, which only Vallkey understands. The hook is not loaded in that function: check that its first line loads vallkey/auto, that a Next.js route is not on the Edge runtime, and for Python that VALLKEY_AUTO=1 is set for that environment (Production, Preview).

No x-guard-request-id header

Same cause: that request did not go through Vallkey. Add VALLKEY_DEBUG=1 to the variables to log each request the hook sends to Vallkey (never the key), then look at the function's logs.

Verify says the request was blocked, or not found

Blocked means it reached Vallkey and your rules refused it: open the key's Activity tab for the reason. Not found means it is older than five minutes, or belongs to another key: make a new request and verify again.

More

Deploy with a key that cannot be misused

Your functions call APIs with a ghost key, inside your rules and budget. The real key never reaches Vercel. Free plan, no card needed.