Security News
Bun 1.2 Released with 90% Node.js Compatibility and Built-in S3 Object Support
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.
@fastify/static
Advanced tools
@fastify/static is a Fastify plugin for serving static files, such as HTML, CSS, JavaScript, and images. It is designed to be highly performant and easy to use, leveraging the speed and efficiency of the Fastify framework.
Serve Static Files
This feature allows you to serve static files from a specified directory. In this example, files from the 'public' directory are served with the '/public/' prefix.
const fastify = require('fastify')();
const path = require('path');
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
prefix: '/public/', // optional: default is '/'
});
fastify.listen(3000, err => {
if (err) throw err;
console.log('Server listening on http://localhost:3000');
});
Serve Single Page Applications (SPA)
This feature is useful for serving Single Page Applications (SPA). When a route is not found, it serves the 'index.html' file, allowing the client-side router to handle the navigation.
const fastify = require('fastify')();
const path = require('path');
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
wildcard: false
});
fastify.setNotFoundHandler((request, reply) => {
reply.sendFile('index.html');
});
fastify.listen(3000, err => {
if (err) throw err;
console.log('Server listening on http://localhost:3000');
});
Serve Files with Custom Headers
This feature allows you to set custom headers for the served files. In this example, a custom header 'X-Custom-Header' is added to the response.
const fastify = require('fastify')();
const path = require('path');
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
setHeaders: (res, path, stat) => {
res.setHeader('X-Custom-Header', 'my-custom-header');
}
});
fastify.listen(3000, err => {
if (err) throw err;
console.log('Server listening on http://localhost:3000');
});
serve-static is a middleware for serving static files in Node.js applications, typically used with Express. It is similar to @fastify/static but is designed for use with the Express framework rather than Fastify.
koa-static is a middleware for serving static files in Koa applications. It provides similar functionality to @fastify/static but is designed for the Koa framework.
Plugin for serving static files as fast as possible.
npm i @fastify/static
Plugin version | Fastify version |
---|---|
^8.x | ^5.x |
^7.x | ^4.x |
^5.x | ^3.x |
^2.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 for more details.
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}
})
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
})
content-disposition
headerconst 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 })
})
root
(required)The absolute path of the directory that contains the files to serve.
The file to serve will be determined by combining req.url
with the
provided root directory.
You can also provide an array of directories containing files to serve. This is useful for serving multiple static directories under a single prefix. Files are served in a "first found, first served" manner, so the order in which you list the directories is important. For best performance, you should always list your main asset directory first. 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 that will be added to registered routes. See Fastify's documentation for route constraints.
prefixAvoidTrailingSlash
Default: false
If set to false prefix will get trailing "/" at the end. If set to true, prefix will not append "/" to 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)
,
where the arguments are:
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
OptionsThe following options are also supported and will be passed directly to the
@fastify/send
module:
acceptRanges
contentType
cacheControl
(Enable or disable setting Cache-Control response header, defaults to true. Important: If you want to provide a custom Cache-Control response header, this option must be false.)dotfiles
etag
extensions
immutable
index
lastModified
maxAge
You're able to alter this options when calling reply.download('filename.html', options)
or reply.download('filename.html', 'otherfilename.html', options)
on each response to a request.
redirect
Default: false
If set to true
, @fastify/static
redirects to the directory with a trailing slash.
This option cannot be set to true
with wildcard
set to false
on a server
with ignoreTrailingSlash
set to true
.
If this option is set to false
, then requesting directories without trailing
slash will trigger your app's 404 handler using reply.callNotFound()
.
wildcard
Default: true
If set to true
, @fastify/static
adds a wildcard route to serve files.
If set to false
, @fastify/static
globs the filesystem for all defined
files in the served folder (${root}/**/**
), and just creates the routes needed for
those and it will not serve the newly added file on the filesystem.
The default options of https://www.npmjs.com/package/glob are applied for getting the file list.
This option cannot be set to false
with redirect
set to true
on a server
with ignoreTrailingSlash
set to true
.
allowedPath
Default: (pathName, root, request) => true
This function allows filtering the served files. Also, with the help of the request object a more complex path authentication is possible.
If the function returns true
, the file will be served.
If the function returns false
, Fastify's 404 handler will be called.
index
Default: undefined
Under the hood we use @fastify/send
lib that by default supports "index.html" files.
To disable this set false or to supply a new index pass a string or an array in preferred order.
serveDotFiles
Default: false
When true
, files in hidden directories (e.g. .foo
) will be served.
list
Default: undefined
If set, it provides the directory list calling the directory path.
Default response is json.
Note:
list
option.dotfiles
option value is deny
or ignore
, dotfiles will be excluded.Example:
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
prefix: '/public/',
index: false
list: true
})
Request
GET .../public
Response
{ "dirs": ["dir1", "dir2"], "files": ["file1.png", "file2.txt"] }
list.format
Default: json
Options: html
, json
Directory list can be also in html
format; in that case, list.render
function is required.
You can override the option with URL parameter format
. Options are html
and json
.
GET .../public/assets?format=json
will return the response as json independent of list.format
.
Example:
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, 'public'),
prefix: '/public/',
list: {
format: 'html',
render: (dirs, files) => {
return `
<html><body>
<ul>
${dirs.map(dir => `<li><a href="${dir.href}">${dir.name}</a></li>`).join('\n ')}
</ul>
<ul>
${files.map(file => `<li><a href="${file.href}" target="_blank">${file.name}</a></li>`).join('\n ')}
</ul>
</body></html>
`
},
}
})
Request
GET .../public
Response
<html><body>
<ul>
<li><a href="/dir1">dir1</a></li>
<li><a href="/dir1">dir2</a></li>
</ul>
<ul>
<li><a href="/foo.html" target="_blank">foo.html</a></li>
<li><a href="/foobar.html" target="_blank">foobar.html</a></li>
<li><a href="/index.css" target="_blank">index.css</a></li>
<li><a href="/index.html" target="_blank">index.html</a></li>
</ul>
</body></html>
list.names
Default: ['']
Directory list can respond to different routes, declared in list.names
options.
Note: if a file with the same name exists, the actual file is sent.
Example:
fastify.register(require('@fastify/static'), {
root: path.join(__dirname, '/static'),
prefix: '/public',
prefixAvoidTrailingSlash: true,
list: {
format: 'json',
names: ['index', 'index.json', '/']
}
})
Dir list respond with the same content to
GET .../public
GET .../public/
GET .../public/index
GET .../public/index.json
list.extendedFolderInfo
Default: undefined
If true
some extended information for folders will be accessible in list.render
and in the json response.
render(dirs, files) {
const dir = dirs[0];
dir.fileCount // number of files in this folder
dir.totalFileCount // number of files in this folder (recursive)
dir.folderCount // number of folders in this folder
dir.totalFolderCount // number of folders in this folder (recursive)
dir.totalSize // size of all files in this folder (recursive)
dir.lastModified // most recent last modified timestamp of all files in this folder (recursive)
}
Warning: This will slightly decrease the performance, especially for deeply nested file structures.
list.jsonFormat
Default: names
Options: names
, extended
This option determines the output format when json
is selected.
names
:
{
"dirs": [
"dir1",
"dir2"
],
"files": [
"file1.txt",
"file2.txt"
]
}
extended
:
{
"dirs": [
{
"name": "dir1",
"stats": {
"dev": 2100,
"size": 4096,
...
},
"extendedInfo": {
"fileCount": 4,
"totalSize": 51233,
...
}
}
],
"files": [
{
"name": "file1.txt",
"stats": {
"dev": 2200,
"size": 554,
...
}
}
]
}
preCompressed
Default: false
Try to send the brotli encoded asset first (when supported within the Accept-Encoding
headers), retry for gzip, and then fall back to the original pathname
. You may choose to skip compression for smaller files that do not benefit from it.
Assume this structure with the compressed asset as a sibling of the un-compressed counterpart:
./public
├── main.js
├── main.js.br
├── main.js.gz
├── crit.css
├── crit.css.gz
└── index.html
If you would just like to use the reply decorator and not serve whole directories automatically, you can simply pass the option { serve: false }
. This will prevent the plugin from serving everything under root
.
The reply object is decorated with a sendFile
function by default. If you want to
disable this, pass the option { decorateReply: false }
. If @fastify/static is
registered to multiple prefixes in the same route only one can initialize reply
decorators.
If a request matches the URL prefix
but a file cannot be found for the
request, Fastify's 404 handler will be called. You can set a custom 404
handler with fastify.setNotFoundHandler()
.
When registering @fastify/static
within an encapsulated context, the wildcard
option may need to be set to false
to support index resolution and nested not-found-handler:
const app = require('fastify')();
app.register((childContext, _, done) => {
childContext.register(require('@fastify/static'), {
root: path.join(__dirname, 'docs'), // docs is a folder that contains `index.html` and `404.html`
wildcard: false
});
childContext.setNotFoundHandler((_, reply) => {
return reply.code(404).type('text/html').sendFile('404.html');
});
done();
}, { prefix: 'docs' });
This code will send the index.html
for the paths docs
, docs/
, and docs/index.html
. For all other docs/<undefined-routes>
it will reply with 404.html
.
If an error occurs while trying to send a file, the error will be passed
to Fastify's error handler. You can set a custom error handler with
fastify.setErrorHandler()
.
stream.path
If you need to access the file path inside the onSend
hook, you can use payload.path
.
fastify.addHook('onSend', function (req, reply, payload, next) {
console.log(payload.path)
next()
})
Licensed under MIT.
FAQs
Plugin for serving static files as fast as possible.
We found that @fastify/static demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Bun 1.2 enhances its JavaScript runtime with 90% Node.js compatibility, built-in S3 and Postgres support, HTML Imports, and faster, cloud-first performance.
Security News
Biden's executive order pushes for AI-driven cybersecurity, software supply chain transparency, and stronger protections for federal and open source systems.
Security News
Fluent Assertions is facing backlash after dropping the Apache license for a commercial model, leaving users blindsided and questioning contributor rights.