Node Server

Node.js HTTP server adapter with optimized request/response handling.

@miiajs/node-server provides a high-performance Node.js HTTP server adapter for MiiaJS.

Installation

bun add @miiajs/node-server

Usage

import { Miia } from '@miiajs/core'
import { serve } from '@miiajs/node-server'

const app = new Miia().register(AppModule)

await app.listen(3000, serve)

With custom hostname:

await app.listen(3000, 'localhost', serve)

How it works

The serve function bridges Node.js's http.IncomingMessage/http.ServerResponse and the Web Standard Request/Response API that MiiaJS uses internally.

Performance modes

The adapter supports two modes:

Optimized mode (default)

Minimizes allocations on the hot path:

  • Lazy Request Proxy — lightweight object instead of new Request(). Method, URL, headers, and body are resolved only on first access.
  • Lightweight Headers — linear scan over raw header pairs instead of constructing a Headers object. Covers .get(), .has(), .forEach(), and iterators.
  • Body Buffering — small POST bodies (Content-Length ≤ bufferThreshold) are buffered and parsed directly, bypassing ReadableStream and Request creation. Large or chunked bodies fall back to streaming via Readable.toWeb().
  • LightResponse Cache — simple responses (string, null, Uint8Array) store a [status, body, headers] tuple without creating a real Response object.
  • Sync Fast Path — synchronous handlers bypass Promise allocation entirely.

Native mode

Full Web API compliance with standard Request and Response objects:

import { serve } from '@miiajs/node-server'

const server = await serve({
  fetch: app.fetch,
  port: 3000,
  mode: 'native',
})

Use native mode when you need strict instanceof Response checks or run multiple frameworks in the same process.

Standalone usage

The adapter can be used without the MiiaJS framework:

import { serve } from '@miiajs/node-server'

const server = await serve({
  fetch: (req) => new Response('Hello, World!'),
  port: 3000,
  hostname: '0.0.0.0',
})

// Later...
await server.close()

Options

interface ServeOptions {
  fetch: (req: Request) => Response | Promise<Response>  // Required
  port?: number              // Default: 3000
  hostname?: string          // Default: '0.0.0.0'
  mode?: 'optimized' | 'native'  // Default: 'optimized'
  bufferThreshold?: number   // Default: 102400 (100KB)
}

The bufferThreshold controls the body buffering optimization in optimized mode. POST/PUT/PATCH bodies with a known Content-Length up to this size are buffered in memory for fast json()/text() access. Bodies without Content-Length or larger than the threshold use streaming via Readable.toWeb().

ServerHandle

The serve function returns a ServerHandle with a close() method:

const server = await serve({ fetch: handler, port: 3000 })

// Graceful shutdown
await server.close()