Documentation Index
Fetch the complete documentation index at: https://mintlify.com/remix-run/remix/llms.txt
Use this file to discover all available pages before exploring further.
Static Middleware
Static file serving middleware that serves files from a directory with support for ETags, range requests, and conditional requests.
Installation
Function
staticFiles()
Creates middleware that serves static files from the filesystem.
Signature:
function staticFiles(root: string, options?: StaticFilesOptions): Middleware
Parameters:
root - The root directory to serve files from (absolute or relative to cwd)
options - Optional configuration for file responses
Returns: The static files middleware.
Note: Uses the URL pathname to resolve files, removing the leading slash to make it a relative path. The middleware always falls through to the handler if the file is not found or an error occurs.
Options
StaticFilesOptions
interface StaticFilesOptions extends FileResponseOptions {
filter?: (path: string) => boolean
acceptRanges?: boolean | AcceptRangesFunction
index?: boolean | string[]
listFiles?: boolean
}
filter
Filter function to determine which files should be served.
- Type:
(path: string) => boolean
- Default:
undefined (all files)
acceptRanges
Whether to support HTTP Range requests for partial content.
- Type:
boolean | AcceptRangesFunction
- Default: Enables ranges only for non-compressible MIME types
Note: Range requests and compression are mutually exclusive. When Accept-Ranges: bytes is present, the compression middleware will not compress the response.
index
Files to try and serve as the index file when the request path targets a directory.
- Type:
boolean | string[]
- Default:
true (uses ['index.html', 'index.htm'])
- Values:
true - Use default index files
false - Disable index file serving
string[] - Custom list of index files to try in order
listFiles
Whether to return an HTML page listing the files in a directory when the request path targets a directory.
- Type:
boolean
- Default:
false
Note: If both listFiles and index are set, index takes precedence.
cacheControl
Cache-Control header value for responses.
- Type:
string
- Default:
undefined
etag
Whether to generate ETags for responses.
- Type:
boolean | 'strong' | 'weak'
- Default:
'weak'
Basic Usage
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [staticFiles('./public')],
})
router.get('/', () => new Response('Home'))
With Cache Control
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [
staticFiles('./public', {
cacheControl: 'public, max-age=31536000, immutable', // 1 year
}),
],
})
Filter Files
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [
staticFiles('./public', {
filter(path) {
// Don't serve hidden files
return !path.startsWith('.')
},
}),
],
})
Multiple Directories
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [
staticFiles('./public'),
staticFiles('./assets', {
cacheControl: 'public, max-age=31536000',
}),
],
})
Custom Index Files
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [
staticFiles('./public', {
index: ['index.html', 'default.html', 'home.html'],
}),
],
})
Disable Index Files
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [
staticFiles('./public', {
index: false, // Don't serve index files
}),
],
})
Directory Listing
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [
staticFiles('./public', {
listFiles: true, // Show directory contents when no index file
}),
],
})
Range Requests
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
// Force range request support for all files
let router = createRouter({
middleware: [
staticFiles('./public', {
acceptRanges: true,
}),
],
})
// Enable ranges for videos only
let router2 = createRouter({
middleware: [
staticFiles('./public', {
acceptRanges: (file) => file.type.startsWith('video/'),
}),
],
})
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [
staticFiles('./public', {
etag: 'strong', // Use strong ETags instead of weak
}),
],
})
import { createRouter } from 'remix/fetch-router'
import { staticFiles } from 'remix/static-middleware'
let router = createRouter({
middleware: [
staticFiles('./public', {
etag: false, // Disable ETag generation
}),
],
})
Security
- Prevents path traversal attacks (e.g.,
../../../etc/passwd)
- Only serves files with GET and HEAD requests
- Respects the configured root directory boundary
Features
- ETag support (weak and strong)
- Range requests support (HTTP 206 Partial Content)
- Conditional request support (If-None-Match, If-Modified-Since)
- Path traversal protection
- Automatic fallback to next middleware/handler if file not found
- fetch-router - Router for the web Fetch API
- fs - File system utilities
- lazy-file - Used internally for streaming file contents