npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@nurbak/watch

v1.2.3

Published

Lightweight monitoring SDK for Next.js API routes and Server Actions

Downloads

89

Readme

@nurbak/watch

Lightweight monitoring SDK for Next.js API routes and Server Actions.

npm version License: MIT Next.js

Nurbak Watch monitors every Next.js API route and Server Action automatically — no external pings, no agents, no YAML. Health checks run inside your server process, catching issues that external monitors miss.

Dashboard, docs and early access at nurbak.com


Table of Contents


Why Nurbak Watch

External monitors ping your URL from outside. They tell you your server responded. They don't tell you:

  • Why /api/checkout is 4x slower than yesterday
  • That 3% of /api/users requests are returning 500
  • That your database connection pool is exhausted

Nurbak Watch runs inside your Next.js server process, capturing real request data on every API route and Server Action — not synthetic pings.


Quick Start

The fastest way to get started is with the CLI:

npx @nurbak/watch init

The CLI will automatically:

  1. Detect your Next.js project (TypeScript/JavaScript, src/ directory, package manager)
  2. Ask for your API key
  3. Create instrumentation.ts with the SDK initialized
  4. Create middleware.ts with the monitoring wrapper
  5. Add your API key to .env.local
  6. Install the package

You can also run it non-interactively:

npx @nurbak/watch init --key nw_test_your_key_here

That's it. Start your dev server and events will appear in your dashboard within 30 seconds.


Manual Installation

If you prefer to set things up yourself, follow these steps.

1. Install the package

# npm
npm install @nurbak/watch

# yarn
yarn add @nurbak/watch

# pnpm
pnpm add @nurbak/watch

# bun
bun add @nurbak/watch

2. Create instrumentation.ts

This file hooks into the Next.js instrumentation API and initializes the SDK when your server starts.

App Router with src/ directory — create src/instrumentation.ts:

import { initWatch } from '@nurbak/watch'

export async function register() {
  initWatch({
    apiKey: process.env.NODE_ENV === 'production'
      ? process.env.NURBAK_WATCH_KEY_LIVE!
      : process.env.NURBAK_WATCH_KEY_TEST!,
  })
}

Without src/ directory — create instrumentation.ts at the project root.

JavaScript projects — use the same code in instrumentation.js (remove the ! non-null assertions).

3. Create middleware.ts

The middleware captures App Router API route requests, including latency, status codes, and response metadata.

Create src/middleware.ts (or middleware.ts at the root if not using src/):

import { withNurbakMiddleware } from '@nurbak/watch'

export default withNurbakMiddleware()

export const config = { matcher: '/api/:path*' }

4. Add your API key

Add your key to .env.local:

# For development
NURBAK_WATCH_KEY_TEST=nw_test_your_key_here

# For production
NURBAK_WATCH_KEY_LIVE=nw_live_your_key_here

5. Enable instrumentation hook (Next.js < 15 only)

If you're on Next.js 13.4–14.x, enable the experimental instrumentation hook in next.config.js:

/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    instrumentationHook: true,
  },
}
module.exports = nextConfig

Next.js 15+ has instrumentation enabled by default — no config change needed.


Configuration

Pass options to initWatch() to customize the SDK behavior:

import { initWatch } from '@nurbak/watch'

export async function register() {
  initWatch({
    // Required
    apiKey: process.env.NURBAK_WATCH_KEY_LIVE!,

    // Optional
    enabled: true,              // Enable/disable the SDK (default: true, false in test env)
    debug: false,               // Log internal SDK activity to console (default: false)
    sampleRate: 1.0,            // Fraction of requests to capture: 0.0 to 1.0 (default: 1.0)
    ignorePaths: ['/api/health'], // Array of path prefixes to exclude from monitoring
    flushInterval: 5000,        // How often to flush the event queue in ms (default: 5000)
    maxBatchSize: 100,          // Max events per batch sent to the ingest API (default: 100)
    ingestUrl: 'https://ingestion.nurbak.com', // Custom ingest endpoint (default: Nurbak cloud)
  })
}

Configuration Options

| Option | Type | Default | Description | |---|---|---|---| | apiKey | string | — | Required. Your Nurbak Watch API key. | | enabled | boolean | true | Set to false to disable monitoring. Automatically disabled in NODE_ENV=test. | | debug | boolean | false | Enables verbose console logging for troubleshooting. | | sampleRate | number | 1.0 | Fraction of requests to monitor (0.0 = none, 1.0 = all). Useful for high-traffic apps. | | ignorePaths | string[] | [] | Path prefixes to exclude (e.g., ['/api/health', '/api/internal']). | | flushInterval | number | 5000 | Milliseconds between automatic queue flushes. | | maxBatchSize | number | 100 | Maximum number of events per batch. | | ingestUrl | string | https://ingestion.nurbak.com | Override the ingest endpoint (for self-hosted or testing). |


Environment Variables

The SDK reads these environment variables:

| Variable | Description | |---|---| | NURBAK_WATCH_KEY_LIVE | API key for production. Used when NODE_ENV=production. | | NURBAK_WATCH_KEY_TEST | API key for development/staging. Used when NODE_ENV is not production. | | NURBAK_WATCH_KEY | Fallback API key used if the environment-specific key is not set. | | NURBAK_WATCH_DEBUG | Set to "true" to enable debug logging in the middleware layer. | | NURBAK_WATCH_INGEST_URL | Override the default ingest endpoint from the middleware layer. |

Recommended setup in .env.local:

NURBAK_WATCH_KEY_TEST=nw_test_xxxxxxxxxxxxx
NURBAK_WATCH_KEY_LIVE=nw_live_xxxxxxxxxxxxx

Middleware

Basic usage

If you don't have an existing middleware:

import { withNurbakMiddleware } from '@nurbak/watch'

export default withNurbakMiddleware()

export const config = { matcher: '/api/:path*' }

Wrapping an existing middleware

If you already have a middleware.ts, wrap your existing function:

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { withNurbakMiddleware } from '@nurbak/watch'

function myMiddleware(request: NextRequest) {
  // Your existing middleware logic
  const response = NextResponse.next()
  response.headers.set('x-custom-header', 'value')
  return response
}

export default withNurbakMiddleware(myMiddleware)

export const config = { matcher: '/api/:path*' }

The wrapper passes the request through your middleware first, then captures the response metadata (status, latency, size) and sends it to Nurbak after the response is delivered to the client.

How the middleware matcher works

The config.matcher controls which routes the middleware runs on. We recommend /api/:path* to monitor all API routes. You can narrow this if needed:

export const config = {
  matcher: ['/api/v1/:path*', '/api/v2/:path*']
}

Non-API routes that hit the middleware are automatically skipped by Nurbak Watch.


What Gets Monitored

API Routes (App Router & Pages Router)

Every request to /api/* is automatically captured via two mechanisms:

  • Middleware layer — captures App Router route handlers with after() for serverless-safe flushing.
  • HTTP interceptor — patches http.Server.emit('request') to capture Pages Router API routes in Node.js runtime.

Server Actions

Server Actions are detected via the Next-Action HTTP header and captured through a fetch interceptor. The SDK resolves action names from Next.js's server-reference-manifest.json when available.

Data captured per event

| Field | Description | |---|---| | method | HTTP method (GET, POST, PUT, DELETE, etc.) | | path | Normalized route path (dynamic segments replaced with [id]) | | statusCode | HTTP status code | | statusCategory | 2xx, 3xx, 4xx, or 5xx | | durationMs | Request duration in milliseconds | | responseBytes | Response body size in bytes | | runtime | nodejs or edge | | region | Vercel region (when available via VERCEL_REGION) | | errorType | Error class name (on failures) | | errorMessage | Error message, truncated to 200 chars (on failures) | | actionHash | Server Action hash (for Server Actions) | | actionName | Resolved Server Action function name (when manifest is available) |

Path normalization

Dynamic segments are automatically replaced with [id] to group related routes:

  • /api/users/12345/api/users/[id]
  • /api/orders/550e8400-e29b-41d4-a716-446655440000/api/orders/[id]
  • /api/posts/abc123def456/api/posts/[id]

How It Works

Your Next.js App
├── instrumentation.ts
│   └── initWatch()
│       ├── Initializes event queue with batching + retry
│       ├── Patches http.Server to capture Pages Router API requests
│       └── Patches global fetch to capture Server Actions
│
└── middleware.ts
    └── withNurbakMiddleware()
        ├── Captures App Router API route requests
        ├── Measures latency and response status
        └── Uses after() to flush events after response is sent

Event lifecycle:

  1. A request hits your API route or Server Action
  2. The SDK captures method, path, status, latency, and error info
  3. The event is added to an in-memory queue
  4. The queue flushes to Nurbak's ingest API every 5 seconds (configurable) or immediately after each event in serverless environments
  5. Failed flushes retry up to 3 times with backoff on 429 (rate limit)
  6. On Vercel, after() and waitUntil() ensure flushes complete before the container freezes

API Reference

initWatch(config: NurbakWatchConfig): void

Initializes the SDK. Call this inside register() in your instrumentation.ts. Idempotent — calling it multiple times has no effect.

import { initWatch } from '@nurbak/watch'

initWatch({
  apiKey: process.env.NURBAK_WATCH_KEY_LIVE!,
  debug: true,
})

withNurbakMiddleware(middleware?: MiddlewareFunction)

Wraps your Next.js middleware to capture API route monitoring data. Returns a new middleware function.

import { withNurbakMiddleware } from '@nurbak/watch'

// Without existing middleware
export default withNurbakMiddleware()

// With existing middleware
export default withNurbakMiddleware(myMiddleware)

flush(): Promise<void>

Manually flushes the event queue. Useful in edge cases where you need to ensure all events are sent before a process exits.

import { flush } from '@nurbak/watch'

await flush()

getSdkStatus(): Promise<SdkStatus>

Returns the current SDK status for debugging.

import { getSdkStatus } from '@nurbak/watch'

const status = await getSdkStatus()
// { initialized: true, queueSize: 0, config: { ... } }

Types

interface NurbakWatchConfig {
  apiKey: string
  ingestUrl?: string
  enabled?: boolean
  debug?: boolean
  sampleRate?: number
  ignorePaths?: string[]
  flushInterval?: number
  maxBatchSize?: number
}

interface SdkStatus {
  initialized: boolean
  queueSize: number
  config: NurbakWatchConfig | null
}

interface ApiCallEvent {
  eventType: 'api_route' | 'server_action'
  method: string
  path: string
  statusCode: number
  statusCategory: '2xx' | '3xx' | '4xx' | '5xx'
  responseBytes: number
  startedAt: string
  durationMs: number
  runtime: 'nodejs' | 'edge'
  region?: string
  errorType?: string
  errorMessage?: string
  actionHash?: string
  actionName?: string
}

CLI Reference

npx @nurbak/watch init

Interactive setup wizard that detects your project and creates all necessary files.

npx @nurbak/watch init

What it does:

  1. Detects Next.js version, TypeScript/JavaScript, src/ directory, and package manager
  2. Prompts for your API key
  3. Creates instrumentation.ts (or .js)
  4. Creates middleware.ts (or .js)
  5. Adds API key to .env.local
  6. Warns if instrumentationHook needs enabling (Next.js < 15)
  7. Installs @nurbak/watch

Non-interactive mode (for CI or AI assistants):

npx @nurbak/watch init --key nw_test_xxxxxxxxxxxxx

Options:

| Flag | Description | |---|---| | --key <key> | API key (nw_test_* or nw_live_*). Skips the interactive prompt. | | --help | Show CLI help. |


Deployment

Vercel

Nurbak Watch is designed to work on Vercel out of the box. The SDK uses after() from next/server and waitUntil() to ensure events are flushed before the serverless container freezes.

No additional configuration is needed. Just set your environment variables in the Vercel dashboard:

NURBAK_WATCH_KEY_LIVE=nw_live_xxxxxxxxxxxxx
NURBAK_WATCH_KEY_TEST=nw_test_xxxxxxxxxxxxx

Self-hosted / Docker

The SDK works identically on self-hosted Next.js. The http.Server interceptor captures all API route requests in long-running Node.js processes.

Edge Runtime

The middleware layer (withNurbakMiddleware) works in both Node.js and Edge runtimes. The instrumentation interceptor (initWatch) runs in the Node.js runtime only.


Nurbak Watch vs Alternatives

| Feature | Datadog | New Relic | Nurbak Watch | |---|---|---|---| | Setup time | 30–60 min | 30–60 min | 2 min | | Lines of code | 50–100+ | 50–100+ | 5 | | Monthly cost | $23+/host | $25+/host | Free tier | | Works on Vercel | Limited | Limited | Yes | | Internal execution | No | No | Yes | | Server Action monitoring | No | No | Yes | | WhatsApp alerts | No | No | Yes | | Zero dependencies | No | No | Yes | | Auto-discovers routes | Partial | Partial | Yes | | Package size | Heavy | Heavy | < 10 KB |


Requirements

  • Next.js 13.4 or higher (App Router, Pages Router, or both)
  • Node.js 18 or higher
  • A free Nurbak account at nurbak.com

Get Your API Key

  1. Go to watch.nurbak.com
  2. Create a free account
  3. Add your project
  4. Copy your API keys (nw_test_* for development, nw_live_* for production)
  5. Add them to .env.local

Troubleshooting

Events not appearing in the dashboard

  1. Enable debug mode to see SDK activity in the console:

    initWatch({ apiKey: '...', debug: true })

    Or set the environment variable: NURBAK_WATCH_DEBUG=true

  2. Check that your API key is correctly set and starts with nw_test_ or nw_live_

  3. Verify your middleware matcher includes /api/:path*

  4. On Next.js < 15, ensure instrumentationHook: true is set in next.config.js

SDK disabled in test environment

The SDK automatically disables itself when NODE_ENV=test. To override this:

initWatch({ apiKey: '...', enabled: true })

Duplicate events

If you see duplicate events, ensure initWatch() is only called once in instrumentation.ts. The SDK is idempotent — multiple calls are safe but unnecessary.


Early Access

Nurbak Watch is currently in beta — free during launch.

  • Free tier included
  • No credit card required
  • Pro plan free for the first 3 months for early adopters
  • Locked pricing for life

Reserve your spot at nurbak.com


License

MIT - Nurbak