Penv Cloud
Start free
Docs
Guidesince cloud@2026-09-10

Deploy to Vercel

Two Vercel paths: your build authenticates to us as its project via OIDC and runs penv, or we export values into the project's environment for functions.

DeployingPath
A build step, or anything started by a commandOIDC identity, then penv run
A tool that reads a file at build timeOIDC identity, then penv pull
A function or an edge handlerExport sync

OIDC identity

Bind the trust in our console under Machine Identities, then Connect a Platform. Fields, trust contents, and the console snippet: connect Vercel. Audience rule: values in a CI build.

Set Project Settings, Security, Issuer Mode to Team before connecting. Global issuer mode shares https://oidc.vercel.com across every Vercel team, so only the subject separates workspaces and a mistyped slug becomes cross-tenant rather than broken.

Trust factValue
ProjectThe name as Vercel lists it. A deployment URL does not match; a rename needs a new trust.
Environmentproduction (default) or preview. development is excluded: its token carries the person who ran it.
Exchange responseWe answer 201 with a credential that lives 15 minutes, capped by the trust's expiry.

A request handler can mint and exchange the token (snippet on connect Vercel), but penv ships no request-time read library; a function that only needs settings uses the export sync.

Build

scripts/penv-build.mjs
import { spawnSync } from 'node:child_process';
import { getVercelOidcToken } from '@vercel/oidc';

const T = await getVercelOidcToken({ audience: '<ORG_ID>' });
const r = await fetch('https://penv.cloud/api/v1/auth/oidc', {
  method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ token: T }),
});
const { credential } = await r.json();

const build = spawnSync('penv', ['run', '--', 'next', 'build'], {
  stdio: 'inherit',
  env: { ...process.env, PENV_TOKEN: credential },
});
process.exit(build.status ?? 1);

Set this file as your vercel-build script. It starts the build because a credential in one process's process.env does not reach a sibling command. Since 1.0.0-beta.2, penv run scans .next/static and other client output after the build and exits 3 when a secret landed there.

Vercel's build image has no penv: install it in an earlier step and put $HOME/.penv/bin on PATH (install the CLI). Replace penv run with penv pull for a file-only tool.

Vercel documents the custom audience only through @vercel/oidc, with no HTTP form. A non-JavaScript build mints the token in JavaScript and passes the credential into that command as PENV_TOKEN.

Export sync

Connect Vercel under Integrations (integrations) with your token from https://vercel.com/account/settings/tokens, plus the team_ id on a team account. Connection fields, mapping fields (project, deployments, Git branch, custom environment), and permission probes: Vercel integration. Write policies and dry runs: how syncs work.

Vercel binds variables at build time. A changed value reaches traffic on the next deploy; penv run picks up a rotated value on restart.

Use the prune policy only where we are the sole writer to the project.

Setup

Set Issuer Mode to Team in Project Settings, Security.

Connect Vercel under Connect a Platform with the team slug and project (connect Vercel).

Add scripts/penv-build.mjs as the vercel-build script, with the workspace id as audience.

For functions, connect Vercel under Integrations, map the environment, and dry run before applying.

Redeploy. A synced value does not reach a deployment already built.