← Blog

Monitor your SaaS on Vercel — health URL + status page

Vercel makes shipping a Next.js frontend trivial. Production still needs a health endpoint the world can ping and an external monitor that is not your browser tab. This walkthrough uses the App Router (app/api/health/route.ts), deploys to a Vercel URL, and registers a StillOnline check plus auto status page.

Generic steps live in Health check quickstart. Railway users: Railway guide.

1. Add app/api/health/route.ts

Keep the handler dynamic if you touch the database — static optimization can cache a stale “ok”.

import { NextResponse } from "next/server";

export const dynamic = "force-dynamic";

export async function GET() {
  let db: "ok" | "error" = "ok";

  try {
    // Optional: await prisma.$queryRaw`SELECT 1`;
    // Remove DB ping for pure liveness on Free-tier hobby DBs.
  } catch {
    db = "error";
  }

  const healthy = db === "ok";
  const status = healthy ? "ok" : "degraded";

  return NextResponse.json(
    {
      status,
      service: "my-saas",
      db,
      timestamp: new Date().toISOString(),
    },
    { status: healthy ? 200 : 503 },
  );
}

Trade-off: returning 503 when Postgres blips marks you down on StillOnline — correct for “API not usable,” noisy during migrations. For liveness only, return 200 and omit the DB block.

2. Deploy on Vercel

  • Connect the Git repo, set production branch.
  • Add env vars (DATABASE_URL, etc.) in the Vercel dashboard.
  • Note the production host: https://your-app.vercel.app or custom domain.

Verify:

curl -sS https://your-app.vercel.app/api/health

3. Avoid common Vercel footguns

IssueFix
Middleware blocks /api/healthExclude path in middleware.ts matcher
Edge runtime without DB driverUse Node runtime for DB health or skip DB
Deployment protection on previewsMonitor production URL only
Redirect www → apexUse the final HTTPS URL in StillOnline

4. StillOnline check (five clicks)

  1. Start free.
  2. Create project + status slug.
  3. HTTP check → https://your-app.vercel.app/api/health (or custom domain), expect 200, 5 min interval.
  4. Share https://stillonline.tech/en/s/{slug} in footer / docs.
  5. Optional Pro: MCP to recreate checks after domain changes.

Free: 1 URL, 24h history. Pro $9/mo: 10 URLs, private pages, API/MCP, 90d history — Pricing.

StillOnline does not deploy to Vercel and does not read Vercel logs. It only HTTP-gets your URL.

5. When Vercel is up but you are “down”

  • Serverless cold start — rare timeouts; increase monitor timeout tolerance or warm critical paths.
  • Region-only outage — single-region Vercel + single monitor = blind spot; advanced teams add a second check from another vendor (comparison post).
  • Third-party API — health should reflect your SLA, not Stripe’s; document external deps on the status page manually via incidents.

FAQ

Server Components vs Route Handler?

Use a Route Handler under app/api/health/route.ts for a simple GET probe. Pages can SSR-cache misleading success.

Should I monitor the marketing page or /api/health?

Monitor the API if paying users depend on it. Marketing on Vercel can be up while API env is misconfigured.

Does @vercel/speed-insights replace uptime monitoring?

No. Speed Insights is performance sampling, not availability alerts.

Can I use the same repo pattern as StillOnline?

Our production app uses a similar JSON health with DB ping at api/health — see our open patterns in docs; your schema can be smaller.

Preview deployments?

StillOnline Free has one URL. Point it at production. Use Pro for extra URLs if you must watch staging.