nuxt-safe-runtime-config
nuxt-safe-runtime-config

Validate Nuxt runtime config with Standard Schema at build time

Nuxt safe runtime config logo
Nuxt Safe Runtime Config

Validate Nuxt runtime config at build time using Zod, Valibot, ArkType, or any Standard Schema compatible library.


npm version npm downloads License Nuxt

๐Ÿ”— Related Nuxt RFC: Enable Standard Schema Validation in Nuxt Config

Features

  • ๐Ÿ”’ Build-time validation with Zod, Valibot, ArkType, or any Standard Schema library
  • ๐Ÿš€ Runtime validation (opt-in) validates config when the server starts
  • โœจ Auto-generated types โ€” useSafeRuntimeConfig() is fully typed without manual generics
  • ๐Ÿ›  ESLint plugin warns when using useRuntimeConfig() instead of the type-safe composable
  • โšก Zero runtime overhead by default โ€” validation happens at build time only

Quick Setup

Install the module:

npx nuxi module add nuxt-safe-runtime-config

Usage

1. Define your schema

Use Zod, Valibot, ArkType, or any Standard Schema compatible library:

With Valibot
import { number, object, optional, string } from 'valibot'

const runtimeConfigSchema = object({
  public: object({
    apiBase: string(),
    appName: optional(string()),
  }),
  databaseUrl: string(),
  secretKey: string(),
  port: optional(number()),
})
With Zod
import { z } from 'zod'

const runtimeConfigSchema = z.object({
  public: z.object({
    apiBase: z.string(),
    appName: z.string().optional(),
  }),
  databaseUrl: z.string(),
  secretKey: z.string(),
  port: z.number().optional(),
})
With ArkType
import { type } from 'arktype'

const runtimeConfigSchema = type({
  'public': {
    'apiBase': 'string',
    'appName?': 'string'
  },
  'databaseUrl': 'string',
  'secretKey': 'string',
  'port?': 'number'
})

2. Configure in nuxt.config.ts

export default defineNuxtConfig({
  modules: ['nuxt-safe-runtime-config'],

  runtimeConfig: {
    databaseUrl: process.env.DATABASE_URL || 'postgresql://localhost:5432/mydb',
    secretKey: process.env.SECRET_KEY || 'default-secret-key',
    port: Number.parseInt(process.env.PORT || '3000'),
    public: {
      apiBase: process.env.PUBLIC_API_BASE || 'https://api.example.com',
      appName: 'My Nuxt App',
    },
  },

  safeRuntimeConfig: {
    $schema: runtimeConfigSchema,
  },
})

3. Use the type-safe composable

Access your validated config with full type safety โ€” types are auto-generated from your schema:

<script setup lang="ts">
const config = useSafeRuntimeConfig()
// config.public.apiBase is typed as string
// config.secretKey is typed as string
</script>

Configuration Options

OptionTypeDefaultDescription
$schemaStandardSchemaV1โ€”Your validation schema (required)
validateAtBuildbooleantrueValidate during dev/build
validateAtRuntimebooleanfalseValidate when server starts
onBuildError'throw' | 'warn' | 'ignore''throw'How to handle build validation errors
onRuntimeError'throw' | 'warn' | 'ignore''throw'How to handle runtime validation errors
logSuccessbooleantrueLog successful validation
logFallbackbooleantrueLog when using JSON Schema fallback
jsonSchemaTargetstring'draft-2020-12'JSON Schema version for runtime validation

Runtime Validation

By default, validation only runs at build time. Enable runtime validation to catch environment variable issues when the server starts:

export default defineNuxtConfig({
  safeRuntimeConfig: {
    $schema: runtimeConfigSchema,
    validateAtRuntime: true,
  },
})

Runtime validation uses @cfworker/json-schema to validate the config after environment variables are merged. This lightweight validator (~8KB) works on all runtimes including edge (Cloudflare Workers, Vercel Edge, Netlify Edge). It catches issues like:

  • Environment variables with wrong types (e.g., NUXT_PORT=abc when expecting a number)
  • Missing required environment variables in production
  • Invalid values that pass build-time checks but fail at runtime

ESLint Integration

The module includes an ESLint plugin that warns when using useRuntimeConfig() instead of useSafeRuntimeConfig().

With @nuxt/eslint (Automatic)

If you use @nuxt/eslint, the rule is auto-registered. No configuration needed.

Manual Setup

Add to your eslint.config.mjs:

import safeRuntimeConfig from 'nuxt-safe-runtime-config/eslint'

export default [
  safeRuntimeConfig.configs.recommended,
  // ... your other configs
]

Or configure manually:

import safeRuntimeConfig from 'nuxt-safe-runtime-config/eslint'

export default [
  {
    plugins: { 'safe-runtime-config': safeRuntimeConfig },
    rules: { 'safe-runtime-config/prefer-safe-runtime-config': 'warn' },
  },
]

The rule includes auto-fix support โ€” run eslint --fix to automatically replace useRuntimeConfig() calls.

Type Safety

Types are auto-generated at build time from your schema's JSON Schema representation. The useSafeRuntimeConfig() composable returns a fully typed object โ€” no manual generics needed:

const config = useSafeRuntimeConfig()
// config is fully typed based on your schema

Generated types are stored in .nuxt/types/safe-runtime-config.d.ts and automatically included in your project.

Error Messages

When validation fails, you see detailed error messages:

[safe-runtime-config] Validation failed!
  1. databaseUrl: Invalid type: Expected string but received undefined
  2. public.apiBase: Invalid type: Expected string but received undefined
  3. port: Invalid type: Expected number but received string

The module stops the build process until all validation errors are resolved.

Why This Module?

Nuxt's built-in schema validation is designed for module authors and broader configuration. This module focuses specifically on runtime config validation using Standard Schema, allowing you to:

  • Use your preferred validation library (Valibot, Zod, ArkType)
  • Catch configuration errors at build time
  • Optionally validate at runtime for environment variable issues
  • Get full type safety in your components

Contribution

Local development
# Install dependencies
pnpm install

# Generate type stubs
pnpm run dev:prepare

# Develop with the playground
pnpm run dev

# Build the playground
pnpm run dev:build

# Run ESLint
pnpm run lint

# Run Vitest
pnpm run test
pnpm run test:watch

# Release new version
pnpm run release