# @fastify/static [](https://github.com/fastify/fastify-static/actions/workflows/ci.yml) [](https://www.npmjs.com/package/@fastify/static) [](https://github.com/neostandard/neostandard) Plugin for serving static files as fast as possible. ## Install ``` npm i @fastify/static ``` ### Compatibility | Plugin version | Fastify version | | ---------------|-----------------| | `>=8.x` | `^5.x` | | `>=7.x <8.x` | `^4.x` | | `>=5.x <7.x` | `^3.x` | | `>=2.x <5.x` | `^2.x` | | `^1.x` | `^1.x` | Please note that if a Fastify version is out of support, then so are the corresponding versions of this plugin in the table above. See [Fastify's LTS policy](https://github.com/fastify/fastify/blob/main/docs/Reference/LTS.md) for more details. ## Usage ```js const fastify = require('fastify')({logger: true}) const path = require('node:path') fastify.register(require('@fastify/static'), { root: path.join(__dirname, 'public'), prefix: '/public/', // optional: default '/' constraints: { host: 'example.com' } // optional: default {} }) fastify.get('/another/path', function (req, reply) { reply.sendFile('myHtml.html') // serving path.join(__dirname, 'public', 'myHtml.html') directly }) fastify.get('/another/patch-async', async function (req, reply) { return reply.sendFile('myHtml.html') }) fastify.get('/path/with/different/root', function (req, reply) { reply.sendFile('myHtml.html', path.join(__dirname, 'build')) // serving a file from a different root location }) fastify.get('/another/path', function (req, reply) { reply.sendFile('myHtml.html', { cacheControl: false }) // overriding the options disabling cache-control headers }) // Run the server! fastify.listen({ port: 3000 }, (err, address) => { if (err) throw err // Server is now listening on ${address} }) ``` ### Multiple prefixed roots ```js const fastify = require('fastify')() const fastifyStatic = require('@fastify/static') const path = require('node:path') // first plugin fastify.register(fastifyStatic, { root: path.join(__dirname, 'public') }) // second plugin fastify.register(fastifyStatic, { root: path.join(__dirname, 'node_modules'), prefix: '/node_modules/', decorateReply: false // the reply decorator has been added by the first plugin registration }) ``` ### Sending a file with `content-disposition` header ```js const fastify = require('fastify')() const path = require('node:path') fastify.register(require('@fastify/static'), { root: path.join(__dirname, 'public'), prefix: '/public/', // optional: default '/' }) fastify.get('/another/path', function (req, reply) { reply.download('myHtml.html', 'custom-filename.html') // sending path.join(__dirname, 'public', 'myHtml.html') directly with custom filename }) fastify.get('another/patch-async', async function (req, reply) { // an async handler must always return the reply object return reply.download('myHtml.html', 'custom-filename.html') }) fastify.get('/path/without/cache/control', function (req, reply) { reply.download('myHtml.html', { cacheControl: false }) // serving a file disabling cache-control headers }) fastify.get('/path/without/cache/control', function (req, reply) { reply.download('myHtml.html', 'custom-filename.html', { cacheControl: false }) }) ``` ### Managing cache-control headers Production sites should use a reverse-proxy to manage caching headers. However, here is an example of using fastify-static to host a Single Page Application (for example a [vite.js](https://vite.dev/) build) with sane caching. ```js fastify.register(require('@fastify/static'), { root: path.join(import.meta.dirname, 'dist'), // import.meta.dirname node.js >= v20.11.0 // By default all assets are immutable and can be cached for a long period due to cache bursting techniques maxAge: '30d', immutable: true, }) // Explicitly reduce caching of assets that don't use cache bursting techniques fastify.get('/', function (req, reply) { // index.html should never be cached reply.sendFile('index.html', {maxAge: 0, immutable: false}) }) fastify.get('/favicon.ico', function (req, reply) { // favicon can be cached for a short period reply.sendFile('favicon.ico', {maxAge: '1d', immutable: false}) }) ``` ### Options #### `serve` Default: `true` If set to `false`, the plugin will not serve files from the `root` directory. #### `root` (required if `serve` is not false) The absolute path of the directory containing the files to serve. The file to serve is determined by combining `req.url` with the root directory. An array of directories can be provided to serve multiple static directories under a single prefix. Files are served in a "first found, first served" manner, so list directories in order of priority. Duplicate paths will raise an error. #### `prefix` Default: `'/'` A URL path prefix used to create a virtual mount path for the static directory. #### `constraints` Default: `{}` Constraints to add to registered routes. See Fastify's documentation for [route constraints](https://fastify.dev/docs/latest/Reference/Routes/#constraints). #### `logLevel` Default: `info` Set log level for registered routes. #### `prefixAvoidTrailingSlash` Default: `false` If `false`, the prefix gets a trailing "/". If `true`, no trailing "/" is added to the prefix. #### `schemaHide` Default: `true` A flag that defines if the fastify route hide-schema attribute is hidden or not. #### `setHeaders` Default: `undefined` A function to set custom headers on the response. Alterations to the headers must be done synchronously. The function is called as `fn(res, path, stat)`, with the arguments: - `res` The response object. - `path` The path of the file that is being sent. - `stat` The stat object of the file that is being sent. #### `send` Options The following options are also supported and will be passed directly to the [`@fastify/send`](https://www.npmjs.com/package/@fastify/send) module: - [`acceptRanges`](https://www.npmjs.com/package/@fastify/send#acceptranges) - [`contentType`](https://www.npmjs.com/package/@fastify/send#contenttype) - [`cacheControl`](https://www.npmjs.com/package/@fastify/send#cachecontrol) - Enable or disable setting Cache-Control response header (defaults to `true`). To provide a custom Cache-Control header, set this option to false - [`dotfiles`](https://www.npmjs.com/package/@fastify/send#dotfiles) - [`etag`](https://www.npmjs.com/package/@fastify/send#etag) - [`extensions`](https://www.npmjs.com/package/@fastify/send#extensions) - [`immutable`](https://www.npmjs.com/package/@fastify/send#immutable) - [`index`](https://www.npmjs.com/package/@fastify/send#index) - [`lastModified`](https://www.npmjs.com/package/@fastify/send#lastmodified) - [`maxAge`](https://www.npmjs.com/package/@fastify/send#maxage) These options can be altered when calling `reply.sendFile('filename.html', options)` or `reply.sendFile('filename.html', 'otherfilename.html', options)` on each response. #### `redirect` Default: `false` If set to `true`, `@fastify/static` redirects to the directory with a trailing slash. This option cannot be `true` if `wildcard` is `false` and `ignoreTrailingSlash` is `true`. If `false`, requesting directories without a trailing slash triggers the app's 404 handler using `reply.callNotFound()`. #### `wildcard` Default: `true` If `true`, `@fastify/static` adds a wildcard route to serve files. If `false`, it globs the filesystem for all defined files in the served folder (`${root}/**/**`) and creates the necessary routes, but will not serve newly added files. The default options of [`glob`](https://www.npmjs.com/package/glob) are applied for getting the file list. This option cannot be `false` if `redirect` is `true` and `ignoreTrailingSlash` is `true`. #### `globIgnore` Default: `undefined` This is passed to [`glob`](https://www.npmjs.com/package/glob) as the `ignore` option. It can be used to ignore files or directories when using the `wildcard: false` option. #### `allowedPath` Default: `(pathName, root, request) => true` This function filters served files. Using the request object, complex path authentication is possible. Returning `true` serves the file; returning `false` calls Fastify's 404 handler. #### `index` Default: `undefined` Under the hood, [`@fastify/send`](https://www.npmjs.com/package/@fastify/send) supports "index.html" files by default. To disable this, set `false`, or supply a new index by passing a string or an array in preferred order. #### `serveDotFiles` Default: `false` If `true`, serves files in hidden directories (e.g., `.foo`). #### `list` Default: `undefined` If set, provides the directory list by calling the directory path. Default response is JSON. Multi-root is not supported within the `list` option. If `dotfiles` is `deny` or `ignore`, dotfiles are excluded. Example: ```js fastify.register(require('@fastify/static'), { root: path.join(__dirname, 'public'), prefix: '/public/', index: false, list: true }) ``` Request ```bash GET /public ``` Response ```json { "dirs": ["dir1", "dir2"], "files": ["file1.png", "file2.txt"] } ``` #### `list.format` Default: `json` Options: `html`, `json` Directory list can be in `html` format; in that case, `list.render` function is required. This option can be overridden by the URL parameter `format`. Options are `html` and `json`. ```bash GET /public/assets?format=json ``` Returns the response as JSON, regardless of `list.format`. Example: ```js fastify.register(require('@fastify/static'), { root: path.join(__dirname, 'public'), prefix: '/public/', list: { format: 'html', render: (dirs, files) => { return `