# How to Serve Static Files with JSON Server: A Complete Guide

> Learn how to serve static HTML, CSS, and JS files with JSON Server. This guide details using the built-in sirv middleware and CLI flags for your mock REST API.

- Repository: [typicode/json-server](https://github.com/typicode/json-server)
- Tags: how-to-guide
- Published: 2026-03-01

---

**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`](https://github.com/typicode/json-server/blob/main/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`](https://github.com/typicode/json-server/blob/main/src/app.ts) (lines 97-99):

```typescript
// 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:

```bash
mkdir public
echo '<h1>Hello from JSON Server</h1>' > public/index.html
json-server db.json

```

Your [`index.html`](https://github.com/typicode/json-server/blob/main/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:

```typescript
// 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`](https://github.com/typicode/json-server/blob/main/src/bin.ts).

### Using the -s or --static Flag

The CLI parser in [`src/bin.ts`](https://github.com/typicode/json-server/blob/main/src/bin.ts) (lines 24-30) collects static directory arguments:

```typescript
// 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:

```bash
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:

```bash
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`](https://github.com/typicode/json-server/blob/main/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.

```typescript
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`](https://github.com/typicode/json-server/blob/main/src/app.ts), the registration sequence is:

1. **Default `public/` directory** (if it exists)
2. **User-provided static directories** (in the order specified via `-s` flags or `static` option)
3. **JSON Server API routes** (REST endpoints)

Because `sirv` middleware runs before the API router, a file named [`users.html`](https://github.com/typicode/json-server/blob/main/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 the `sirv` middleware, as implemented in [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts).
- **Custom directories**: Use the `-s` or `--static` CLI flag (parsed in [`src/bin.ts`](https://github.com/typicode/json-server/blob/main/src/bin.ts)) to mount additional static folders; multiple flags can be stacked.
- **Programmatic API**: Pass a `static` array to `createApp()` when embedding JSON Server in Node.js applications.
- **Resolution order**: Static files are checked before API routes, with the default `public` folder 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`](https://github.com/typicode/json-server/blob/main/src/app.ts), the `sirv` middleware is registered before the JSON Server router. This means if you have a file named [`users.html`](https://github.com/typicode/json-server/blob/main/users.html) in your static directory and an endpoint `/users`, accessing [`/users.html`](https://github.com/typicode/json-server/blob/main//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`](https://github.com/typicode/json-server/blob/main/index.html) for all non-file paths). If you need SPA support, you would need to either place your [`index.html`](https://github.com/typicode/json-server/blob/main/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`](https://github.com/typicode/json-server/blob/main/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:

```bash
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.