varsvars

Next.js

Using vars with Next.js — App Router, Pages Router, and API routes.

Setup

{
  "scripts": {
    "dev": "vars run --env dev -- next dev",
    "build": "vars run --env prod -- next build"
  }
}

Server Components & API Routes

Import vars directly — they run on the server where process.env is available:

import { vars } from '#vars'

export async function GET() {
  return Response.json({ db: vars.DATABASE_URL.unwrap() })
}

Server-side on Vercel (or any serverless target)

For production deployments to Vercel, Netlify, or other serverless runtimes, regenerate with the serverless platform so ciphertexts ship in the bundle and decrypt at runtime from a single VARS_KEY:

vars gen config.vars --platform serverless

Then switch to the async getVars(env) entry point:

import { getVars } from '#vars'

export async function GET() {
  const vars = await getVars(process.env)
  return Response.json({ db: vars.DATABASE_URL.unwrap() })
}

Set only VARS_KEY + VARS_ENV in the platform dashboard — no per-secret entries. See the Vercel guide for the full deploy flow.

Keep the default (non-serverless) build for local dev and for purely-static exports where runtime decryption isn't needed.

Client Components

Next.js automatically inlines NEXT_PUBLIC_* variables from process.env into client bundles at build time. No extra config needed.

Mark client-safe variables with public and prefix with NEXT_PUBLIC_:

public NEXT_PUBLIC_API_URL : z.string().url() {
  dev  = "http://localhost:3000/api"
  prod = "https://api.example.com"
}

public NEXT_PUBLIC_POSTHOG_KEY : z.string() {
  dev  = "phc_dev_placeholder"
  prod = "phc_live_real_key"
}

These are available in both server and client code.

Example config.vars

env(dev, staging, prod)

# Server-only secrets
DATABASE_URL : z.string().url() {
  dev     = "postgres://localhost:5432/myapp"
  staging = "postgres://staging.db:5432/myapp"
  prod    = "postgres://prod.db:5432/myapp"
}

NEXTAUTH_SECRET : z.string().min(32) {
  dev     = "dev-secret-at-least-32-characters-long!"
  staging = "stg-secret-at-least-32-characters-long!"
  prod    = "prod-secret-very-secure-value-here-64ch"
}

# Client-safe (inlined into browser bundle by Next.js)
public NEXT_PUBLIC_API_URL : z.string().url() {
  dev     = "http://localhost:3000/api"
  staging = "https://staging-api.example.com"
  prod    = "https://api.example.com"
}

CI/CD

# GitHub Actions
env:
  VARS_KEY: ${{ secrets.VARS_KEY }}

steps:
  - run: vars run --env prod -- next build