NuxtHub

NuxtHub Storage

Self-hosted log retention for evlog using NuxtHub database storage. Store, query, and automatically clean up your structured logs with zero external dependencies.

@evlog/nuxthub stores your evlog wide events directly in your NuxtHub database. No external logging service needed — your logs live next to your data, with automatic cleanup based on a retention policy.

Why Self-Hosted Logs?

External logging services (Axiom, Datadog, etc.) are great for production at scale. But sometimes you want:

  • Zero external dependencies — logs stored in the same database as your app
  • Full data ownership — no third-party access to your log data
  • Free tier friendly — no per-event pricing, just your existing database
  • Development & staging — full log visibility without paying for a service

@evlog/nuxthub works as a drop-in drain. Your existing evlog setup stays the same — you just get a database-backed storage layer on top.

Install

pnpm add @evlog/nuxthub

Or with nuxi:

npx nuxi module add @evlog/nuxthub

Setup

Add the module to your nuxt.config.ts:

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@evlog/nuxthub'],

  evlog: {
    retention: '7d',
  },
})

That's it. The module automatically:

  1. Installs evlog/nuxt and @nuxthub/core if not already registered
  2. Registers the evlog_events database schema with NuxtHub
  3. Hooks into evlog:drain to store every event in the database
  4. Schedules a cleanup task based on your retention policy
Prerequisites: Your project must use NuxtHub with a database configured. @evlog/nuxthub uses Drizzle ORM to interact with the database.

How It Works

Request → evlog wide event → evlog:drain hook → INSERT into evlog_events table
                                                          ↓
                          Cron task (automatic) → DELETE events older than retention

Every wide event emitted by evlog is stored as a row in the evlog_events table. The drain plugin handles both single events and batches (when used with the pipeline).

Database Schema

The evlog_events table stores indexed columns for fast querying and a data JSON column for all remaining fields:

ColumnTypeDescription
idtextUUID primary key
timestamptextEvent timestamp
leveltextLog level (info, warn, error, debug)
servicetextService name
environmenttextEnvironment (production, staging, etc.)
methodtextHTTP method
pathtextRequest path
statusintegerHTTP status code
duration_msintegerRequest duration in milliseconds
request_idtextRequest correlation ID
sourcetextEvent source (server, client)
errortextError details (JSON string)
datatextAll remaining event fields (JSON)
created_attextRow insertion timestamp

Indexed columns: timestamp, level, service, status, request_id, created_at.

Dialect Support

The schema is automatically registered for your NuxtHub database dialect:

  • SQLite (default for Cloudflare D1)
  • MySQL
  • PostgreSQL

The correct schema is selected via the hub:db:schema:extend hook based on your NuxtHub configuration.

Combining with External Adapters

@evlog/nuxthub doesn't replace external adapters — you can use both. The module registers its own evlog:drain hook, so any other drain plugins you have will still work:

server/plugins/evlog-drain.ts
import { createAxiomDrain } from 'evlog/axiom'

export default defineNitroPlugin((nitroApp) => {
  // This runs alongside @evlog/nuxthub's built-in drain
  nitroApp.hooks.hook('evlog:drain', createAxiomDrain())
})

Next Steps

Copyright © 2026