What Causes This Error?
This error occurs when you try to access Nuxt’s Nitro server instance before it has been initialized. Nitro handles server-side rendering and API routes, but it’s not available immediately.
The Problem
// modules/my-module.ts
export default defineNuxtModule({
setup(options, nuxt) {
// ❌ Wrong - Nitro not ready yet
console.log(nuxt.options.nitro) // Might work
nuxt.server // Error! Server not initialized
}
})
The Fix
Wait for Nitro to Initialize
// modules/my-module.ts
export default defineNuxtModule({
setup(options, nuxt) {
// ✅ Use hooks to wait for Nitro
nuxt.hook('nitro:init', (nitro) => {
// Nitro is now available
console.log('Nitro initialized:', nitro.options.preset)
})
nuxt.hook('nitro:config', (nitroConfig) => {
// Modify Nitro config before initialization
nitroConfig.preset = 'node-server'
})
}
})
Nitro Lifecycle Hooks
export default defineNuxtModule({
setup(options, nuxt) {
// Before Nitro config is resolved
nuxt.hook('nitro:config', (nitroConfig) => {
// Modify config
nitroConfig.routeRules = {
'/api/**': { cors: true }
}
})
// After Nitro is initialized
nuxt.hook('nitro:init', (nitro) => {
// Access Nitro instance
console.log('Preset:', nitro.options.preset)
console.log('Output dir:', nitro.options.output.dir)
})
// Before Nitro build
nuxt.hook('nitro:build:before', (nitro) => {
console.log('Building Nitro...')
})
// After Nitro build
nuxt.hook('nitro:build:public-assets', (nitro) => {
console.log('Public assets ready')
})
}
})
Common Use Cases
Modify Server Routes
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('nitro:config', (nitroConfig) => {
// Add route rules
nitroConfig.routeRules = {
...nitroConfig.routeRules,
'/api/**': {
cors: true,
headers: {
'Access-Control-Allow-Origin': '*'
}
}
}
})
}
})
Add Server Plugins
import { createResolver } from '@nuxt/kit'
export default defineNuxtModule({
setup(options, nuxt) {
const resolver = createResolver(import.meta.url)
nuxt.hook('nitro:config', (nitroConfig) => {
nitroConfig.plugins = nitroConfig.plugins || []
nitroConfig.plugins.push(resolver.resolve('./runtime/server/plugin'))
})
}
})
Configure Presets
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('nitro:config', (nitroConfig) => {
// Set deployment preset
if (process.env.VERCEL) {
nitroConfig.preset = 'vercel'
} else if (process.env.NETLIFY) {
nitroConfig.preset = 'netlify'
}
})
}
})
Add Virtual Server Files
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('nitro:config', (nitroConfig) => {
nitroConfig.virtual = {
...nitroConfig.virtual,
'#my-module/config': `export default ${JSON.stringify(options)}`
}
})
}
})
Accessing Nitro Options
In nuxt.config.ts
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
// Direct Nitro configuration
preset: 'node-server',
compressPublicAssets: true,
routeRules: {
'/api/**': { cors: true }
},
storage: {
redis: {
driver: 'redis',
url: process.env.REDIS_URL
}
}
}
})
Reading Nitro Config
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('nitro:init', (nitro) => {
// Read final config
console.log('Storage:', nitro.options.storage)
console.log('Route rules:', nitro.options.routeRules)
console.log('Output:', nitro.options.output)
})
}
})
Dev Server Access
export default defineNuxtModule({
setup(options, nuxt) {
// Access dev server (development only)
nuxt.hook('listen', (server, { url }) => {
console.log(`Server running at ${url}`)
})
// Vite dev server
nuxt.hook('vite:serverCreated', (viteServer) => {
console.log('Vite server created')
})
}
})
Error Handling
export default defineNuxtModule({
setup(options, nuxt) {
nuxt.hook('nitro:init', (nitro) => {
try {
// Safe to access Nitro
doSomethingWithNitro(nitro)
} catch (error) {
console.error('Nitro error:', error)
}
})
}
})
Quick Checklist
- Don’t access Nitro directly in module setup
- Use
nitro:confighook to modify configuration - Use
nitro:inithook to access Nitro instance - Use nuxt.config.ts
nitrooption for static config - Handle both dev and production scenarios
- Check for dev-only features (like Vite server)