serve-static
Express-maintained middleware for serving static files over HTTP, with caching, ETags, and range-request support built in.
Repository Health
Technical Analysis
serve-static is the Node.js middleware that Express itself uses under express.static() to serve files straight from a directory on disk. Given a root folder and a request, it resolves the file, streams it to the response, and calls next() (rather than sending a 404) whenever no file matches, so it can be stacked with other middleware or used as a fallback in a routing chain.
Rather than reimplementing file streaming, it delegates the heavy lifting — range requests, conditional GETs, ETags, MIME typing — to the send package, and focuses its own logic on Express/Connect-style middleware wiring: option normalization, directory-listing behavior (redirect-to-trailing-slash or 404), dotfile handling, and error fall-through semantics. It ships as a single small file with no build step, making it one of the most widely depended-on packages in the Node.js ecosystem.
What You Get
- A single
serveStatic(root, options)factory that returns a standard(req, res, next)middleware function usable in Express, Connect, or vanillahttp.createServerhandlers - Built-in HTTP caching support — ETag, Last-Modified, Cache-Control with
maxAge/immutable, and conditional-request handling inherited fromsend - Configurable dotfile policy (
allow/deny/ignore) so requests for hidden files can be permitted, rejected, or treated as not found - Directory-request handling that either 301-redirects to a trailing slash and serves an index file, or falls through/404s when
redirectis disabled - A
setHeaders(res, path, stat)hook for attaching custom response headers per file (e.g. forcing downloads viaContent-Disposition) - Fall-through error semantics so a missing file calls
next()instead of terminating the request, letting multiple static roots or routes stack
Common Use Cases
- Serving a public/ or build/ folder of static assets (HTML, CSS, JS, images) from an Express app via
app.use(serveStatic(...)) - Stacking multiple static directories with fallback (e.g. an optimized-assets folder checked before a general public folder)
- Forcing file downloads instead of inline rendering by setting
Content-Dispositionthrough thesetHeadershook - Serving static files from a bare Node.js
http.createServerwithout pulling in a full framework - Applying different cache lifetimes per file type (e.g. no caching for HTML, long
maxAgefor hashed JS/CSS bundles)
Under The Hood
Architecture
The module is a single ~200-line file exporting one factory function, serveStatic(root, options), that returns a standard Express/Connect middleware (req, res, next). It delegates the actual file-serving and streaming logic entirely to the send package, acting as a thin adapter that wires send’s event-driven stream interface (directory, headers, error, file events) into Express’s fallthrough and error-forwarding conventions. Directory-listing behavior is implemented via two small closures — a redirect listener and a not-found listener — chosen once at setup based on the redirect option, keeping branching logic out of the hot request path. Each call to serveStatic() produces an independent middleware closure with no shared mutable state across requests, so if send’s streaming contract ever changed, this module would need a substantial rewrite since it holds no independent file-system logic of its own.
Tech Stack
Plain CommonJS Node.js (engine >= 18), with no build step or bundler — the package ships its raw source (index.js plus LICENSE) directly to npm. Runtime dependencies are all small, single-purpose utilities maintained by the same expressjs org: encodeurl, escape-html, parseurl, and send for the actual streaming. Development tooling is ESLint 7 with the standard config, Mocha for the test runner, nyc for coverage (reported to Coveralls), and supertest for HTTP-level integration assertions. No TypeScript or Flow — types aren’t checked statically anywhere in the codebase.
Code Quality
The test suite is an 883-line Mocha spec with 19 top-level describe blocks exercising nearly every option (dotfiles, etag, extensions, fallthrough, redirect, setHeaders, index, immutable, maxAge, acceptRanges) through real HTTP requests via supertest rather than mocks, giving thorough behavioral coverage. CI runs the suite through GitHub Actions with coverage reporting, and linting is enforced via npm run lint. Error handling is explicit: bad constructor arguments throw synchronous TypeErrors, and runtime stream errors are forwarded through a fallthrough/forwardError flag that decides whether to call next() or next(err). There is no static type system in place, so correctness relies entirely on the test suite and linter rather than compiler-enforced types.
API Design
The public surface is a single default export matching the exact Express/Connect middleware signature, so it drops into app.use() with no adapter code required. Options are a flat, well-documented object — each one explained with its default in the README — and the setHeaders(res, path, stat) hook is the sole extensibility point, letting callers customize per-file headers (like forcing downloads) without subclassing or a configuration DSL. Given the module’s small surface area, documentation is thorough: every option is explained with its default and behavior, backed by four runnable example snippets covering vanilla http, forced downloads, simple Express usage, multiple static roots, and per-extension cache policy.
Used by 4 apps in this directory
ClearFlask
Product Management · Community
Open-source feedback management and roadmap tool that lets product teams collect, prioritize, and respond to user input — with AI-powered summarization and full self-hosting control.
HeyForm
Forms Surveys · No Code Platforms
Open-source conversational form builder with AI generation, conditional logic, and 30+ integrations — self-host with full data ownership.
Silex
No Code Platforms · Design Tools
Free, open-source visual website builder that exports clean HTML/CSS — no lock-in, no subscription, host anywhere
Standard Notes
Note Taking
End-to-end encrypted notes and files — private by design, built to last, and fully self-hostable.