How to Serve Static Files with JSON Server: A Complete Guide
JSON Server can serve static HTML, CSS, and JavaScript files alongside your mock REST API using the built-in sirv middleware and optional CLI flags.
JSON Server is not just a fake REST API generator—it also functions as a lightweight static file server. Whether you need to serve a simple HTML frontend or host assets for your mock API, the typicode/json-server repository provides two mechanisms: an automatic public/ directory and customizable static paths via command-line arguments.
Built-in Static File Support in JSON Server
The core static file functionality is implemented in src/app.ts, where the Express-like application mounts directories using the sirv middleware.
The Default public/ Directory
By default, JSON Server automatically serves files from a public/ directory if it exists at the project root. This behavior is hardcoded in src/app.ts (lines 97-99):
// From src/app.ts
if (existsSync('public')) {
app.use(sirv('public', { dev: !isProduction }))
}
To use this feature, simply create a public folder and place your assets inside:
mkdir public
echo '<h1>Hello from JSON Server</h1>' > public/index.html
json-server db.json
Your index.html is now accessible at http://localhost:3000/index.html.
How sirv Middleware Handles Static Assets
JSON Server uses sirv, a tiny and fast static file server for Node.js. The middleware is configured with a dev flag that disables caching when not in production:
// Configuration pattern from src/app.ts
app.use(sirv(directoryPath, { dev: !isProduction }))
Static files are mounted before any JSON Server API routes, meaning a request matching a static asset path never reaches the REST layer.
Serving Custom Static Directories with CLI Flags
For projects requiring multiple asset sources or non-standard directory names, JSON Server provides the -s or --static CLI flag defined in src/bin.ts.
Using the -s or --static Flag
The CLI parser in src/bin.ts (lines 24-30) collects static directory arguments:
// CLI argument parsing from src/bin.ts
.args({
static: {
alias: 's',
describe: 'Set static files directory',
type: 'string',
},
})
To serve a custom directory, pass its path after the -s flag:
json-server db.json -s ./static
Files in ./static are served at the root URL. For example, ./static/logo.png becomes accessible at http://localhost:3000/logo.png.
Stacking Multiple Static Directories
You can specify multiple -s flags to mount several directories. The order matters—directories are checked in the sequence provided:
json-server db.json -s ./static -s ./assets/images
This configuration first looks for files in ./static, then falls back to ./assets/images if not found. This behavior is handled in src/app.ts (lines 97-101) where each directory is mounted with sirv in the order received.
Programmatic Static File Configuration
When embedding JSON Server in a Node.js application rather than using the CLI, you can configure static directories via the createApp options object.
import { Low } from 'lowdb';
import { JSONFile } from 'lowdb/node';
import { createApp } from 'json-server';
// Initialize database
const adapter = new JSONFile<{ posts: any[] }>('db.json');
const db = new Low(adapter);
await db.read();
// Create app with custom static directories
const app = createApp(db, {
static: ['./public', './extra-static'],
});
app.listen(3000, () => console.log('Server running on http://localhost:3000'));
The static option accepts an array of directory paths, mirroring the CLI -s flag functionality. Paths can be absolute or relative to process.cwd().
Static File Resolution Order and Priority
Understanding the middleware mounting order is crucial for debugging 404 errors. In src/app.ts, the registration sequence is:
- Default
public/directory (if it exists) - User-provided static directories (in the order specified via
-sflags orstaticoption) - JSON Server API routes (REST endpoints)
Because sirv middleware runs before the API router, a file named users.html in your static directory will take precedence over the /users API endpoint. If you need to disable the default public folder, simply remove or rename the directory; JSON Server only mounts it if existsSync('public') returns true.
Summary
- Default behavior: JSON Server automatically serves files from a
public/directory using thesirvmiddleware, as implemented insrc/app.ts. - Custom directories: Use the
-sor--staticCLI flag (parsed insrc/bin.ts) to mount additional static folders; multiple flags can be stacked. - Programmatic API: Pass a
staticarray tocreateApp()when embedding JSON Server in Node.js applications. - Resolution order: Static files are checked before API routes, with the default
publicfolder mounted first, followed by custom directories in the order provided.
Frequently Asked Questions
Can I disable the default public folder?
Yes. JSON Server only mounts the public/ directory if it exists at startup. To disable this behavior, simply rename or delete the public folder. If you need static file serving without the default directory, use the -s flag to specify a different folder or pass an empty static array to createApp() programmatically.
What happens if a static file path conflicts with an API route?
Static files take precedence over API routes. In src/app.ts, the sirv middleware is registered before the JSON Server router. This means if you have a file named users.html in your static directory and an endpoint /users, accessing /users.html will return the file, while /users will still hit the API. If a static file exists at a path that matches an API route exactly (e.g., a file named users with no extension), the file will be served and the API endpoint will be shadowed.
Does JSON Server support single-page application (SPA) routing?
JSON Server uses sirv with default settings, which does not automatically support SPA fallback routing (serving index.html for all non-file paths). If you need SPA support, you would need to either place your index.html in the root of your static directory and use hash-based routing, or implement a custom middleware that intercepts 404s from sirv and serves your SPA entry point. The current implementation in src/app.ts mounts sirv without custom 404 handling for SPAs.
How do I serve static files from multiple directories?
You can specify multiple -s or --static flags when starting the server. Each flag adds a directory to the static file search path. For example:
json-server db.json -s ./static -s ./assets -s ./uploads
Directories are mounted in the order provided, so ./static is checked first, then ./assets, then ./uploads. In programmatic usage, pass an array of paths to the static option of createApp(). This allows you to organize assets across multiple folders while serving them from a single JSON Server instance.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →