1. Documentation
  2. Deploying
  3. Vercel
ReadmenpmGitHub
  • Introduction
  • Quickstart
  • Configuration file
  • Monitors
  • Checks and scheduling
  • Notifications
  • Incidents and maintenance
  • Subscribers
  • Metrics and badges
  • Identity and appearance
  • Telemetry
  • The check run
  • Uptime and history
  • Automatic incidents
  • Notification delivery
  • Public subscriptions
  • StatusPage component
  • Themes
  • UI primitives
  • Colour mode
  • React Router
  • Next.js
  • Astro
  • SQLite
  • Cloudflare D1
  • PostgreSQL
  • Schema and migrations
  • Cloudflare Workers
  • Vercel
  • Self-hosting
  • API overview
  • Status endpoints
  • Incident and maintenance endpoints
  • Subscriber endpoints
  • Badges, feeds and metrics
  • Admin endpoints
  • CLI commands
  • Package exports
  • Security
  • Troubleshooting

Vercel

Deploy with PostgreSQL and authenticated Vercel Cron routes.

A Vercel deployment pairs PostgreSQL with Vercel Cron. The overlay adds one cron route per job, guarded by a bearer secret, and a vercel.json that schedules all three.

bash
bun create @heyo-sh/heyo-status my-status-page \  --template next --deployment vercel --database postgres

Cron routes

app/api/cron/[task]/route.ts
import { vercelCronHandler, type VercelCronTask } from "@heyo-sh/heyo-status/deployments/vercel";import { statusPage } from "../../../../heyo-status.config";const tasks = new Set<VercelCronTask>(["checks", "summarize", "cleanup"]);export async function GET(request: Request, { params }: { params: Promise<{ task: string }> }) {  const { task } = await params;  if (!tasks.has(task as VercelCronTask)) {    return Response.json({ error: "Not found" }, { status: 404 });  }  return vercelCronHandler(statusPage, task as VercelCronTask, {    secret: process.env.CRON_SECRET,  })(request);}
vercel.json
{  "crons": [    { "path": "/api/cron/checks", "schedule": "*/5 * * * *" },    { "path": "/api/cron/summarize", "schedule": "10 0 * * *" },    { "path": "/api/cron/cleanup", "schedule": "0 3 * * *" }  ]}

The schedules must match checks.interval, checks.summaryCron and checks.cleanupCron in the configuration file.

Cron routes are closed without CRON_SECRET

Without a secret the handler answers 503. That is intentional: cleanup deletes history and checks sends outbound requests to every configured monitor, so an unauthenticated trigger is both destructive and abusable.

Vercel sends Authorization: Bearer $CRON_SECRET with scheduled invocations. The comparison is constant-time.

Responses

TaskResponse
checks{ "ok": true, "task": "checks", "results": 6 }
summarize{ "ok": true, "task": "summarize", "result": { … } }
cleanup{ "ok": true, "task": "cleanup" }
bash
curl -H "authorization: Bearer $CRON_SECRET" https://status.acme.com/api/cron/checks

Deploy

  1. 1

    Provision PostgreSQL

    Vercel Postgres, Neon, Supabase or any managed instance. Prefer a pooled connection string for serverless functions.

  2. 2

    Set environment variables

    VariablePurpose
    DATABASE_URLPostgreSQL connection string.
    CRON_SECRETBearer secret for the cron routes.
    HEYO_STATUS_API_TOKENBearer token for /admin/*.

    Set them for Production, Preview and Development as needed.

  3. 3

    Migrate

    bash
    DATABASE_URL=… bun run db:migrate

    Run it once per environment before the first deploy, and again after upgrading the package. Request handlers never migrate automatically.

  4. 4

    Deploy and verify

    bash
    vercel deploy --prodcurl https://status.acme.com/api/heyo-status/healthzcurl -H "authorization: Bearer $CRON_SECRET" https://status.acme.com/api/cron/checks

Notes for serverless

  • The function filesystem is ephemeral and read-only, which is why SQLite is not offered for this target.
  • The snapshot cache lives inside one instance. It still removes repeated reads within an invocation burst.
  • Keep the connection pool small and pooled; a status page issues only a handful of queries per request.
  • Cron frequency is bounded by your Vercel plan, regardless of what the configuration says.
  • tcp and ssl monitors work on Vercel's Node runtime — use Node.js 20.19+ so node:net and node:tls resolve.

Other frameworks

The same overlay exists for each template:

FrameworkCron route
Next.jsapp/api/cron/[task]/route.ts
React Routersrc/routes/api.cron.$task.ts
Astrosrc/pages/api/cron/[task].ts

Related

  • PostgreSQL
  • Scheduling
  • Security checklist
Cloudflare Workers< PreviousSelf-hostingNext >

Powered by heyo

On this page

Cron routesResponsesDeployNotes for serverlessOther frameworks