UnJS Ecosystem Guide (2026): Every Package You Should Know
UnJS is a collection of universal JavaScript utilities that powers Nuxt, Nitro, and increasingly the broader JS ecosystem. These are the building blocks that framework authors use — and that you should know about.
What is UnJS?
UnJS (Universal JavaScript) is a collection of ~60 packages maintained by the Nuxt team and community. Each package solves one thing well, works everywhere (Node.js, Deno, Bun, Cloudflare Workers, browsers), and has zero or minimal dependencies.
Think of it as the standard library JavaScript never got.
The Essential Packages
Nitro — Universal Server Engine
Nitro is a server engine that deploys to any platform: Node.js, Deno, Bun, Cloudflare Workers, Vercel, Netlify, AWS Lambda, and more.
Key features:
- File-based routing (API routes)
- Hot module replacement in development
- Auto-imports
- Built-in storage layer (KV, filesystem, Redis, etc.)
- Scheduled tasks (cron)
- WebSocket support
- Builds to a single output for any deployment target
Use it when: You want a backend/API server that deploys anywhere without code changes.
// server/routes/hello.ts
export default defineEventHandler(() => {
return { message: 'Hello from Nitro!' }
})
H3 — Minimal HTTP Framework
H3 is the HTTP framework underneath Nitro. Think of it as a modern, lightweight Express alternative.
Key features:
- Tiny (~2KB)
- Works on any JS runtime
- Composable event handlers
- Built-in body parsing, cookies, headers
- WebSocket support
- Type-safe utilities
Use it when: You want a minimal HTTP framework without Express's baggage.
import { createApp, defineEventHandler, createRouter } from 'h3'
const app = createApp()
const router = createRouter()
router.get('/api/users', defineEventHandler(async (event) => {
const query = getQuery(event)
return { users: [], page: query.page }
}))
app.use(router)
ofetch — Universal Fetch
ofetch wraps the Fetch API with smart defaults and works everywhere.
Key features:
- Auto-parses JSON responses
- Auto-stringifies JSON request bodies
- Interceptors (onRequest, onResponse, onError)
- Automatic retries
- Timeout support
- Base URL support
- Works in Node.js, Deno, Bun, and browsers
Use it when: You want fetch but better.
import { ofetch } from 'ofetch'
// Simple — auto-parses JSON
const data = await ofetch('/api/users')
// With options
const user = await ofetch('/api/users', {
method: 'POST',
body: { name: 'Alice' },
retry: 3,
timeout: 5000,
})
consola — Beautiful Console Logger
consola provides a consistent, beautiful logging experience across environments.
Key features:
- Styled log levels (info, warn, error, success, debug)
- Fancy reporter (colored, boxed output in terminals)
- Browser-compatible
- Pluggable reporters
- Prompt utilities (confirm, select, text input)
- Spam prevention (throttles repeated messages)
import { consola } from 'consola'
consola.info('Starting server...')
consola.success('Server running on port 3000')
consola.error('Database connection failed')
consola.box('Application Ready 🚀')
c12 — Smart Configuration
c12 loads configuration from multiple sources with smart defaults, environment overrides, and TypeScript support.
Key features:
- Loads from
.config/files,package.json, environment variables - TypeScript config files supported
- Deep merging of multiple config sources
- Default values
- Config watching (reload on changes)
- Extends/layers (inherit from other configs)
Use it when: Your app needs configuration from files, env vars, and defaults — merged intelligently.
defu — Deep Defaults
defu assigns default values to objects, deeply and recursively. Essential for merging configuration.
import { defu } from 'defu'
const config = defu(userConfig, {
server: { port: 3000, host: 'localhost' },
database: { url: 'postgres://localhost:5432/app' },
})
// User values preserved, defaults fill gaps
pathe — Cross-Platform Path
pathe is a drop-in replacement for Node.js path that normalizes paths to POSIX format everywhere.
Use it when: You want consistent path handling across Windows/Mac/Linux without path separator headaches.
ufo — URL Utilities
ufo provides URL parsing and manipulation utilities.
import { parseURL, joinURL, withQuery } from 'ufo'
joinURL('/api', 'users', '123') // '/api/users/123'
withQuery('/search', { q: 'hello', page: 1 }) // '/search?q=hello&page=1'
unenv — Universal Environment
unenv provides polyfills and mocking for Node.js built-ins, making Node.js code work in edge runtimes and browsers.
Use it when: You need Node.js code to run on Cloudflare Workers, Deno Deploy, or in the browser.
unstorage — Universal Storage
unstorage provides a unified storage API that works with any backend: filesystem, Redis, Cloudflare KV, S3, memory, HTTP, and more.
import { createStorage } from 'unstorage'
import fsDriver from 'unstorage/drivers/fs'
const storage = createStorage({
driver: fsDriver({ base: './data' })
})
await storage.setItem('user:1', { name: 'Alice' })
const user = await storage.getItem('user:1')
Switch drivers without changing code — develop with filesystem, deploy with Redis or KV.
unbuild — Build Tool
unbuild is a zero-config build tool for TypeScript packages. It produces ESM and CJS output with type declarations.
Use it when: You're publishing an npm package and want automatic builds from your TypeScript source.
citty — CLI Framework
citty creates beautiful CLI applications with type-safe argument parsing.
import { defineCommand, runMain } from 'citty'
const main = defineCommand({
meta: { name: 'my-cli', description: 'My CLI tool' },
args: {
name: { type: 'positional', description: 'Your name' },
greeting: { type: 'string', default: 'Hello' },
},
run({ args }) {
console.log(`${args.greeting}, ${args.name}!`)
},
})
runMain(main)
hookable — Hook/Plugin System
hookable provides a lightweight hook system for making libraries extensible.
Use it when: You want to add a plugin/middleware system to your library or framework.
changelogen — Changelog Generator
changelogen generates changelogs from conventional commits. Used by the entire UnJS ecosystem for releases.
The Full Package Map
| Category | Packages |
|---|---|
| Server | Nitro, H3, listhen (dev server), serve-placeholder |
| Fetch | ofetch, httpxy (proxy) |
| Config | c12, defu, rc9, dotenv |
| Path/URL | pathe, ufo, mlly (module resolution) |
| Build | unbuild, mkdist, jiti (runtime TS) |
| CLI | citty, consola |
| Storage | unstorage |
| Runtime | unenv, std-env, unimport |
| Utility | destr (safe JSON parse), ohash (hashing), scule (string case), unctx (async context) |
| Release | changelogen, pkg-types |
When to Use UnJS vs Alternatives
| Need | UnJS | Alternative |
|---|---|---|
| HTTP server | H3 / Nitro | Express, Fastify, Hono |
| Fetch wrapper | ofetch | axios, ky, got |
| CLI framework | citty | commander, yargs, oclif |
| Config loading | c12 | cosmiconfig |
| Logging | consola | pino, winston |
| Build tool | unbuild | tsup, rollup |
| Path utils | pathe | Node.js path |
Choose UnJS when: You want universal runtime support, minimal dependencies, and modern ESM-first design. UnJS packages are typically smaller and more focused than alternatives.
FAQ
Do I need Nuxt to use UnJS?
No. Every UnJS package is standalone. Nuxt uses them, but they work independently in any JavaScript project.
Are UnJS packages production-ready?
Yes. They power Nuxt, which is used by thousands of production applications. Many individual packages have millions of weekly npm downloads.
Should I replace Express with H3?
If starting a new project, H3 (or Nitro) is worth considering — smaller, faster, and universal. For existing Express apps, migration is optional and incremental.
How does Nitro compare to Next.js API routes?
Nitro is a standalone server engine. Next.js API routes are tied to the Next.js framework. Nitro deploys anywhere, supports more runtimes, and has built-in features (storage, caching, tasks) that Next.js API routes don't.
The Bottom Line
UnJS gives you the building blocks that framework authors use, without the framework lock-in. Start with:
- ofetch — Replace axios/got with a universal fetch wrapper
- consola — Better logging everywhere
- defu — Stop writing manual config merging
- H3 — For your next API server
- Nitro — When you want deploy-anywhere server infrastructure
These packages are small, focused, and dependency-free. Add them individually as needed — that's the whole point.