Open-Source Wikis

/

Express

/

Features

/

Static files

expressjs/express

Static files

Active contributors: dougwilson, wesleytodd, ulisesgascon

Express has two paths for serving files:

  • express.static(root, [opts]) — middleware that serves a directory.
  • res.sendFile(path, [opts], [cb]) — explicit per-request file streaming.

Both are powered by the send package; express.static is a direct re-export of serve-static, which itself wraps send.

express.static

// lib/express.js (excerpt)
exports.static = require('serve-static');

Usage:

app.use(express.static('public'));
app.use('/assets', express.static(path.join(__dirname, 'public')));

serve-static walks a request URL path under the given root, calls send(req, pathname, opts) to stream the file, and forwards anything else to next(). Notable options:

  • dotfiles'allow' / 'deny' / 'ignore' (default).
  • etag — boolean (default true).
  • extensions — list of fallback extensions to try (e.g., ['html']).
  • index — directory index file (default 'index.html', or false to disable).
  • lastModified — sends Last-Modified (default true).
  • maxAgeCache-Control: max-age in milliseconds.
  • redirect — redirect bare directories to dir/ (default true).
  • setHeaders(res, path, stat) — hook to inject custom headers.

Because Express simply re-exports serve-static, every option in the serve-static README applies.

res.sendFile

res.sendFile is implemented in lib/response.js and delegates to the send package directly. The Express layer:

  1. Validates that path is a non-empty string and either absolute or accompanied by opts.root. Throws TypeError otherwise.
  2. URL-encodes the pathname.
  3. Sets opts.etag from app.enabled('etag') so the streamed file uses the same ETag policy as res.send.
  4. Calls send(req, encodedPath, opts) and pipes the resulting stream to the response.
  5. Wires events: directory → callback with EISDIR; error → callback; abortedECONNABORTED; finished → success.

Flow

sequenceDiagram
    participant Caller
    participant Res as res.sendFile
    participant Send as send package
    participant FS as filesystem
    participant Sock as response

    Caller->>Res: res.sendFile(path, opts, cb)
    Res->>Res: validate
    Res->>Send: send(req, encodeURI(path), opts)
    Send->>FS: stat + open
    FS-->>Send: stream
    Send->>Sock: pipe(res)
    Sock-->>Res: 'finished' / 'aborted' / 'directory' / 'error'
    Res-->>Caller: cb(err?)

res.download

res.download(path, [name], [opts], [cb]) is a thin wrapper on top of res.sendFile. It:

  1. Sets Content-Disposition: attachment; filename=... using the content-disposition package.
  2. Merges user-provided headers (without overriding the disposition).
  3. Resolves the path to absolute when no opts.root was given.
  4. Calls res.sendFile(fullPath, opts, cb).
app.get('/report.pdf', (req, res) => {
  res.download('/var/reports/report-2026-04.pdf', 'monthly-report.pdf');
});

Caching and ETag

For both express.static and res.sendFile, the send package generates an ETag (when enabled) and a Last-Modified header from the file's mtime. On a subsequent request with If-None-Match or If-Modified-Since, the fresh package decides freshness and send returns 304 with no body.

The Express-level 'etag' setting (which controls in-memory ETag generation in res.send) is forwarded to send for res.sendFile (added explicitly in 5.1).

Common pitfalls

  • Relative path without root in res.sendFile throws. Always use absolute paths or pass opts.root.
  • Dotfiles: by default, serve-static ignores them. Pass dotfiles: 'allow' if you really want to serve them.
  • Directory traversal: send blocks .. outside the configured root. Don't try to roll your own escape hatch.
  • Large files: streams are piped, so memory is bounded — but Content-Length must be set by send. If you want to add custom headers, use setHeaders (for serve-static) or opts.headers (for res.sendFile).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Static files – Express wiki | Factory