Nostics
Getting Started

Quick start

Install nostics and define your first diagnostic catalog.

nostics is for library authors who want errors and warnings to be easy to recognize, document, and fix.

Instead of throwing anonymous strings from different places, you define a small catalog of diagnostic codes. Each code has a stable name, a message, an optional fix, and an optional docs URL.

Install

pnpm add nostics

The package is ESM only.

Define codes

Create one or multiple diagnostics file(s) in your library.

src/diagnostics.ts
import { createConsoleReporter, defineDiagnostics } from 'nostics'

export const diagnostics = defineDiagnostics({
  docsBase: code => `https://nuxt.com/e/${code.replace('NUXT_', '').toLowerCase()}`,
  reporters: [createConsoleReporter()],
  codes: {
    NUXT_B2011: {
      why: (p: { src: string, mode: 'client' | 'server' }) => {
        const expected = p.mode === 'client' ? 'server' : 'client'
        return `Plugin "${p.src}" is ${expected}-only but was registered with mode "${p.mode}".`
      },
      fix: (p: { mode: 'client' | 'server' }) => {
        const expected = p.mode === 'client' ? 'server' : 'client'
        return `Rename the file or register it with mode "${expected}".`
      },
    },
    NUXT_B5001: {
      why: (p: { value: string, configPath: string }) =>
        `Invalid compatibilityDate "${p.value}" in ${p.configPath}.`,
      fix: (p: { example: string }) => `Use an ISO date like "${p.example}", or "latest".`,
    },
  },
})

The returned diagnostics object has one function per code. TypeScript checks the params at the call site.

Use them

src/module.ts
import { diagnostics } from './diagnostics'

type PluginMode = 'all' | 'client' | 'server'

export function addRuntimePlugin(plugin: { src: string, mode?: PluginMode }): void {
  const suffix = plugin.src.match(/\.(client|server)\./)?.[1] as 'client' | 'server' | undefined

  if (suffix && plugin.mode && plugin.mode !== 'all' && plugin.mode !== suffix) {
    throw diagnostics.NUXT_B2011({
      src: plugin.src,
      mode: plugin.mode,
      sources: [plugin.src],
    })
  }

  // register plugin
}

export function validateConfig(config: { compatibilityDate?: string, filepath: string }): void {
  if (config.compatibilityDate && !/^(\d{4}-\d{2}-\d{2}|latest)$/.test(config.compatibilityDate)) {
    diagnostics.NUXT_B5001({
      configPath: config.filepath,
      value: config.compatibilityDate,
      example: '2024-04-03',
    })
  }
}

Calling a diagnostic reports it and returns a Diagnostic. Throwing the return value raises it.

Output

[NUXT_B2011] Plugin `./runtime/analytics.server.ts` is server-only but was registered with mode `client`.
├▶ fix: Rename the file or register it with mode `server`.
├▶ sources: modules/analytics.ts:18:5
╰▶ see: https://nuxt.com/e/b2011

The code is stable, the message is readable, and the fix is next to the error.

Catch it

Diagnostic extends Error.

import { Diagnostic } from 'nostics'

try {
  const plugin = resolvePlugin()
  addRuntimePlugin(plugin)
}
catch (error) {
  if (error instanceof Diagnostic) {
    console.log(error.name)
    console.log(error.fix)
    console.log(error.docs)
  }
}

Next

Define diagnostics

Parameters, docs URLs, sources, causes, and code naming.

Production builds

Strip report-only diagnostics from production bundles.

API reference

Imports, types, options, and built-ins.
Copyright © 2026