send

Streaming static file server library for Node.js with Range requests and conditional-GET caching support.

Library
npm
v1.2.1
811stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
49/100Fair
Development Activity16
Maintenance20
Community80
Maturity60
Momentum20

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
64/100Good
Architecture80
Code Quality85
Innovation40
Learning Curve50

send is the streaming file-transfer library that powers Express’s static file serving and countless other Node.js HTTP servers. It reads files from disk and pipes them directly into an HTTP response, handling the parts of the HTTP spec that are easy to get wrong: byte-range requests for partial content, conditional-GET negotiation (If-Match, If-None-Match, If-Modified-Since, If-Unmodified-Since), ETag generation, and correct Cache-Control headers.

Rather than serving whole directories itself, send exposes a low-level SendStream API — an EventEmitter you attach handlers to for directory listings, custom headers, and error responses — so higher-level modules like serve-static and framework static-file middleware can build directory-aware routing on top of it. Its focus stays narrow: stream one resolved path safely and efficiently, with security checks against path traversal and dotfile access built in.

What You Get

  • A send(req, path, options) function returning a pipeable SendStream for any HTTP response.
  • Built-in HTTP Range and conditional-GET support that passes strict spec-compliance tests.
  • Security defaults (dotfile handling, path traversal rejection) that protect against common static-file vulnerabilities.
  • An event API (headers, directory, file, error, stream, end) for layering custom behavior on top of the base stream.

Common Use Cases

  • Express and Connect static middleware - Framework authors use send as the streaming primitive underneath serve-static and similar static-file middleware, rather than reimplementing range/cache logic.
  • Custom static file servers - Node.js developers building a bespoke HTTP file server call send(req, path, opts).pipe(res) directly to get spec-correct range and caching support with minimal code.
  • Media streaming endpoints - Applications serving video or audio rely on send’s Range support so browsers and native players can seek within large files instead of downloading them whole.
  • CDN-fronted asset serving - Backends behind a CDN or reverse proxy configure maxAge/immutable through send so cache headers are set correctly at the origin, reducing repeat requests reaching the app server.

Under The Hood

Architecture The library is a single-file module (index.js, ~1000 lines) built around one class, SendStream, which extends Node’s core Stream via the pre-ES6 util.inherits pattern. The public API is a factory function send(req, path, options) returning a SendStream whose primary consumer-facing method is .pipe(res). Internally, pipe() orchestrates the whole request lifecycle: it resolves and sanitizes the path (rejecting .. traversal via a dedicated regexp and enforcing root-relative resolution), delegates to sendIndex/sendFile/stream methods that stat the file, determine conditional-GET freshness (isConditionalGET, isFresh, isRangeFresh, isPreconditionFailure, notModified), set response headers (etag, Last-Modified, Cache-Control) via setHeader, then create a filesystem ReadStream scoped to the parsed Range and pipe it to the response, cleaning up via the on-finished package. There is no dependency injection or plugin system — behavior is customized entirely through EventEmitter hooks (headers, directory, file, stream, error) attached before calling .pipe(). Downstream consumers like serve-static and Express’s static middleware depend on both its public methods and its emitted events, so any restructuring of the resolve-stat-stream pipeline would ripple outward.

Tech Stack Plain CommonJS with no TypeScript and no build step — the package ships index.js directly per the files field in package.json. Runtime dependencies are small, focused utility packages: debug, encodeurl, escape-html, etag, fresh (conditional-GET matching), http-errors, mime-types, ms (duration parsing), on-finished, range-parser, and statuses. There is no web framework or ORM here — this package is itself a low-level primitive that frameworks build on. Testing uses mocha with supertest and nyc for coverage; linting uses eslint with eslint-config-standard. CI runs via GitHub Actions across a Node engines >= 18 matrix.

Code Quality The test suite (test/send.js) is larger than the module it tests, covering nearly every option, header interaction, and edge case — range parsing, malformed ranges, dotfile handling, extension fallback, precondition failures — through real HTTP requests against fixture files. There is no type system; errors are surfaced via http-errors for typed HTTP status codes, and stream/callback code follows conventional Node error-first patterns with explicit stat-error handling for cases like ENOENT and EACCES. Naming follows a consistent underscore-private-field convention with JSDoc-style comments throughout, and CI enforces both linting and coverage-tracked testing on every push and pull request.

What Makes It Unique send doesn’t introduce novel algorithms — HTTP range and conditional-GET handling are well-established parts of the HTTP spec — but it has become the de facto reference implementation that Express’s serve-static and most Node static-file middleware build on, valued for correctness on edge cases rather than new capability. Its narrow scope, a single-file streaming primitive rather than a full static-file server, is a deliberate design choice that keeps it embeddable inside other tools instead of competing with them.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search