Imports

Use the singleton or create instances.

Module styleDefaultNamed exports
CommonJSrequire('node-http-server')Server, Config, RefString
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();
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.

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. Concurrent calls share it; idle close is safe; callback receives no arguments or an error.
RedeployThe same instance may deploy again after close() resolves.
Do not deploy twice: deploying an already active instance 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 HTTPS server or nullAccess the active HTTPS listener.
lastErrorError or nullLast captured request, hook, stream, 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.

Hooks

Take over only the step you need.

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 does not re-enter beforeServe.
afterServerequest,responseAfter the response finishes.Observe; may return a Promise.
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() does not root-contain an arbitrary caller-provided filename and deliberately bypasses automatic dotfile routing policy. Never pass raw request input into it; resolve and validate application-selected files yourself.

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 is for captured request, hook, stream, and logging failures. It does not replace the Node 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.