CommonJS + ESM library
Own the listener lifecycle.
Create isolated servers, inspect active Node listeners, serve custom responses, and extend the request lifecycle with hooks.
Imports
Use the singleton or create instances.
| Module style | Default | Named exports |
|---|---|---|
| CommonJS | require('node-http-server') | Server, Config, RefString |
| ESM | import server from 'node-http-server' | Server, Config, RefString |
const {Server}=require('node-http-server');
const server=new Server({root:'./public'});
server.deploy();import {Server} from 'node-http-server';
const server=new Server({root:'./public'});
server.deploy();new Server() when code may own more than one listener or needs independent configuration.Lifecycle
Deploy, observe readiness, close, redeploy.
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();
});| Step | Contract |
|---|---|
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. |
| Redeploy | The same instance may deploy again after close() resolves. |
ERR_SERVER_ALREADY_DEPLOYED. Await close() before reusing it. Omitted settings persist across later deployment overlays.Public members
Methods and state.
| Member | Returns | Use |
|---|---|---|
deploy(config?, callback?) | Server | Start the instance's listeners. |
close(callback?) | Promise<void> | Close every listener owned by the instance. |
address() | address object or null | Read the first active listener address. |
serve(request,response,body='',encoding='utf8') | Promise | Complete 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. |
config | Config | Read the instance's isolated active configuration. |
server | Node HTTP server or null | Access the active HTTP listener. |
secureServer | Node HTTPS server or null | Access the active HTTPS listener. |
lastError | Error or null | Last captured request, hook, stream, or logging failure. |
Parsed request data
Use text or original bytes.
| Member | Type | Value |
|---|---|---|
request.body | string | UTF-8 request body. |
request.bodyBuffer | Buffer | Original request bytes. |
request.uri | object | Parsed URL and query information. |
request.url | string | Processed request path. |
request.serverRoot | string | Selected 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.
| Hook | Arguments | When | Takeover |
|---|---|---|---|
onRawRequest | request,response,serve | Immediately after receipt, before body parsing. | Return truthy; supplied serve is the public safe serve path. |
onRequest | request,response,serve | After URL helpers and body forms are ready. | Return truthy; supplied serve is the public safe serve path. |
beforeServe | request,response,bodyRef,encodingRef,complete | Before a buffered response is sent. | Return truthy; complete is one-shot and does not re-enter beforeServe. |
afterServe | request,response | After the response finishes. | Observe; may return a Promise. |
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
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;
};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.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.
| Need | Call | Expected result |
|---|---|---|
| Generated text/JSON | await serve(request,response,body,'utf8') | Completes through beforeServe/afterServe. |
| Selected trusted file | await this.serveFile(filename,request,response) | Returns whether a file was served. |
| Low-level Node behavior | response.end(...) | Your hook owns headers/body and bypasses library completion hooks; return truthy to stop fallback. |
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.
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.