tutorial

tRPC API Monitoring with Vigilmon

"Learn how to monitor tRPC APIs in your Next.js or T3 Stack application using Vigilmon — covering health procedures, REST-compatible health routes, ping monitor setup, and alerting on procedure failures."

tRPC API Monitoring with Vigilmon

tRPC is a TypeScript-first RPC framework that gives you end-to-end type safety between your client and server — no schemas, no code generation, just TypeScript. It's the backbone of the T3 Stack and increasingly common in Next.js applications. When your tRPC API goes down, your frontend loses access to all its data fetching in one shot.

This guide covers how to monitor tRPC APIs with Vigilmon, including health procedures, REST-compatible health endpoints, and alerting configuration.


The Monitoring Challenge with tRPC

tRPC procedures are not REST endpoints — they're TypeScript functions called over HTTP with a specific serialization format. A tRPC query call looks like:

GET /api/trpc/user.getProfile?input=%7B%22id%22%3A%221%22%7D

And a mutation:

POST /api/trpc/user.updateProfile
Content-Type: application/json

{"0":{"json":{"name":"Alice"}}}

Generic uptime monitors that issue plain HTTP requests won't work well with these URLs. You need either a dedicated health endpoint or a lightweight health procedure.


Strategy 1: Dedicated REST Health Endpoint (Recommended)

The simplest approach is a plain HTTP endpoint alongside your tRPC router. Since tRPC typically mounts on /api/trpc, your health check lives at /api/health or similar.

Next.js App Router

// app/api/health/route.ts
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';

export async function GET() {
  try {
    await db.$queryRaw`SELECT 1`;

    return NextResponse.json(
      { status: 'ok', service: 'trpc-api' },
      { status: 200 }
    );
  } catch (error) {
    return NextResponse.json(
      { status: 'down', error: 'Database unreachable' },
      { status: 503 }
    );
  }
}

Next.js Pages Router

// pages/api/health.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import { db } from '@/lib/db';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  if (req.method !== 'GET') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    await db.$queryRaw`SELECT 1`;
    res.status(200).json({ status: 'ok', uptime: process.uptime() });
  } catch {
    res.status(503).json({ status: 'down' });
  }
}

Point Vigilmon at https://yourapp.com/api/health and add a keyword check for "status":"ok".


Strategy 2: tRPC Health Procedure

If you prefer to keep health checks within the tRPC layer, create a dedicated health procedure on your root router:

// server/api/routers/health.ts
import { createTRPCRouter, publicProcedure } from '@/server/api/trpc';
import { db } from '@/server/db';

export const healthRouter = createTRPCRouter({
  check: publicProcedure.query(async () => {
    const checks: Record<string, boolean> = {
      database: false,
    };

    try {
      await db.$queryRaw`SELECT 1`;
      checks.database = true;
    } catch {}

    const healthy = Object.values(checks).every(Boolean);

    return {
      ok: healthy,
      checks,
      timestamp: new Date().toISOString(),
    };
  }),
});

Register it on the root router:

// server/api/root.ts
import { createTRPCRouter } from '@/server/api/trpc';
import { healthRouter } from './routers/health';
import { userRouter } from './routers/user';

export const appRouter = createTRPCRouter({
  health: healthRouter,
  user: userRouter,
});

The health procedure is now callable at:

GET /api/trpc/health.check

The tRPC response wraps your return value in a result envelope:

{"result":{"data":{"json":{"ok":true,"checks":{"database":true},"timestamp":"2026-06-30T07:00:00.000Z"}}}}

Configure Vigilmon with:

  • URL: https://yourapp.com/api/trpc/health.check
  • Method: GET
  • Keyword check: "ok":true

Setting Up the Vigilmon Monitor

Step 1: Create the Monitor

  1. Log in to VigilmonMonitors → New Monitor
  2. Type: HTTP
  3. Method: GET
  4. URL: https://yourapp.com/api/health (or your tRPC health procedure URL)
  5. Interval: 1 minute
  6. Keyword check: "status":"ok" or "ok":true depending on your endpoint

Step 2: Add Authentication Headers (if needed)

If your health endpoint requires an API key for security:

// app/api/health/route.ts
export async function GET(req: Request) {
  const token = req.headers.get('x-health-token');

  if (token !== process.env.HEALTH_CHECK_TOKEN) {
    return new Response('Unauthorized', { status: 401 });
  }

  // ... health logic
}

In Vigilmon, add a custom header: X-Health-Token: your-token-value.

Alternatively, keep the health endpoint public (no auth) but return no sensitive data — just { status: 'ok' } or { status: 'down' }.


Handling tRPC Errors in Monitoring

tRPC uses HTTP status codes differently from REST. A tRPC procedure error returns a non-2xx HTTP status depending on the error type:

| tRPC Error Code | HTTP Status | |-----------------|-------------| | UNAUTHORIZED | 401 | | NOT_FOUND | 404 | | INTERNAL_SERVER_ERROR | 500 | | BAD_REQUEST | 400 |

Vigilmon monitors the HTTP status code by default. If your health procedure throws a tRPC error, Vigilmon will catch the resulting 4xx/5xx response automatically.

For deeper monitoring — catching when a specific procedure consistently returns errors even with a 200 status — use keyword monitoring. Add a keyword check that must be absent: "error". This catches cases where tRPC returns 200 with an error envelope.


Webhook Alerting

When Vigilmon detects your tRPC API is down, it can POST to your webhook endpoint. Handle it server-side:

// app/api/webhooks/vigilmon/route.ts
import { NextResponse } from 'next/server';

export async function POST(req: Request) {
  const payload = await req.json();
  const { event, monitor } = payload;

  if (event === 'down') {
    console.error(`[Vigilmon] DOWN: ${monitor.name}`);
    // Notify Slack, create incident, page on-call
    await notifySlack(`🔴 tRPC API is DOWN: ${monitor.url}`);
  } else if (event === 'up') {
    console.info(`[Vigilmon] RECOVERED: ${monitor.name}`);
    await notifySlack(`✅ tRPC API recovered: ${monitor.url}`);
  }

  return NextResponse.json({ received: true });
}

Register this URL in Vigilmon under Alert Channels → Webhook.


Monitoring Across Environments

For T3 Stack apps deployed to Vercel, Railway, or Fly.io, set up one monitor per environment:

| Environment | URL | Alert Channel | |-------------|-----|---------------| | Production | https://yourapp.com/api/health | PagerDuty + Slack | | Staging | https://staging.yourapp.com/api/health | Slack only | | Preview | https://preview-abc.vercel.app/api/health | Email only |

Use Vigilmon's monitor groups to organize these and get a unified dashboard view.


Alerting on Procedure Latency

tRPC procedures that are slow degrade UX even when they technically return 200. Monitor response time as well as availability:

  1. In Vigilmon, open your monitor → Advanced Settings
  2. Enable Response time threshold
  3. Set a warning at 1000ms and a critical alert at 3000ms

For tRPC over Next.js, cold starts on serverless deployments can cause spikes. Set the threshold to 5000ms for the first check after a deployment, then tighten it once the function is warm.


Summary

| Scenario | Approach | |----------|----------| | Next.js App Router | app/api/health/route.ts returning JSON | | Next.js Pages Router | pages/api/health.ts returning JSON | | tRPC procedure health | health.check public procedure with DB ping | | Error monitoring | Keyword check for absence of "error" | | Latency monitoring | Response time threshold in Vigilmon |

With a health endpoint and Vigilmon configured, you'll catch tRPC API failures within 60 seconds — before users see loading spinners that never resolve.


Further Reading

Monitor your app with Vigilmon

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

Start free →