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.appor custom domain.
Verify:
curl -sS https://your-app.vercel.app/api/health
3. Avoid common Vercel footguns
| Issue | Fix |
|---|---|
Middleware blocks /api/health | Exclude path in middleware.ts matcher |
| Edge runtime without DB driver | Use Node runtime for DB health or skip DB |
| Deployment protection on previews | Monitor production URL only |
Redirect www → apex | Use the final HTTPS URL in StillOnline |
4. StillOnline check (five clicks)
- Start free.
- Create project + status slug.
- HTTP check →
https://your-app.vercel.app/api/health(or custom domain), expect 200, 5 min interval. - Share
https://stillonline.tech/en/s/{slug}in footer / docs. - 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?
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.