How to Monitor Vinxi with Vigilmon
Vinxi powers the full-stack layer under TanStack Start and other modern metaframeworks. It wires together Vite bundling, Nitro server rendering, and deployment adapters — giving you a framework-in-a-box that can target Node.js, Cloudflare Workers, Vercel, Netlify, and more.
The deployment flexibility is powerful. It also means failures look different depending on where you deploy: a Cloudflare Worker timeout looks nothing like a Node.js OOM crash, and a Vercel SSR function timeout is different from a Nitro prerender error.
This tutorial covers monitoring a Vinxi application regardless of deployment target. By the end you'll have:
- A health route that verifies your Vinxi server is rendering
- HTTP uptime monitoring with Vigilmon
- Deployment verification after every push
- Heartbeat monitoring for background tasks
- Slack alerts on downtime and recovery
Why Monitor a Vinxi Application
Vinxi abstracts over multiple runtimes, which introduces several distinct failure modes:
- Nitro server crash — SSR rendering fails, all routes return 500
- Adapter misconfiguration — build succeeds but the deployment adapter targets the wrong runtime format
- Server function error — RPC endpoints (
createServerFn) throw, client-side requests fail silently - Cold start regression — bundle grew, cold start latency spiked, first-load p99 crosses SLA
- Static asset mismatch — Vite build hash rotated but CDN serves stale JS — hydration errors on client
External monitoring catches all of these as HTTP failures or timeouts, before your users find them.
Key Metrics to Watch
| Metric | What it means | |--------|---------------| | Health endpoint HTTP status | Nitro server alive and responding | | SSR route response time | Rendering latency, cold starts | | Server function response | RPC layer functional | | Deployment heartbeat | Build + deploy completed successfully | | Static asset availability | CDN serving current build artifacts |
Step 1: Add a Health Route to Your Vinxi App
Vinxi uses file-based routing conventions (following the framework built on top of it). Here's how to add a health endpoint that works with TanStack Start's API route convention:
TanStack Start (API route)
// app/routes/api/health.ts
import { json } from '@tanstack/start';
import { createAPIFileRoute } from '@tanstack/start/api';
export const APIRoute = createAPIFileRoute('/api/health')({
GET: async ({ request }) => {
const checks: Record<string, 'ok' | 'error'> = {};
let allOk = true;
// Check your data layer
try {
// Replace with your actual DB check
await checkDatabase();
checks.database = 'ok';
} catch {
checks.database = 'error';
allOk = false;
}
return json(
{ status: allOk ? 'ok' : 'degraded', checks, timestamp: new Date().toISOString() },
{ status: allOk ? 200 : 503 },
);
},
});
Custom Vinxi App (raw Nitro route)
If you're building a custom framework on top of Vinxi, add a Nitro server route:
// server/routes/health.get.ts (Nitro convention)
export default defineEventHandler(async (event) => {
const checks: Record<string, 'ok' | 'error'> = {};
let allOk = true;
try {
await checkDatabase();
checks.database = 'ok';
} catch {
checks.database = 'error';
allOk = false;
}
setResponseStatus(event, allOk ? 200 : 503);
return { status: allOk ? 'ok' : 'degraded', checks };
});
Test locally:
npm run dev
curl http://localhost:3000/api/health
# {"status":"ok","checks":{"database":"ok"},"timestamp":"2026-07-06T10:00:00.000Z"}
Step 2: SSR Smoke-Test Route
The health endpoint verifies your server layer. But Vinxi's value is SSR — you should also verify that full server-side rendering works, not just that the process is alive.
Add a minimal SSR route that renders without data dependencies:
// app/routes/api/health/render.ts
import { json } from '@tanstack/start';
import { createAPIFileRoute } from '@tanstack/start/api';
// Renders a minimal HTML string server-side — verifies Nitro + Vite SSR pipeline
export const APIRoute = createAPIFileRoute('/api/health/render')({
GET: async () => {
try {
const html = `<html><body>ok</body></html>`;
return new Response(html, {
status: 200,
headers: { 'Content-Type': 'text/html' },
});
} catch (err) {
return json({ error: 'SSR failure' }, { status: 503 });
}
},
});
Monitor /api/health/render as a separate Vigilmon check alongside /api/health. If the server process is up but SSR is broken, the render check catches it while the plain health check passes.
Step 3: Set Up HTTP Monitoring in Vigilmon
- Sign up at vigilmon.online (free, no card required)
- Click New Monitor → HTTP
- Enter
https://yourdomain.com/api/health - Set check interval: 1 minute (paid) or 5 minutes (free)
- Expected status code:
200 - Save
Add a second monitor for the SSR render check:
https://yourdomain.com/api/health → server process + deps
https://yourdomain.com/api/health/render → Nitro SSR pipeline
For Vercel or Netlify deployments, also monitor your preview URL pattern so you catch failures on staging before they reach production.
Step 4: Deployment Verification Heartbeat
Every Vinxi deployment should end with a verified health check ping. This pattern catches deployments that complete (build succeeds, container starts) but the app is serving errors.
Add a post-deploy verification step to your CI/CD:
#!/bin/bash
# scripts/verify-deploy.sh
HEALTH_URL="${DEPLOY_URL}/api/health"
HEARTBEAT_URL="${VIGILMON_DEPLOY_HEARTBEAT}"
MAX_RETRIES=12
RETRY_INTERVAL=10
echo "Waiting for deployment to be healthy..."
for i in $(seq 1 $MAX_RETRIES); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "$HEALTH_URL")
if [ "$STATUS" = "200" ]; then
echo "Health check passed after $((i * RETRY_INTERVAL))s"
# Notify Vigilmon that deployment succeeded
if [ -n "$HEARTBEAT_URL" ]; then
curl -s "$HEARTBEAT_URL" > /dev/null
echo "Deployment heartbeat sent"
fi
exit 0
fi
echo "Attempt $i/$MAX_RETRIES: got $STATUS, retrying in ${RETRY_INTERVAL}s..."
sleep $RETRY_INTERVAL
done
echo "Deployment health check failed after $((MAX_RETRIES * RETRY_INTERVAL))s"
exit 1
In Vigilmon:
- Click New Monitor → Heartbeat
- Set expected interval: 24 hours (or your deploy frequency)
- Copy the ping URL → set as
VIGILMON_DEPLOY_HEARTBEATin your CI secrets - Save
If a deployment fails its health check (script exits 1), no heartbeat is sent. Vigilmon alerts you that a verified deployment hasn't happened in over 24 hours.
Step 5: Server Function Monitoring
TanStack Start server functions (createServerFn) are RPC calls from client to server. They're critical paths — if a server function returns an error, the user-visible action fails.
Add a canary server function that acts as a lightweight smoke test:
// app/functions/healthPing.ts
import { createServerFn } from '@tanstack/start';
export const serverHealthPing = createServerFn({ method: 'GET' }).handler(async () => {
// Check any critical server-side resource
await checkDatabase();
return { ok: true, timestamp: new Date().toISOString() };
});
Expose it via an API route that Vigilmon can poll:
// app/routes/api/health/server-fn.ts
export const APIRoute = createAPIFileRoute('/api/health/server-fn')({
GET: async () => {
try {
const result = await serverHealthPing();
return json(result);
} catch {
return json({ ok: false }, { status: 503 });
}
},
});
Add a Vigilmon monitor for /api/health/server-fn. If server functions start failing (Nitro handler crash, serialization error, middleware regression), you're alerted before users hit a broken UI action.
Step 6: Slack Alerts and Status Page
Slack alerts: Go to Notifications → New Channel → Slack in Vigilmon, paste your webhook URL, and enable it on all monitors.
When your Vinxi app goes down:
🔴 DOWN: yourdomain.com/api/health
Status: 503 Service Unavailable
Region: NA-West
2 minutes ago
Status page: In Vigilmon, go to Status Pages → New Status Page, add all your monitors (health, SSR render, server functions), and publish.
Link it from your app's error boundary:
// app/components/ErrorBoundary.tsx
export function ErrorBoundary({ error }: { error: Error }) {
return (
<div>
<h2>Something went wrong</h2>
<p>
Check our <a href="https://status.yourdomain.com">status page</a> for updates.
</p>
</div>
);
}
What You've Built
| What | How |
|------|-----|
| Server health endpoint | Nitro/API route returning 200/503 |
| SSR pipeline check | Render canary route verifying full SSR |
| HTTP uptime monitoring | Vigilmon HTTP monitor → /api/health |
| Deployment verification | CI script + heartbeat ping after health check passes |
| Server function monitoring | Canary API route wrapping createServerFn |
| Slack alerts | Vigilmon Slack notification channel |
| Status page | Vigilmon public status page |
Your Vinxi application is now observable end-to-end — from server process health to SSR rendering to individual RPC calls. You'll know about regressions before your users do.
Next Steps
- Add Vinxi adapter-specific checks: for Cloudflare Workers adapters, verify Worker CPU and KV bindings; for Vercel, verify Edge Function response times
- Monitor your static asset CDN URL alongside the SSR health check — a CDN outage can cause hydration errors even when your server is fine
- Add a heartbeat for any background data sync or cache warming jobs that run after deployment
Get started free at vigilmon.online.