Neon is a serverless Postgres platform with autoscaling, database branching, and per-second billing. You don't manage servers, but your application still depends on a database connection — and Neon's serverless architecture introduces its own failure modes: cold computes that take a moment to wake, connection pool exhaustion, and branch mismatches between staging and production. Vigilmon can't monitor Neon directly (it's a managed service), but it can monitor your application and its ability to reach Neon — which is what actually matters for your users.
This tutorial shows you how to add a database health check to your API and use Vigilmon to alert you the moment your app loses its Neon connection.
What You'll Build
- A
/healthAPI endpoint that probes the Neon Postgres connection - A Vigilmon HTTP monitor watching the health endpoint
- Alerts specifically tuned for database connection failures and Neon cold starts
Prerequisites
- An application using Neon Postgres (any language/framework)
- Your app deployed to a reachable URL (Vercel, Render, Railway, a VPS, etc.)
- A free account at vigilmon.online
Step 1: Add a DB Health Check to Your API
The health check should verify that your application can actually query Neon — not just that the HTTP server is running.
Node.js with pg or postgres
// routes/health.js
import postgres from "postgres";
const sql = postgres(process.env.DATABASE_URL, { max: 1 });
export async function healthHandler(req, res) {
const checks = {};
let ok = true;
try {
// Lightweight query — doesn't touch user tables
const result = await sql`SELECT 1 AS db_ok`;
checks.database = result[0]?.db_ok === 1 ? "ok" : "unexpected_result";
} catch (err) {
checks.database = `error: ${err.message}`;
ok = false;
}
res.status(ok ? 200 : 503).json({
status: ok ? "ok" : "degraded",
checks,
});
}
Node.js with Prisma
// routes/health.js
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export async function healthHandler(req, res) {
const checks = {};
let ok = true;
try {
await prisma.$queryRaw`SELECT 1`;
checks.database = "ok";
} catch (err) {
checks.database = `error: ${err.message}`;
ok = false;
} finally {
await prisma.$disconnect();
}
res.status(ok ? 200 : 503).json({ status: ok ? "ok" : "degraded", checks });
}
Python with psycopg2 or asyncpg
# routes/health.py
import os
import psycopg2
from flask import jsonify
def health():
checks = {}
ok = True
try:
conn = psycopg2.connect(os.environ["DATABASE_URL"], connect_timeout=5)
with conn.cursor() as cur:
cur.execute("SELECT 1")
conn.close()
checks["database"] = "ok"
except Exception as e:
checks["database"] = f"error: {str(e)}"
ok = False
return jsonify({"status": "ok" if ok else "degraded", "checks": checks}), 200 if ok else 503
Go with database/sql
// handlers/health.go
package handlers
import (
"database/sql"
"encoding/json"
"net/http"
"time"
)
func HealthHandler(db *sql.DB) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
checks := map[string]string{}
ok := true
db.SetConnMaxLifetime(5 * time.Second)
if err := db.PingContext(r.Context()); err != nil {
checks["database"] = "error: " + err.Error()
ok = false
} else {
checks["database"] = "ok"
}
status := "ok"
code := http.StatusOK
if !ok {
status = "degraded"
code = http.StatusServiceUnavailable
}
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(code)
json.NewEncoder(w).Encode(map[string]any{"status": status, "checks": checks})
}
}
Wire this to GET /health in your router of choice.
Step 2: Handle Neon's Serverless Cold Start
Neon's serverless computes autosuspend after a period of inactivity (default: 5 minutes on the free plan). The first connection after suspension takes a few seconds while the compute wakes. This is expected behavior, but it can cause your health check to time out if your Vigilmon timeout is too tight.
Recommendations:
- Set Vigilmon's response timeout to 15 seconds for apps on Neon's free tier.
- Use Neon's connection pooler (
-poolerconnection string suffix) — it keeps connections warm independently of the compute. - Consider setting autosuspend to a longer delay or disabling it on Neon's Pro plan for production workloads.
# Standard connection string
DATABASE_URL=postgres://user:pass@ep-xxx.us-east-2.aws.neon.tech/neondb
# Pooler connection string (preferred for serverless apps)
DATABASE_URL=postgres://user:pass@ep-xxx-pooler.us-east-2.aws.neon.tech/neondb?sslmode=require
Step 3: Configure the Vigilmon HTTP Monitor
- Log in to Vigilmon → Add Monitor → HTTP.
- URL:
https://your-app.example.com/health. - Check interval: 60 seconds.
- Response timeout: 15 seconds (Neon cold start headroom).
- Expected status:
200. - JSON assertion: path
status, expected valueok. - Click Save.
Tip: If your app is deployed to Vercel serverless functions, the /health endpoint itself may also cold-start. Set the timeout to 20 seconds to cover both the Vercel function startup and the Neon compute wakeup.
Step 4: Alert on Database Connection Failures
Configure Vigilmon alerts under Settings → Notifications:
| Trigger | Alert | Likely cause |
|---|---|---|
| HTTP 503 | Immediate email + Slack | Neon compute suspended, connection pool exhausted, or credentials rotated |
| Response timeout | Immediate email | Neon cold start taking too long; increase autosuspend delay |
| JSON status ≠ ok | Immediate email | Health check ran but DB query failed |
| Monitor unreachable | Immediate email | App server is down, not a Neon issue |
Set alert after: 2 consecutive failures. A single slow cold-start wakeup shouldn't page on-call. Two consecutive failures almost always mean a real problem.
Step 5: Environment-Specific Monitors
Neon's branching feature means you likely have multiple database branches (production, staging, preview). Add a monitor per environment:
| Monitor | URL | Alert channel |
|---|---|---|
| Production /health | https://myapp.com/health | Email + Slack (on-call) |
| Staging /health | https://staging.myapp.com/health | Slack only |
This catches the case where a bad migration on the staging branch (which may share the same Neon project) causes failures that could be confused with production issues.
What Vigilmon Catches That Neon's Dashboard Misses
| Scenario | Neon dashboard | Vigilmon |
|---|---|---|
| App can't connect to Neon | Shows compute active | HTTP monitor fires (app-side failure) |
| Wrong branch in DATABASE_URL | No alert | Health check fails, Vigilmon fires |
| Connection pool exhausted | Metrics may lag | Health endpoint returns 503, monitor fires |
| App server is down (not Neon) | No visibility | HTTP monitor catches unreachable |
| Cold start causes user-facing timeout | Compute logs | Response timeout fires alert |
Neon handles the database infrastructure, but it can't monitor your application's connection to it. That's your job — and Vigilmon makes it easy. One health endpoint, one monitor, and you'll know within 60 seconds if your app loses its database.
Add database monitoring to your Neon-backed app in minutes — register free at vigilmon.online.