MainSDK
Search⌘K
How-to

Deploy on Vercel

Ship a MainSDK app on Vercel with secrets as references, a production overlay, mainsdk check on every pull request and a second network wall.

Updated 2026-10-28

Deploy Pinecart, a Next.js app on MainSDK, to Vercel with no key in your code and a check that blocks unsafe changes before they ship. MainSDK is a library, not a host, so Vercel still deploys it; Ship with deploy config writes vercel.json from main.yaml. This guide adds secrets as references, a production overlay, mainsdk check in CI and a second network wall.

Before you start:

  • A Next.js App Router app with a main.yaml (see Adopt an existing app if you don't have one yet).
  • A Vercel project linked to the repo, and the Vercel CLI.
  • npx mainsdk check passing locally (see Your first check).

1. Keep keys as references

main.yaml never holds a key. It names one with secret:NAME, and the secrets driver resolves it on the server at startup. On Vercel, the env driver reads Vercel environment variables.

main.yaml
schema: 1
project: prj_01JC8Q4W7ZK3M5N8P2R6T9V0XY
baseline: main27
targets: { web: { framework: nextjs } }
secrets:
  driver: env                       # reads Vercel environment variables
auth:
  driver: github
db:
  driver: postgres
  regions: { us: secret:DATABASE_URL_US, eu: secret:DATABASE_URL_EU }
ai:
  driver: bedrock                   # IAM role, no key in code
config:
  driver: vercel-global-config      # settings change without a deploy
  schema: ./config.schema.json
jobs:
  driver: vercel-queues
overlays: { order: [market, segment, env] }

Add the values in Vercel, per environment:

bash
vercel env add DATABASE_URL_US production
vercel env add DATABASE_URL_EU production

If your keys live in Vault, AWS, Google Cloud, Azure, Doppler or Infisical, change secrets.driver and keep the same secret: references. See Secrets.

2. Add a production overlay

Put production-only values in main.env.prod.yaml. Environment resolves at build time, so the production build carries only that layer. See main.yaml and overlays.

main.env.prod.yaml
network:
  default: deny
  allow: ["*.pinecart.dev"]

3. Check the production config

mainsdk check --env prod refuses any interface that still resolves to a local driver. If an earlier setup left secrets.driver: local, you see:

bash
npx mainsdk check --env prod
text
mainsdk check · pinecart · env prod · Main 27
 config  1 finding
  MAIN-CHECK-0026  critical  main.yaml
  fix: local driver in production: secrets. Set secrets.driver to env or a key service.
 secrets
 policy
 network
 data
1 gate failed · exit 1

Set secrets.driver: env as in step 1 and run it again until it ends with all gates passed · exit 0.

4. Check every pull request

Run the check in CI on each pull request, before Vercel promotes anything. The check is free and runs on your own runner.

.github/workflows/mainsdk.yml
name: mainsdk
on: [pull_request]
jobs:
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 22 }
      - run: npm ci
      - run: npx mainsdk check --env prod --sarif mainsdk.sarif
      - uses: github/codeql-action/upload-sarif@v3
        if: always()
        with: { sarif_file: mainsdk.sarif }

SARIF puts each finding inline on the pull request. Make the job a required status check, so a failed gate blocks the merge and the deploy that follows it. Exit codes are explained in The check.

5. Add a second network wall

network.allow is enforced in the SDK for every outbound call. Export the same list as a firewall rule for an independent wall. The CLI writes Kubernetes rules with --to k8s and AWS security-group rules with --to aws-sg. Vercel and Cloudflare exports are planned, so on Vercel the SDK check is the wall for now:

bash
npx mainsdk network export --to k8s

See Network permissions.

6. Verify the deploy

Open a pull request. The mainsdk job runs, and a red check blocks the merge. Once it is green and merged, Vercel deploys as usual. To confirm nothing secret reached the browser, run the check against the production build output:

bash
npx mainsdk check --env prod

A secret value in a client chunk fails with MAIN-SECRET-0004 and names the chunk.

Optional: OIDC instead of a stored key

When you send telemetry to MainSDK Cloud, each environment normally needs an ingest key in MAINSDK_KEY (msk_live_… for prod, msk_test_… for dev and stage). On Vercel and in GitHub Actions the platform's OIDC token for the linked project or repo is accepted in place of the key.

main.yaml
telemetry:
  to: [terminal, mainsdk]
  sample: 0.2

The Vercel-side setup for that OIDC trust (which audience and issuer to register) is not decided yet. Until it is, store MAINSDK_KEY as a sensitive Vercel variable.

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet