# How app.ts Creates the HTTP Server and Defines Routes in JSON Server

> Discover how app.ts in JSON Server builds the HTTP server and defines routes. Learn about middleware, RESTful routes, and CRUD operations.

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

---

**The [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts) file in JSON Server constructs a Tinyhttp application instance, configures essential middleware for static files, CORS, and JSON parsing, and registers a complete set of RESTful routes that delegate CRUD operations to the Service layer.**

JSON Server’s architecture separates the HTTP layer from the CLI lifecycle. The `typicode/json-server` repository implements the core web logic in [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts), which exports a factory function `createApp`. This function builds a fully configured Tinyhttp application that transforms a LowDB database instance into a mock REST API, while the actual server startup is handled separately by [`src/bin.ts`](https://github.com/typicode/json-server/blob/main/src/bin.ts).

## Creating the Tinyhttp Application in app.ts

### Instantiating the App Class

At the heart of the HTTP server creation is the Tinyhttp framework. Inside [`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts) at line 95, the code initializes the application:

```typescript
const app = new App()

```

The `App` class is imported from `@tinyhttp/app`, a lightweight Node.js framework. This `app` instance serves as the container for all middleware and route definitions. The function containing this instantiation is exported as `createApp`, allowing both the CLI and programmatic consumers to generate a configured server instance without immediately binding it to a network port.

## Configuring Middleware for the HTTP Server

Before defining routes, [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) layers several middleware functions to handle cross-cutting concerns. Each middleware is registered using Tinyhttp’s `app.use()` pattern.

### Static File Serving

JSON Server serves a built-in web UI and supports custom static directories. Lines 98-101 configure this:

```typescript
app.use(serveStatic('public'))
staticArr.forEach((dir) => {
  app.use(serveStatic(dir))
})

```

The `public` folder contains the default HTML interface, while additional directories passed via the CLI `--static` flag are mounted iteratively.

### CORS Handling

To support cross-origin requests, lines 104-113 implement dynamic CORS middleware. Rather than using a static configuration, it inspects the incoming `Access-Control-Request-Headers` and mirrors them back in the `Access-Control-Allow-Headers` response. This ensures the mock API accepts the specific headers requested by the client.

### JSON Body Parsing

At line 115, the application gains the ability to parse JSON request bodies:

```typescript
app.use(json())

```

This middleware from `@tinyhttp/json` parses `application/json` payloads and assigns the result to `req.body`, making it available to subsequent route handlers.

### Template Engine Setup

For the root UI page, JSON Server uses the **Eta** template engine. Lines 117-118 configure the engine and set the views directory:

```typescript
app.engine('eta', eta.renderFile)
app.set('views', 'views')

```

This allows the route handler for `GET /` to render [`views/index.html`](https://github.com/typicode/json-server/blob/main/views/index.html) with the current database state.

## Defining RESTful Routes in app.ts

With middleware configured, [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) registers the full spectrum of REST endpoints. Each route delegates its logic to methods from [`src/service.ts`](https://github.com/typicode/json-server/blob/main/src/service.ts), which implements the actual CRUD operations against the LowDB database.

### List and Single Resource Retrieval

Collection listing and individual resource retrieval are handled by parameterized routes. Lines 119-130 define the collection list endpoint:

```typescript
app.get('/:name', (req, res) => {
  const { name } = req.params
  const query = parseListParams(req.query, db.data[name])
  res.locals['data'] = service.find(name, query)
})

```

The `parseListParams` function (lines 30-66) processes query string parameters like `_sort`, `_page`, `_per_page`, and `_where` to build filtering and pagination logic. For single resources, lines 133-137 handle `GET /:name/:id` by calling `service.findById`.

### Create, Update, and Delete Operations

Mutation routes use helper wrappers to validate inputs before calling service methods. Line 139 shows the create endpoint:

```typescript
app.post('/:name', withBody, (req, res) => {
  res.locals['data'] = service.create(req.params.name, res.locals['body'])
})

```

The `withBody` middleware validates that `req.body` is a valid item. Similarly, `PUT` and `PATCH` routes use `withBody` for collection updates and `withIdAndBody` for single item updates. Lines 149-152 handle deletion:

```typescript
app.delete('/:name/:id', (req, res) => {
  const { name, id } = req.params
  service.destroyById(name, id, req.query['_dependent'])
  res.locals['data'] = {}
})

```

### Query Parameter Parsing

The `parseListParams` function (lines 30-66) is critical for the list endpoints. It interprets special query parameters:
- `_sort` and `_order` for sorting
- `_page` and `_per_page` for pagination
- `_embed` for sideloading related resources
- `_where` for complex filtering

This transforms raw query strings into a structured query object passed to `service.find`.

## Starting the Server from bin.ts

A crucial architectural detail is that [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) does not start the server itself. This separation allows the application logic to be tested or embedded without binding to a port. The CLI entry point in [`src/bin.ts`](https://github.com/typicode/json-server/blob/main/src/bin.ts) handles server startup:

```typescript
// src/bin.ts – lines 42-44
const app = createApp(db, { logger: false, static: staticArr });
app.listen(port, () => { 
  // pretty console output 
});

```

The `createApp` function exported from [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) returns the fully configured Tinyhttp instance. Calling `app.listen()` (provided by Tinyhttp) creates the underlying Node.js HTTP server and begins accepting connections.

## Programmatic Usage Example

Because [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) exports a factory function rather than a singleton, you can embed JSON Server in your own applications:

```ts
import { Low } from 'lowdb'
import { JSONFile } from 'lowdb/node'
import { createApp } from './src/app.js'

// 1️⃣ Initialise an in‑memory DB (no file needed for demo)
const adapter = new JSONFile<{ posts: any[] }>('tmp-db.json')
const db = new Low(adapter, { posts: [] })
await db.read()

// 2️⃣ Build the Tinyhttp app
const app = createApp(db, { logger: true })

// 3️⃣ Start listening (e.g., port 4000)
app.listen(4000, () => console.log('JSON Server listening on http://localhost:4000'))

// Now you can call:
// GET http://localhost:4000/posts
// POST http://localhost:4000/posts   { "title": "Hello" }

```

This pattern demonstrates how [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) creates a reusable HTTP server configuration independent of the CLI lifecycle.

## Summary

- **[`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts)** constructs a **Tinyhttp** application instance via `new App()` and exports it as a factory function `createApp`, enabling both CLI and programmatic usage.
- The file configures **middleware** for static file serving, dynamic CORS, JSON body parsing, and the Eta template engine before any routes are defined.
- **RESTful routes** are registered for all CRUD operations (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`), delegating business logic to [`src/service.ts`](https://github.com/typicode/json-server/blob/main/src/service.ts) and using helper functions like `withBody` and `parseListParams` for validation and query parsing.
- The actual **HTTP server startup** occurs in [`src/bin.ts`](https://github.com/typicode/json-server/blob/main/src/bin.ts), which calls `app.listen()` after receiving the configured app from `createApp`, maintaining a clean separation between application logic and server lifecycle.

## Frequently Asked Questions

### What is the difference between app.ts and bin.ts in JSON Server?

[`src/app.ts`](https://github.com/typicode/json-server/blob/main/src/app.ts) is responsible for building and configuring the Tinyhttp application instance, including all middleware and route definitions, but it does not start the server. [`src/bin.ts`](https://github.com/typicode/json-server/blob/main/src/bin.ts) acts as the CLI entry point that parses command-line arguments, initializes the LowDB database, calls `createApp()` to get the configured app, and then invokes `app.listen()` to bind to a port and start accepting HTTP requests.

### How does app.ts handle CORS requests?

Rather than using a static CORS configuration, [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) implements dynamic CORS middleware between lines 104-113. It inspects the incoming request's `Access-Control-Request-Headers` header and mirrors those specific headers back in the `Access-Control-Allow-Headers` response. This ensures the mock API accepts exactly the headers requested by the client without hardcoding allowed origins or methods.

### Can I use app.ts to create a JSON Server instance programmatically?

Yes, [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) exports a `createApp` factory function specifically designed for programmatic usage. You can import `createApp` into your own Node.js application, pass it a LowDB instance and configuration options (such as `{ logger: true, static: [] }`), and receive a fully configured Tinyhttp app. This allows you to embed JSON Server's REST API functionality into existing applications or test suites without using the CLI.

### What routing library does JSON Server use under the hood?

JSON Server uses **Tinyhttp** (`@tinyhttp/app`), a lightweight, Express-like Node.js framework, as its routing library. The `App` class from Tinyhttp provides the `use()`, `get()`, `post()`, and other HTTP method functions used in [`app.ts`](https://github.com/typicode/json-server/blob/main/app.ts) to define middleware and routes. This choice keeps the codebase minimal while providing robust routing capabilities compatible with Express middleware patterns.