# How to Secure JSON Server in a Production Environment: 7 Essential Hardening Steps

> Secure JSON Server in production with 7 essential steps. Learn to restrict CORS, implement authentication, guard HTTP verbs, and use a reverse proxy to protect your API.

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

---

**To secure JSON Server in production, disable the development file watcher by setting `NODE_ENV=production`, restrict CORS to specific origins in [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts), mount authentication middleware before routes, disable or guard mutating HTTP verbs, and deploy behind a TLS-terminating reverse proxy.**

JSON Server from `typicode/json-server` provides a full fake REST API for rapid prototyping, but its default configuration is deliberately permissive to accelerate development. When you need to expose this service to real traffic, you must harden the tinyhttp-based application against unauthorized access and data corruption. This guide shows you exactly how to secure JSON Server in a production environment by extending the core source files with industry-standard middleware and deployment patterns.

## 1. Understand the Default Security Posture

Before hardening, recognize that JSON Server ships with open defaults intended for local development. According to the source code in [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts), the server enables **CORS for any origin** and exposes unrestricted CRUD endpoints powered by **lowdb**. Meanwhile, [`src/bin.ts`](https://github.com/typicode/json-server/blob/main/src/bin.ts) activates a file watcher that rewrites [`db.json`](https://github.com/typicode/json-server/blob/main/db.json) on every change, which is dangerous under production load. The core architecture uses **tinyhttp**, making it straightforward to inject Express-compatible middleware for authentication, logging, and access control.

## 2. Enable Production Mode and Disable File Watching

The codebase checks `process.env['NODE_ENV']` to toggle development behaviors. In [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts), this flag controls view caching:

```ts
// src/app.ts
const isProduction = process.env['NODE_ENV'] === 'production';
const eta = new Eta({
  views: join(__dirname, '../views'),
  cache: isProduction,          // enables caching only in prod
});

```

Setting `NODE_ENV=production` also disables the file watcher defined in [`src/bin.ts`](https://github.com/typicode/json-server/blob/main/src/bin.ts), preventing the server from reloading the database file on every write during high-traffic scenarios.

**Action:** Start the server with the production flag:

```bash
NODE_ENV=production npx json-server db.json

```

## 3. Lock Down CORS to Trusted Origins

By default, [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts) applies `app.use(cors())` without restrictions, allowing any domain to interact with your API. Replace this with a whitelist before route definitions so the restriction inherits to all endpoints:

```ts
import { cors } from '@tinyhttp/cors';

// src/app.ts – replace existing CORS block
app.use(
  cors({
    origin: ['https://example.com', 'https://api.example.com'],
    allowedHeaders: (req) =>
      req.headers['access-control-request-headers']?.split(',').map((h) => h.trim()),
  })
);

```

Because the CORS middleware mounts early in the chain, it guards every subsequent route including those generated dynamically from your JSON file.

## 4. Implement Authentication Middleware

JSON Server does not provide authentication out of the box, but you can mount any tinyhttp-compatible guard. Insert this before the body parser and route definitions in [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts) to reject unauthorized requests early:

```ts
import { Request, Response, NextFunction } from '@tinyhttp/app';

// Simple API‑key guard
function apiKeyGuard(req: Request, res: Response, next: NextFunction) {
  const key = req.headers['x-api-key'];
  if (key === process.env['JSON_SERVER_API_KEY']) {
    return next();
  }
  res.status(401).json({ error: 'Invalid API key' });
}

// src/app.ts – after CORS, before routes
app.use(apiKeyGuard);

```

Store the secret in an environment variable (`JSON_SERVER_API_KEY`) and never commit it to version control.

## 5. Restrict or Remove Mutating Endpoints

If your production use case is read‑only, eliminate the risk of data corruption by disabling write operations. In [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts), comment out or conditionally mount the mutating routes that bind to methods in [`src/service.ts`](https://github.com/typicode/json-server/blob/main/src/service.ts):

```ts
// src/app.ts – comment out write routes or protect with middleware
// app.post('/:name', withBody(service.create.bind(service)));
// app.put('/:name', withBody(service.update.bind(service)));
// app.patch('/:name', withBody(service.patch.bind(service)));
// app.delete('/:name/:id', async (req, res, next) => { ... });

```

Alternatively, wrap these routes with the same `apiKeyGuard` so only administrative clients can modify data while public visitors retain read access.

## 6. Deploy Behind a Reverse Proxy with TLS

JSON Server does not manage TLS certificates. Deploy it behind **nginx**, **Traefik**, or a cloud load balancer that terminates HTTPS and provides additional firewall rules. A minimal nginx configuration:

```nginx
server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    location / {
        proxy_pass http://localhost:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

```

This setup shields the Node.js process from direct internet exposure and centralizes certificate management.

## 7. Harden File Permissions and Enable Structured Logging

Protect the underlying **lowdb** database file and gain observability with these final steps:

**File Security:**
- Ensure [`db.json`](https://github.com/typicode/json-server/blob/main/db.json) is owned by the runtime user and not world‑writable (`chmod 600 db.json`).
- Periodically backup the file to a secure location.
- The `Observer` class already serializes writes, but you can configure lowdb to use atomic file replacement via `fs.rename` for stronger consistency guarantees.

**Logging:**
Production logging defaults to off (`createApp(db, { logger: false })`). Enable a structured logger like **pino** in [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts):

```ts
import pino from 'pino';
const logger = pino({ level: 'info' });

app.use((req, res, next) => {
  logger.info({ method: req.method, url: req.url, ip: req.ip });
  next();
});

```

Ship these logs to a central monitoring system and combine with process managers like PM2 or systemd to restart the service on crashes.

## Summary

- **Set `NODE_ENV=production`** to disable the file watcher and enable view caching in [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts).
- **Whitelist CORS origins** instead of allowing all domains.
- **Mount authentication middleware** (API keys or JWT) before route definitions to block anonymous requests.
- **Disable mutating routes** (POST/PUT/PATCH/DELETE) or wrap them with authorization guards when read‑only mode is required.
- **Use a reverse proxy** (nginx) for TLS termination and IP filtering.
- **Restrict file permissions** on [`db.json`](https://github.com/typicode/json-server/blob/main/db.json) and enable structured logging for audit trails.

## Frequently Asked Questions

### Can JSON Server handle HTTPS natively?

No. The tinyhttp core in [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts) does not include TLS termination capabilities. You must place JSON Server behind a reverse proxy such as nginx or a cloud load balancer that manages SSL certificates and terminates HTTPS traffic before forwarding plain HTTP to the Node.js application.

### How do I prevent the database file from being corrupted during concurrent writes?

The `Observer` class in the source code serializes write operations to [`db.json`](https://github.com/typicode/json-server/blob/main/db.json), but you should also ensure the file has restrictive Unix permissions (not world‑writable) and is owned by the service account. For stronger guarantees, configure the underlying lowdb adapter to write to a temporary file and use `fs.rename` for atomic replacement.

### Is it safe to use JSON Server for production data?

Only if you implement the hardening steps above. The default configuration exposes all CRUD operations to any origin without authentication, which is unsafe for production. You must add authentication middleware, restrict CORS, and consider read‑only mode or IP allowlisting before exposing real data.

### How do I disable specific HTTP methods like DELETE or POST?

In [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts), locate the route definitions that use `withBody(service.create.bind(service))`, `service.update`, `service.patch`, or the async handler for `DELETE`. Comment out these lines or conditionally mount them only when an admin API key is present, effectively removing public write access while preserving GET endpoints.