Tiny JavaScript Server

Usage no npm install needed!

<script type="module">
  import nuxtH2 from 'https://cdn.skypack.dev/@nuxt/h2';


d v b a c

h2 - Tiny JavaScript Server


  • Works perfectly with Serverless, Workers and NodeJS
  • Compatible with connect/express middleware
  • Tree-shakable and zero-dependency
  • Promise and aync/await support
  • Lazy loading
  • Quick prefix router
  • Custom route matcher

See un for workers support


yarn add @nuxt/h2
# or
npm install @nuxt/h2


Using listhen:

const { createApp } = require('@nuxt/h2')
const { listen } = require('listhen')

const app = createApp()
app.use('/', () => 'Hello world!')


Using plain node:

const { Server } = require('http')
const { createApp } = require('@nuxt/h2')

const app = createApp()

// Handle can directly return object or Promise<object> for JSON response
app.use('/api', (req) => ({ url: req.url }))

// You can have better matching other than quick prefix match
app.use('/odd', () => 'Is odd!', { match: url => url.substr(1) % 2 })

// Handle can directly return string for HTML response
app.use(() => '<h1>Hello world!</h1>')

// You can chain calls to .use()
app.use('/1', () => '<h1>Hello world!</h1>').use('/2', () => '<h1>Goodbye!</h1>')

// If handle is already async, using useAsync to avoid unnecessary promisify wrapper
// (Shortcut to pass { promisify: false })
// app.useAsync(async () => {})

// Lazy loading routes using { lazy: true }
// app.use('/big', () => import('./big'), { lazy: true })

const port = process.env.PORT || 3000
const server = new Server(app)

server.listen(port, () => {
  console.log(`Listening on: http://localhost:${port}`)


There are two vital parts that make it working: Stack Runner (App), and promisifyHandle.


App is basically a http server handle with req, res and attached utilities that runs a stack of middleware/handles in parallel. It will stop when the writableEnded flag is set on a response (which means that res.end has been called) and throw a 404 if writableEnded flag has not been set by the end.

Additionally the app has a quick prefix matcher and will automatically call res.end if any stack layers return a value.


Converts a classic middleware (req, res, next?) into a promisified version ready to use with App

  • If middleware has 3rd next/callback param, promise will resolve/reject when called
  • If middleware returns a promise, it will be chained to main promise
  • If calling middleware throws an immediate error, promise will be rejected
  • On close and error events of res, promise will resolve/reject (to ensure if middleware simply calls res.end)

When calling app.use, middleware will be automatically promisified.

If you are already making an async aware middleware, you can use app.useAsync