Imports

Use the singleton or create instances.

Node.js module entries: CommonJS and ESM are Node.js module entry points, not browser entry points. These bare package imports resolve through Node or a Node-targeted bundler; they are not native-browser imports and do not use an import map.
Module styleDefaultNamed exports
CommonJSrequire('node-http-server')Server, Config, RefString
Node.js ESMimport server from 'node-http-server'Server, Config, RefString
CommonJS · isolated instance
const {Server}=require('node-http-server');

const server=new Server({root:'./public'});
server.deploy();
Node.js ESM · isolated instance
import {Server} from 'node-http-server';

const server=new Server({root:'./public'});
server.deploy();
Compatibility: the default export is the original shared singleton. Prefer new Server() when code may own more than one listener or needs independent configuration.

Lifecycle

Deploy, observe readiness, close, redeploy.

Node.js ESM · readiness and shutdown
import {Server} from 'node-http-server';

const server=new Server({root:'./public',port:8080});

server.deploy((instance,nodeServer)=>{
    console.log(nodeServer.address());
});

process.once('SIGTERM',async()=>{
    await server.close();
});
StepContract
new Server(config?)Creates isolated configuration and listener state.
deploy(config?, callback?)Overlays current config, starts HTTP and optional HTTPS, returns the same instance immediately, and calls the callback once as each listener becomes ready. A function first argument is accepted as the callback.
close(callback?)Returns a Promise that resolves after every owned listener closes. HTTP/2 sessions close gracefully after their active streams finish. Concurrent calls share it; idle close is safe; callback receives no arguments or an error.
RedeployThe same instance may deploy again after close() resolves.
One active deployment per instance: a second active deployment throws ERR_SERVER_ALREADY_DEPLOYED. Await close() before reusing it. Omitted settings persist across later deployment overlays.

Public members

Methods and state.

MemberReturnsUse
deploy(config?, callback?)ServerStart the instance's listeners.
close(callback?)Promise<void>Close every listener owned by the instance.
address()address object or nullRead the first active listener address.
serve(request,response,body='',encoding='utf8')PromiseComplete a deliberate response through hooks; defaults to text/plain, honors HEAD and Content-Length.
serveFile(filename,request,response)Promise<boolean>Serve a deliberate trusted file; legacy (filename,exists,request,response) remains accepted.
configConfigRead the instance's isolated active configuration.
serverNode HTTP server or nullAccess the active HTTP listener.
secureServerNode Http2SecureServer, https.Server, or nullAccess the active HTTPS listener. HTTP/2 with HTTP/1.1 negotiation is the default; https.http2:false selects the original https.Server.
lastErrorError or nullLast captured request, hook, stream, HTTP/2 session, or logging failure.

Parsed request data

Use text or original bytes.

MemberTypeValue
request.bodystringUTF-8 request body.
request.bodyBufferBufferOriginal request bytes.
request.uriobjectParsed URL and query information.
request.urlstringProcessed request path.
request.serverRootstringSelected static root after Host routing.

When maxRequestBodyBytes is set and the request crosses it, parsing stops with 413 Payload Too Large.

HTTP/2 request bodies are read through the request stream even without Content-Length, and the complete body forms reach onRequest. Virtual-host routing uses HTTP/2 :authority or HTTP/1 Host values to select request.serverRoot.

Hooks

Take over only the step you need.

Hooks receive native Node request/response objects for the negotiated protocol, including Node's HTTP/2 compatibility objects when HTTPS selects HTTP/2. Use public methods such as response.setHeader() and response.end(), or the supplied serve continuation. HTTP/2 streams cannot use raw HTTP/1 socket writes or connection-specific headers such as Connection and Transfer-Encoding. request.httpVersionMajor identifies the request protocol. See Node's compatibility API for protocol-specific behavior.

HookArgumentsWhenTakeover
onRawRequestrequest,response,serveImmediately after receipt, before body parsing.Return truthy; supplied serve is the public safe serve path.
onRequestrequest,response,serveAfter URL helpers and body forms are ready.Return truthy; supplied serve is the public safe serve path.
beforeServerequest,response,bodyRef,encodingRef,completeBefore a buffered response is sent.Return truthy; complete is one-shot and proceeds directly to response completion.
afterServerequest,responseAfter the response finishes.Observe; may return a Promise.
Node.js ESM · JSON health route plus static files
import {Server} from 'node-http-server';

class AppServer extends Server{
    async onRequest(request,response,serve){
        if(request.url!='/health') return false;

        response.setHeader('Content-Type','application/json');
        await serve(request,response,JSON.stringify({ok:true}));
        return true;
    }
}

new AppServer({root:'./public'}).deploy();

Rewrite a buffered text file safely

JavaScript · Buffer-aware beforeServe
server.beforeServe=function(request,response,bodyRef){
    if(!Buffer.isBuffer(bodyRef.value)) return false;

    const text=bodyRef.value.toString('utf8');
    bodyRef.value=Buffer.from(text.replaceAll('{{mode}}','preview'));
    return false;
};
Buffering cost: defining a custom beforeServe buffers every static file and bypasses normal streaming/automatic compression. Static file bodies arrive as Buffers; convert explicitly before string replacement. RefString remains exported for this compatibility shape.
Completion boundary: afterServe runs for library completion paths. A hook that calls response.end() directly bypasses it. Use and await the supplied serve function when completion observation matters.

Manual serving

Respond from a hook without replacing the server.

Call and await the supplied safe serve continuation for generated content. Use serveFile() only when custom routing selects a deliberate trusted file. Both preserve the server's response/error lifecycle.

NeedCallExpected result
Generated text/JSONawait serve(request,response,body,'utf8')Completes through beforeServe/afterServe.
Selected trusted fileawait this.serveFile(filename,request,response)Returns whether a file was served.
Low-level Node behaviorresponse.end(...)Your hook owns headers/body and bypasses library completion hooks; return truthy to stop fallback.
Trusted filenames only: serveFile() accepts the caller-provided filename verbatim and deliberately bypasses automatic dotfile routing policy. Resolve and validate application-selected files before passing them to it.

Error contract

Listener errors remain native Node events.

CommonJS · bind failure handler
const {Server}=require('node-http-server');
const server=new Server({root:'./public'});

server.deploy();
server.server.once('error',error=>{
    console.error(error);
});

lastError captures request, hook, stream, HTTP/2 session, and logging failures. Node listener failures arrive through the listener's error event. Attach handlers to both server.server and server.secureServer when both protocols run. Synchronous deployment validation—invalid roots, ports, timeout values, or incomplete HTTPS configuration—throws before a usable listener is ready.