Serve Files From a Folder
@fastify/static
Mount a folder as static assets with proper caching headers and an optional single-page application fallback for client-side routing.
What you'll learn
- Install @fastify/static
- Register with root and optional prefix
- Add an SPA fallback for client-side routing
@fastify/static serves files from a directory: JS bundles, CSS, images, a built SPA. Behind the scenes it uses the proven send library and stream responses for efficiency.
Install & Register
npm install @fastify/static import { fileURLToPath } from 'node:url'
import { dirname, join } from 'node:path'
import fastifyStatic from '@fastify/static'
const __dirname = dirname(fileURLToPath(import.meta.url))
await app.register(fastifyStatic, {
root: join(__dirname, '..', 'public'),
prefix: '/static/',
maxAge: '7d',
immutable: true,
}) immutable: true plus maxAge produces Cache-Control: public, max-age=604800, immutable. Combine with fingerprinted filenames (app.abc123.js) for hands-off caching.
SPA Fallback
When the URL does not match a built file, return index.html so the SPA router can take over.
app.setNotFoundHandler((req, reply) => {
if (req.raw.url?.startsWith('/api')) {
return reply.code(404).send({ error: 'not found' })
}
return reply.sendFile('index.html')
}) Multiple Roots
You can register the plugin several times with decorateReply: false after the first to serve from multiple directories under different prefixes.
await app.register(fastifyStatic, {
root: join(__dirname, '..', 'public'),
prefix: '/',
})
await app.register(fastifyStatic, {
root: join(__dirname, '..', 'docs-dist'),
prefix: '/docs/',
decorateReply: false,
})