> ## Documentation Index
> Fetch the complete documentation index at: https://capy.sc/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Vercel + Next.js Environment Variables (Encrypted)

> Deploy Next.js to Vercel with Capy-encrypted secrets. Build-time env inlining for static pages, no plaintext in Vercel settings, zero changes to next.config.js.

Vercel's build step runs in Node, regardless of whether your deployed functions run on Node or Edge. That means you can `capy run -- next build` during build, and Next.js inlines the decrypted values into the output bundle as string literals. Request-time functions read the literals - no runtime decryption, no service hop, nothing to load.

## Setup (once per project)

1. **Add Capy's CLI as a dep** so Vercel installs it during build:

   ```bash theme={null}
   bun add -D @capysc/cli
   ```

2. **Wrap your build (and dev) in `package.json`:**

   ```json theme={null}
   {
     "scripts": {
       "dev": "capy run -- next dev",
       "build": "capy run -- next build"
     }
   }
   ```

3. **Point `next.config.js` at the generated env map.** `capy run` emits `.capy/next-env.js` during build, containing every secret name it decrypted from `SECRETS_BLOB`. Import it once:

   ```js theme={null}
   const capyEnv = require(
     "./.capy/next-env"
   );

   module.exports = {
     env: capyEnv,
   };
   ```

   That's it - no hand-maintained list. Add a secret to Capy, redeploy, Next picks it up automatically.

4. **Run `capy deploy`** and pick Vercel. Capy prints two env vars - `SECRETS_BLOB` and `PROJECT_KEY` - and the setup page shows you the exact values. Paste them into **Settings → Environment Variables** in the Vercel dashboard (or `vercel env add SECRETS_BLOB production` / `vercel env add PROJECT_KEY production`). Repeat for Preview and Development if you want Capy to decrypt there too.

5. **Deploy.** Vercel clones your branch, installs `@capysc/cli`, runs `capy run -- next build`, and the resulting bundle has your runtime values baked in. Both Node and Edge routes read them normally.

Vercel builds each git branch independently. Production, staging, and PR preview branches each get whichever secrets you've pasted into their respective Vercel environments with no manual sync step.

## What happens during the build

<Frame>
  <img src="https://mintcdn.com/capy-c95c79c0/N7qpVCkQCaY3Lo-w/images/diagrams/11-vercel-build.svg?fit=max&auto=format&n=N7qpVCkQCaY3Lo-w&q=85&s=5f6e9971e08576a6db68c1b0021ea7bb" className="block dark:hidden" alt="Vercel env holds SECRETS_BLOB and PROJECT_KEY. During the build, capy run parses SECRETS_BLOB, posts the outer blob to Capy, gets a service_key back, combines it with PROJECT_KEY via HKDF, decrypts the env vars, writes .capy/next-env.js, then spawns next build with plaintext process.env. Next inlines every listed variable into the deployed bundle as a string literal." width="593" height="368" data-path="images/diagrams/11-vercel-build.svg" />

  <img src="https://mintcdn.com/capy-c95c79c0/N7qpVCkQCaY3Lo-w/images/diagrams/11-vercel-build-dark.svg?fit=max&auto=format&n=N7qpVCkQCaY3Lo-w&q=85&s=4697cbd11a752a89d19941f1ca6e06de" className="hidden dark:block" alt="Vercel env holds SECRETS_BLOB and PROJECT_KEY. During the build, capy run parses SECRETS_BLOB, posts the outer blob to Capy, gets a service_key back, combines it with PROJECT_KEY via HKDF, decrypts the env vars, writes .capy/next-env.js, then spawns next build with plaintext process.env. Next inlines every listed variable into the deployed bundle as a string literal." width="593" height="368" data-path="images/diagrams/11-vercel-build-dark.svg" />
</Frame>

**Why this beats runtime decryption:**

* Runtime functions do zero crypto - they read already-inlined constants.
* Edge / Node / any framework - the mechanism is just `process.env`.
* One service call per build, not per request.
* Revocation = redeploy. Intentional; no caches to chase.

`PROJECT_KEY` never leaves the build step. Only the outer-wrapped portion of `SECRETS_BLOB` travels to Capy's service; the service verifies the deploy token isn't revoked and returns a one-way derived `service_key`. That's combined locally with `PROJECT_KEY` to derive the key that actually opens the encrypted env. See [Cryptography → Deploying](/internals/cryptography#deploying-to-production) for the exact construction.

## Local development

Same wrapper, different command:

```bash theme={null}
capy run -- next dev
```

`capy run` resolves the project key from your local keyring (populated by `capy` sync) - no `SECRETS_BLOB` / `PROJECT_KEY` required locally. See [Getting started → Next.js](/getting-started/nextjs) for the end-to-end local loop.
