Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.capy.sc/llms.txt

Use this file to discover all available pages before exploring further.

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:
    bun add -D @capy/cli
    
  2. Wrap your build (and dev) in package.json:
    {
      "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:
    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 @capy/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

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.
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 for the exact construction.

Local development

Same wrapper, different command:
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 for the end-to-end local loop.