← Back to articles

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

CategoryPackages
ServerNitro, H3, listhen (dev server), serve-placeholder
Fetchofetch, httpxy (proxy)
Configc12, defu, rc9, dotenv
Path/URLpathe, ufo, mlly (module resolution)
Buildunbuild, mkdist, jiti (runtime TS)
CLIcitty, consola
Storageunstorage
Runtimeunenv, std-env, unimport
Utilitydestr (safe JSON parse), ohash (hashing), scule (string case), unctx (async context)
Releasechangelogen, pkg-types

When to Use UnJS vs Alternatives

NeedUnJSAlternative
HTTP serverH3 / NitroExpress, Fastify, Hono
Fetch wrapperofetchaxios, ky, got
CLI frameworkcittycommander, yargs, oclif
Config loadingc12cosmiconfig
Loggingconsolapino, winston
Build toolunbuildtsup, rollup
Path utilspatheNode.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:

  1. ofetch — Replace axios/got with a universal fetch wrapper
  2. consola — Better logging everywhere
  3. defu — Stop writing manual config merging
  4. H3 — For your next API server
  5. 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.

Get AI tool guides in your inbox

Weekly deep-dives on the best AI coding tools, automation platforms, and productivity software.