tutorial

How to Monitor Vinxi with Vigilmon

Production monitoring for Vinxi-powered frameworks and metaframeworks — health endpoints for SSR apps, uptime checks, deployment verification, and server function alerting.

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

  1. Sign up at vigilmon.online (free, no card required)
  2. Click New Monitor → HTTP
  3. Enter https://yourdomain.com/api/health
  4. Set check interval: 1 minute (paid) or 5 minutes (free)
  5. Expected status code: 200
  6. 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:

  1. Click New Monitor → Heartbeat
  2. Set expected interval: 24 hours (or your deploy frequency)
  3. Copy the ping URL → set as VIGILMON_DEPLOY_HEARTBEAT in your CI secrets
  4. 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.

Monitor your app with Vigilmon

Free plan — 5 monitors, no credit card required. Up and running in 60 seconds.

Start free →