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

nuxt-safe-runtime-config

v0.1.1

Published

Validate Nuxt runtime config with Standard Schema at build time

Readme

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 typesuseSafeRuntimeConfig() 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
  • 🔐 Shelve integration — fetch secrets from Shelve and merge into runtime config

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:

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

const runtimeConfigSchema = object({
  public: object({
    apiBase: string(),
    appName: optional(string()),
  }),
  databaseUrl: string(),
  secretKey: string(),
  port: optional(number()),
})
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(),
})
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

| Option | Type | Default | Description | | ------------------- | ------------------------------- | ----------------- | ------------------------------------------ | | $schema | StandardSchemaV1 | — | Your validation schema (required) | | validateAtBuild | boolean | true | Validate during dev/build | | validateAtRuntime | boolean | false | Validate 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 | | logSuccess | boolean | true | Log successful validation | | logFallback | boolean | true | Log when using JSON Schema fallback | | jsonSchemaTarget | string | 'draft-2020-12' | JSON Schema version for runtime validation | | shelve | boolean \| ShelveOptions | undefined | Shelve secrets integration (see below) |

Shelve Integration

Shelve is a secrets management service. This module fetches secrets from Shelve at build time and merges them into your runtime config before validation.

Zero-Config Setup

If you have a shelve.json file in your project root, the integration enables automatically:

export default defineNuxtConfig({
  safeRuntimeConfig: {
    $schema: runtimeConfigSchema,
    shelve: true, // Auto-detects project, team, and environment
  },
})

The module resolves configuration from multiple sources (highest priority first):

| Config | Sources | | ----------- | ---------------------------------------------------------------------- | | project | nuxt.configSHELVE_PROJECTshelve.jsonpackage.json name | | slug | nuxt.configSHELVE_TEAM_SLUGshelve.json | | environment | nuxt.configSHELVE_ENVshelve.json → dev mode auto | | token | SHELVE_TOKEN~/.shelve file |

Explicit Configuration

You can override any auto-detected value:

export default defineNuxtConfig({
  safeRuntimeConfig: {
    $schema: runtimeConfigSchema,
    shelve: {
      project: 'my-app',
      slug: 'my-team',
      environment: 'production',
      url: 'https://app.shelve.cloud', // Self-hosted Shelve
      fetchAtBuild: true, // Default: fetch at build time
      fetchAtRuntime: false, // Opt-in: fetch on server cold start
    },
  },
})

Variable Transformation

Shelve variables transform from SCREAMING_SNAKE_CASE to camelCase with smart grouping:

DATABASE_URL           → databaseUrl
GITHUB_CLIENT_ID       → github.clientId (grouped)
GITHUB_CLIENT_SECRET   → github.clientSecret (grouped)
PUBLIC_API_URL         → public.apiUrl

Variables with repeated prefixes (2+ keys) nest automatically. PUBLIC_* and NUXT_PUBLIC_* map to runtimeConfig.public.

Runtime Fetch (Opt-in)

For dynamic environments or secret rotation, enable runtime fetching:

export default defineNuxtConfig({
  safeRuntimeConfig: {
    shelve: {
      fetchAtBuild: true, // Bake secrets into build
      fetchAtRuntime: true, // Also refresh on cold start
    },
  },
})

The runtime plugin runs before validation, so freshly fetched secrets are validated against your schema.

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 { configs } from 'nuxt-safe-runtime-config/eslint'

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

Or configure manually:

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

export default [
  {
    plugins: { 'safe-runtime-config': plugin },
    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

# 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