Skip to main content

Deploying

Deploying on Vercel with Neon, white-labelling the pages, running in a monolith, and sending email.

On Vercel, with Neon

  1. Connect Neon to the project. It sets DATABASE_URL, which is used when FG_ID_DATABASE_URL is not, and DATABASE_URL_UNPOOLED, which migrations connect through.
  2. Build with pnpm check-env && pnpm build && pnpm migrate — or, in a distribution, its own pnpm build, which runs all three. pnpm check-env refuses to deploy without what this app needs, naming each variable; pnpm migrate is fg-dist migrate --build: a production build migrates, a preview build only with FG_MIGRATE=build (once each preview has its own database), and a build on Vercel with no database fails rather than deploying one that cannot start.
  3. Set FG_ID_SMTP_URL, and a group of FG_ID_SERVICE_* per service — in a distribution, pnpm dist env setup adds them, generating the secrets. FG_ID_URL, FG_ID_NAME and FG_ID_EMAIL_FROM are optional: production is served at the project's production domain without them.

Keys need nothing: they are made on first use. Preview deployments use their own VERCEL_URL as the issuer unless FG_ID_URL says otherwise.

White-labelling

FG_ID_URL is the domain everything follows from: the OIDC issuer, the passkey relying party, the links in emails. FG_ID_NAME is the name on every page, email and passkey prompt. The API's group, id.fairgarden.org, names the software rather than the deployment, so it stays the same.

In a monolith

Mounted at /id, the issuer becomes FG_ID_URL plus /id, and every page, API route and OIDC endpoint moves with it. The monolith's build migrates this app along with every other it mounts, into the database this app would use: FG_ID_DATABASE_URL, or the DATABASE_URL they share. The monolith must list oidc-provider in its own serverExternalPackages: oidc-provider names its models by their class names, which a bundle would minify.

Email

Sign-in emails go over SMTP, FG_ID_SMTP_URL. Without it, a local host uses the mock mailbox, and a public host sends nothing — anyone who could read the mock mailbox could sign in as anyone. FG_ID_MOCK_EMAIL=true forces it for a demo.