Skip to content
oRPC
Esc
navigateopen⌘Jpreview
On this page

Static File Plugin

Serve static files alongside your procedures, with ETag caching, range requests, single page application fallback, and directory traversal protection.

Installation

npm install @orpc/node@beta
pnpm add @orpc/node@beta
yarn add @orpc/node@beta
bun add @orpc/node@beta

Setup

Use StaticFileHandlerPlugin to serve a directory alongside your procedures. Files are only served when no procedure matches a GET or HEAD request, so procedures always take precedence.

import { StaticFileHandlerPlugin } from '@orpc/node'
import { RPCHandler } from '@orpc/server/node'

const handler = new RPCHandler(router, {
  plugins: [
    new StaticFileHandlerPlugin({
      /**
       * The directory files are served from. Resolved against the working
       * directory when relative.
       */
      rootDir: './public',

      /**
       * The URL path files are served under, appended to the handler prefix
       * when one is set.
       *
       * @default '/'
       */
      path: '/',

      /**
       * The file served when the request path resolves to a directory.
       * Set to `false` to disable directory index files.
       *
       * @default 'index.html'
       */
      indexFile: 'index.html',

      /**
       * A file served with status 200 when no file matches the request path,
       * relative to `rootDir`. Useful for single page application routing.
       *
       * @default undefined
       */
      fallbackFile: 'index.html',

      /**
       * The `Cache-Control` response header value. Set to `false` to omit the header.
       *
       * @default 'public, max-age=0'
       */
      cacheControl: 'public, max-age=0',

      /**
       * Whether files and directories whose name starts with a dot can be served.
       *
       * @default false
       */
      dotfiles: false,

      /**
       * Whether precompressed `.br`, `.zst`, and `.gz` sidecar files can be served
       * when the client accepts their encoding.
       *
       * @default false
       */
      precompressed: false,

      /**
       * Whether symbolic links whose target lies outside `rootDir` can be served.
       * Enabling this exposes every file those links reach.
       *
       * @default false
       */
      allowSymlinks: false,

      /**
       * Extra content types keyed by lowercase file extension without the dot,
       * merged over the built-in detection. Unrecognised extensions are served
       * as `application/octet-stream`.
       */
      mimeTypes: {},
    }),
  ],
})

Responses carry ETag and Last-Modified headers, so unchanged files revalidate as 304 Not Modified, and range requests are answered with 206 Partial Content for media seeking and resumable downloads.

Learn More

For implementation details, see the source code.

Last updated on August 10, 2026

Was this page helpful?