# Express User Guide

## 1. Quick Start

Express is a fast, unopinionated, minimalist web framework for Node.js. It provides a thin layer of fundamental web application features — routing, middleware, templating, and HTTP utilities — without obscuring the Node.js platform underneath.

**Key features:**

- Robust routing with support for parameters, pattern matching, and HTTP method handlers
- Middleware pipeline architecture for composable request/response processing
- Built-in body parsing (`json`, `urlencoded`, `raw`, `text`) and static file serving
- Template engine integration (EJS, Handlebars, Pug, and any engine exposing `__express`)
- Content negotiation via `Accept` header inspection
- Cookie handling with optional signing
- Proxy trust configuration for `X-Forwarded-*` header support
- Sub-application mounting for modular architectures

**Prerequisites:** Node.js 18 or later

**Install and run:**

```bash
npm install express
```

**Minimal application:**

```javascript
const express = require('express');
const app = express();

app.get('/', (req, res) => {
  res.send('Hello World!');
});

app.listen(3000, () => {
  console.log('Server listening on port 3000');
});
```

```text
Server listening on port 3000
```

> [!TIP]
> Pass an object or array to `res.send()` and Express automatically serializes it as JSON with the correct `Content-Type` header — no need to call `res.json()` explicitly.

**What to try next:** see Configuration for application settings, Core Usage for routing and middleware, and Common Tasks for real-world recipes.

## 2. Installation

### System Requirements

| Requirement | Minimum |
|---|---|
| Node.js | >= 18 |
| npm | Any version bundled with Node 18+ |
| OS | Any platform supported by Node.js |

### Install Methods

=== "npm"
    ```bash
    npm install express
    ```

=== "yarn"
    ```bash
    yarn add express
    ```

=== "pnpm"
    ```bash
    pnpm add express
    ```

### Post-Install Verification

```bash
node -e "console.log(require('express/package.json').version)"
```

```text
5.2.1
```

> [!IMPORTANT]
> Express 5 requires Node.js 18 or later. If you are running an older Node.js version, you must upgrade before installing.

### Dependencies

Express 5.2.1 ships with these production dependencies (installed automatically):

| Dependency | Purpose |
|---|---|
| `body-parser` ^2.2.1 | Request body parsing (JSON, URL-encoded, raw, text) |
| `router` ^2.2.0 | HTTP routing engine |
| `serve-static` ^2.2.0 | Static file serving middleware |
| `send` ^1.1.0 | File streaming for `res.sendFile` |
| `accepts` ^2.0.0 | Content negotiation |
| `cookie` ^0.7.1 | Cookie parsing/serialization |
| `cookie-signature` ^1.2.1 | Signed cookie support |
| `qs` ^6.14.2 | Extended query string parsing |
| `proxy-addr` ^2.0.7 | Trusted proxy address resolution |
| `debug` ^4.4.0 | Debug logging (`DEBUG=express:*`) |
| `finalhandler` ^2.1.0 | Default error handling |
| `mime-types` ^3.0.0 | MIME type resolution |
| `etag` ^1.8.1 | ETag generation |
| `fresh` ^2.0.0 | HTTP cache freshness checks |
| `http-errors` ^2.0.0 | HTTP error creation |
| `depd` ^2.0.0 | Deprecation notices |
| `content-disposition` ^1.0.0 | Content-Disposition header generation |
| `content-type` ^1.0.5 | Content-Type header parsing |
| `encodeurl` ^2.0.0 | URL encoding |
| `escape-html` ^1.0.3 | HTML entity escaping |
| `merge-descriptors` ^2.0.0 | Object descriptor merging |
| `on-finished` ^2.4.1 | Response finish detection |
| `once` ^1.4.0 | One-time callback wrapper |
| `parseurl` ^1.3.3 | URL parsing with caching |
| `range-parser` ^1.2.1 | Range header parsing |
| `statuses` ^2.0.1 | HTTP status code utilities |
| `type-is` ^2.0.1 | Content-Type checking |
| `vary` ^1.1.2 | Vary header management |

### Install Troubleshooting

**Q: `npm install` fails with permission errors**

Run `npm install express` without `sudo`. If your global `node_modules` has permission issues, configure npm to use a user-level prefix: `npm config set prefix ~/.npm-global`.

**Q: `Error: Cannot find module 'express'`**

Ensure you ran `npm install` in the project directory (where `package.json` lives), not globally.

**Q: Module version conflicts with other packages**

Delete `node_modules` and `package-lock.json`, then run `npm install` again to get a clean dependency tree.

## 3. Configuration

Express applications are configured via `app.set(setting, value)`. Settings are inherited by mounted sub-apps.

### Application Settings Reference

| Setting | Default | Values | Effect |
|---|---|---|---|
| `env` | `NODE_ENV` or `'development'` | Any string | Controls environment mode; `'production'` enables view caching |
| `etag` | `'weak'` | `'weak'`, `'strong'`, `false`, or function | ETag generation strategy |
| `jsonp callback name` | `'callback'` | Any string | Query parameter name for JSONP responses |
| `json escape` | N/A | Boolean | Escape `<`, `>`, `&` in JSON responses |
| `json replacer` | N/A | Function | Custom `JSON.stringify` replacer |
| `json spaces` | N/A | Number | JSON pretty-print indentation |
| `query parser` | `'simple'` | `'simple'`, `'extended'`, `false`, or function | Query string parser (`simple` = Node built-in, `extended` = `qs` library) |
| `subdomain offset` | `2` | Number | Number of dot-separated parts to remove for `req.subdomains` |
| `trust proxy` | `false` | Boolean, string, number, array, or function | Trust `X-Forwarded-*` headers from proxies |
| `views` | `./views` (resolved from CWD) | String or array of strings | Template view directory |
| `view cache` | `true` in production | Boolean | Cache compiled template lookups |
| `view engine` | N/A | String (e.g., `'ejs'`, `'pug'`) | Default template engine extension |
| `view` | `View` (built-in) | Constructor | Custom view class |
| `x-powered-by` | `true` | Boolean | Send `X-Powered-By: Express` header |
| `case sensitive routing` | `false` | Boolean | Treat `/Foo` and `/foo` as different routes |
| `strict routing` | `false` | Boolean | Treat `/foo` and `/foo/` as different routes |

> [!WARNING]
> The `query parser` setting defaults to `'simple'` in Express 5 (using Node's built-in `querystring` module), which does **not** support nested objects. If your application relies on nested query parameters like `?user[name]=tobi`, set `app.set('query parser', 'extended')`.

### Common Configuration Patterns

```javascript
const app = express();

// Production-ready baseline
app.set('trust proxy', 1);          // trust first proxy hop
app.set('etag', 'strong');          // strong ETags for caching
app.set('query parser', 'extended'); // nested query object support
app.disable('x-powered-by');       // hide framework fingerprint

// Template engine setup
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
```

### Environment Variable

| Variable | Purpose |
|---|---|
| `NODE_ENV` | Sets `app.get('env')`. When set to `'production'`, view caching is enabled automatically. |

> [!TIP]
> Use `app.enable('setting')` and `app.disable('setting')` as shorthand for `app.set('setting', true/false)`. Check state with `app.enabled('setting')` or `app.disabled('setting')`.

See the Admin Guide for full configuration reference with internals and compilation details.

## 4. Core Usage

### Creating an Application

```javascript
const express = require('express');
const app = express();
```

The `express()` factory returns a function that doubles as an HTTP request handler. The returned object inherits from `EventEmitter` and exposes the full application API.

### Routing

Routes map HTTP methods and URL paths to handler functions.

#### Basic Route Methods

```javascript
app.get('/users', (req, res) => {
  res.json([{ name: 'Tobi' }]);
});

app.post('/users', (req, res) => {
  res.status(201).json({ created: true });
});

app.put('/users/:id', (req, res) => {
  res.json({ updated: req.params.id });
});

app.delete('/users/:id', (req, res) => {
  res.sendStatus(204);
});
```

Express supports all HTTP methods recognized by Node.js (`get`, `post`, `put`, `delete`, `patch`, `options`, `head`, and more). Use `app.all()` to match every method on a path:

```javascript
app.all('/secret', (req, res, next) => {
  console.log('Accessing the secret section...');
  next();
});
```

#### Route Parameters

```javascript
app.get('/user/:id', (req, res) => {
  res.send(`User ${req.params.id}`);
});

// Range parameters
app.get('/users/:from-:to', (req, res) => {
  res.json({ from: req.params.from, to: req.params.to });
});
```

#### Route Objects

Use `app.route()` to chain handlers for a single path:

```javascript
app.route('/book')
  .get((req, res) => res.send('Get a book'))
  .post((req, res) => res.send('Add a book'))
  .put((req, res) => res.send('Update the book'));
```

#### Parameter Pre-Processing

Use `app.param()` to run logic before route handlers when a named parameter is present:

```javascript
app.param('user', (req, res, next, id) => {
  // load user from database
  req.user = users[id];
  next();
});

app.get('/user/:user', (req, res) => {
  res.json(req.user);
});
```

> [!NOTE]
> `app.param()` accepts an array of parameter names: `app.param(['id', 'page'], callback)`.

### Middleware

Middleware functions have access to the request, response, and the `next` function in the pipeline.

#### Application-Level Middleware

```javascript
// Runs on every request
app.use((req, res, next) => {
  console.log(`${req.method} ${req.path}`);
  next();
});

// Runs only for paths starting with /api
app.use('/api', (req, res, next) => {
  // authenticate API requests
  next();
});
```

#### Built-In Middleware

Express 5 ships five built-in middleware functions:

| Middleware | Usage | Purpose |
|---|---|---|
| `express.json()` | `app.use(express.json())` | Parse JSON request bodies |
| `express.urlencoded()` | `app.use(express.urlencoded())` | Parse URL-encoded form bodies |
| `express.raw()` | `app.use(express.raw())` | Parse raw binary request bodies |
| `express.text()` | `app.use(express.text())` | Parse plain text request bodies |
| `express.static(root)` | `app.use(express.static('public'))` | Serve static files from a directory |

```javascript
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(express.static('public'));
```

> [!IMPORTANT]
> Body parsers must be mounted **before** route handlers that read `req.body`. Without `express.json()`, `req.body` will be `undefined` for JSON requests.

#### Error-Handling Middleware

Error-handling middleware takes **four** arguments. Express recognizes the 4-argument signature as an error handler:

```javascript
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).send('Something broke!');
});
```

> [!WARNING]
> The error handler **must** have exactly four parameters `(err, req, res, next)` even if you do not use `next`. Omitting any parameter changes the function signature and Express will not recognize it as an error handler.

### Request Object (`req`)

| Property/Method | Returns | Description |
|---|---|---|
| `req.params` | Object | Named route parameters |
| `req.query` | Object | Parsed query string (depends on `query parser` setting) |
| `req.body` | Any | Parsed request body (requires body-parser middleware) |
| `req.get(header)` / `req.header(header)` | String | Request header value (case-insensitive) |
| `req.is(type)` | String/false/null | Check if Content-Type matches `type` |
| `req.accepts(types)` | String/false | Content negotiation based on Accept header |
| `req.acceptsCharsets(...charsets)` | String/Array | Check Accept-Charset |
| `req.acceptsEncodings(...encodings)` | String/Array | Check Accept-Encoding |
| `req.acceptsLanguages(...langs)` | String/Array | Check Accept-Language |
| `req.range(size, [options])` | Array/number | Parse Range header |
| `req.ip` | String | Remote IP (respects `trust proxy`) |
| `req.ips` | Array | Proxy chain IPs when `trust proxy` is set |
| `req.hostname` | String | Hostname from Host header (respects `trust proxy`) |
| `req.host` | String | Host header value (includes port if present) |
| `req.path` | String | URL pathname |
| `req.protocol` | String | `'http'` or `'https'` (respects `trust proxy`) |
| `req.secure` | Boolean | `true` if `req.protocol === 'https'` |
| `req.subdomains` | Array | Subdomain array (respects `subdomain offset`) |
| `req.fresh` | Boolean | Response cache is still valid |
| `req.stale` | Boolean | Response cache is expired |
| `req.xhr` | Boolean | `true` if `X-Requested-With: XMLHttpRequest` |

### Response Object (`res`)

| Method | Description |
|---|---|
| `res.status(code)` | Set HTTP status code (chainable). Must be integer 100–999. |
| `res.send(body)` | Send response (string → HTML, object/array → JSON, Buffer → binary) |
| `res.json(obj)` | Send JSON response |
| `res.jsonp(obj)` | Send JSON with JSONP callback support |
| `res.sendStatus(code)` | Set status and send status message as body |
| `res.sendFile(path, [options], [callback])` | Stream a file with Content-Type auto-detection |
| `res.download(path, [filename], [options], [callback])` | Prompt file download (sets Content-Disposition) |
| `res.redirect([status], url)` | Redirect (default 302) |
| `res.render(view, [locals], [callback])` | Render a template |
| `res.type(type)` / `res.contentType(type)` | Set Content-Type |
| `res.format(obj)` | Content negotiation response |
| `res.set(field, [value])` / `res.header(field, [value])` | Set response header(s) |
| `res.get(field)` | Get response header value |
| `res.append(field, value)` | Append to response header |
| `res.cookie(name, value, [options])` | Set a cookie |
| `res.clearCookie(name, [options])` | Clear a cookie |
| `res.location(url)` | Set Location header |
| `res.links(links)` | Set Link header |
| `res.vary(field)` | Add Vary header |
| `res.locals` | Object | Per-request local variables for templates |

### Template Rendering

```javascript
app.set('view engine', 'ejs');
app.set('views', './views');

app.get('/', (req, res) => {
  res.render('index', { title: 'Home', users: ['Tobi', 'Loki'] });
});
```

Register custom engine mappings with `app.engine()`:

```javascript
app.engine('html', require('ejs').renderFile);
```

> [!NOTE]
> Express auto-requires template engines by file extension. For `.ejs` files, it calls `require('ejs').__express`. Use `app.engine()` only when mapping a non-standard extension or when the engine lacks `__express`.

### Sub-Applications (Mounting)

Mount an Express app as middleware on another app:

```javascript
const admin = express();
admin.get('/', (req, res) => {
  res.send('Admin homepage');
});

const app = express();
app.use('/admin', admin);
```

Mounted apps inherit `trust proxy`, request/response prototypes, engines, and settings from their parent. The `mount` event fires on the child app when mounted. `admin.mountpath` returns `'/admin'`.

### The Express Router

Use `express.Router()` to create modular, mountable route handlers:

```javascript
const router = express.Router();

router.get('/', (req, res) => {
  res.json({ version: 1 });
});

router.get('/users', (req, res) => {
  res.json([]);
});

app.use('/api/v1', router);
```

## 5. Common Tasks

### Serve Static Files

```javascript
app.use(express.static('public'));
// Files in ./public/ are now served at the root URL
// e.g., public/css/style.css → GET /css/style.css
```

Mount at a virtual path prefix:

```javascript
app.use('/static', express.static('public'));
// public/css/style.css → GET /static/css/style.css
```

### Parse JSON Request Bodies

```javascript
app.use(express.json());

app.post('/api/data', (req, res) => {
  console.log(req.body); // parsed JSON object
  res.json({ received: true });
});
```

### Handle Form Submissions

```javascript
app.use(express.urlencoded({ extended: true }));

app.post('/login', (req, res) => {
  const { username, password } = req.body;
  // authenticate...
  res.redirect('/dashboard');
});
```

### Set and Read Cookies

```javascript
app.get('/', (req, res) => {
  res.cookie('rememberme', '1', {
    maxAge: 900000,
    httpOnly: true
  });
  res.send('Cookie set');
});
```

To clear a cookie:

```javascript
res.clearCookie('rememberme', { path: '/' });
```

> [!TIP]
> The `maxAge` option is in **milliseconds** and automatically generates an `expires` date. Express converts `maxAge` to seconds internally for the `Set-Cookie` header.

### File Downloads

```javascript
app.get('/download', (req, res) => {
  res.download('/path/to/report.pdf', 'report.pdf', (err) => {
    if (err) {
      // handle error, but check if headers were already sent
      if (!res.headersSent) {
        res.status(500).send('Download failed');
      }
    }
  });
});
```

### Content Negotiation

```javascript
app.get('/data', (req, res) => {
  res.format({
    'text/html': () => {
      res.send('<p>Hello</p>');
    },
    'application/json': () => {
      res.json({ message: 'Hello' });
    },
    'text/plain': () => {
      res.send('Hello');
    },
    default: () => {
      res.status(406).send('Not Acceptable');
    }
  });
});
```

### Build a REST API

```javascript
const express = require('express');
const app = express();

app.use(express.json());

const users = [
  { id: 1, name: 'Tobi' },
  { id: 2, name: 'Loki' }
];

app.get('/api/users', (req, res) => {
  res.json(users);
});

app.get('/api/user/:name/repos', (req, res) => {
  const user = users.find(u => u.name === req.params.name);
  if (!user) return res.sendStatus(404);
  res.json({ user: user.name, repos: [] });
});

app.listen(3000);
```

### Session Management

```javascript
const session = require('express-session');

app.use(session({
  secret: 'keyboard cat',
  resave: false,
  saveUninitialized: false
}));

app.get('/login', (req, res) => {
  req.session.user = { name: 'tobi' };
  res.send('Logged in');
});
```

### Virtual Hosts

```javascript
const vhost = require('vhost');

const api = express();
api.get('/', (req, res) => res.send('API'));

app.use(vhost('api.example.com', api));
```

### Multi-Router Architecture

```javascript
const apiV1 = express.Router();
apiV1.get('/users', (req, res) => res.json({ version: 1 }));

const apiV2 = express.Router();
apiV2.get('/users', (req, res) => res.json({ version: 2 }));

app.use('/api/v1', apiV1);
app.use('/api/v2', apiV2);
```

### Custom Error Pages

```javascript
// 404 handler (after all routes)
app.use((req, res) => {
  res.status(404).render('404', { url: req.originalUrl });
});

// Error handler
app.use((err, req, res, next) => {
  const status = err.status || 500;
  res.status(status);

  if (app.get('env') === 'development') {
    res.render('500', { error: err });
  } else {
    res.render('500', { error: {} });
  }
});
```

### HTTPS Server

```javascript
const https = require('node:https');
const fs = require('node:fs');
const express = require('express');
const app = express();

const options = {
  key: fs.readFileSync('server.key'),
  cert: fs.readFileSync('server.cert')
};

https.createServer(options, app).listen(443);
```

> [!NOTE]
> `app.listen()` creates an HTTP server internally. For HTTPS, create the server with `https.createServer()` and pass the Express app as the callback.

### User Authentication Pattern

```javascript
function restrict(req, res, next) {
  if (req.session.user) {
    next();
  } else {
    req.session.error = 'Access denied!';
    res.redirect('/login');
  }
}

app.get('/restricted', restrict, (req, res) => {
  res.send('Protected content');
});
```

### Online User Tracking

```javascript
let onlineCount = 0;

app.use((req, res, next) => {
  if (!req.session.online) {
    req.session.online = true;
    onlineCount++;
  }
  next();
});

app.get('/', (req, res) => {
  res.send(`${onlineCount} users online`);
});
```

## 6. Troubleshooting

### Diagnostic Decision Tree

1. **App won't start?** → Check Node.js version (`node -v` must be >= 18) and that `express` is in `node_modules`
2. **Route not matching?** → Check method, path, and middleware order. Routes are matched in registration order.
3. **`req.body` is undefined?** → Mount `express.json()` or `express.urlencoded()` **before** your routes
4. **Static files not serving?** → Verify the directory path passed to `express.static()` is correct relative to where you run `node`
5. **Template not found?** → Check `views` setting and `view engine` setting

### Error: `app.use() requires a middleware function`

**Cause:** You passed a non-function argument to `app.use()` without a path prefix, or passed `undefined` (often from a missing/misspelled `require`).

**Solution:**
1. Verify the middleware module is installed: `npm ls <module-name>`
2. Check spelling of the `require()` call
3. Ensure the module exports a function

**Prevention:** Always verify that imported middleware is a function before passing it to `app.use()`.

### Error: `callback function required`

**Cause:** `app.engine()` was called with a non-function second argument.

**Solution:**

```javascript
// Wrong
app.engine('html', 'ejs');

// Correct
app.engine('html', require('ejs').renderFile);
```

### Error: `No default engine was specified and no extension was provided.`

**Cause:** `res.render('viewname')` was called without setting a `view engine` and without providing a file extension.

**Solution:**

```javascript
// Option 1: Set default engine
app.set('view engine', 'ejs');
res.render('index'); // looks for views/index.ejs

// Option 2: Provide extension explicitly
res.render('index.ejs');
```

### Error: `Failed to lookup view "..." in views directory "..."`

**Cause:** The template file does not exist in the configured `views` directory.

**Solution:**
1. Check that `app.set('views', path)` points to the correct directory
2. Verify the template file exists with the correct extension
3. If using multiple view directories, pass an array: `app.set('views', [dir1, dir2])`

### Error: `path must be absolute or specify root to res.sendFile`

**Cause:** `res.sendFile()` received a relative path without the `root` option.

**Solution:**

```javascript
// Option 1: Absolute path
res.sendFile(path.join(__dirname, 'files', 'report.pdf'));

// Option 2: Use root option
res.sendFile('report.pdf', { root: path.join(__dirname, 'files') });
```

### Error: `name argument is required to req.get`

**Cause:** `req.get()` or `req.header()` was called without a header name argument, or the argument was not a string.

**Solution:** Always pass a string: `req.get('Content-Type')`.

### Error: `Invalid status code: ... Status code must be an integer.`

**Cause:** `res.status()` received a non-integer value (string, float, etc.).

**Solution:**

```javascript
// Wrong
res.status('200');
res.status(200.5);

// Correct
res.status(200);
```

**Prevention:** Always pass integer literals to `res.status()`.

### Error: `cookieParser("secret") required for signed cookies`

**Cause:** `res.cookie()` was called with `{ signed: true }` but no cookie-parser middleware with a secret is registered.

**Solution:**

```javascript
const cookieParser = require('cookie-parser');
app.use(cookieParser('my-secret'));

res.cookie('name', 'value', { signed: true });
```

> [!WARNING]
> Signed cookies require the `cookie-parser` middleware with a secret string. Without it, Express throws at response time, not at startup — this error only appears when a handler actually tries to set a signed cookie.

### Error: `Content-Type cannot be set to an Array`

**Cause:** `res.set('Content-Type', [...])` was called with an array value, which is not supported for the Content-Type header.

**Solution:** Pass a single string: `res.set('Content-Type', 'application/json')`.

### Error: `unknown value for query parser function: ...`

**Cause:** `app.set('query parser', value)` received an unsupported value.

**Solution:** Use one of the supported values: `'simple'`, `'extended'`, `false`, or a custom function.

### Issue: BigInt values cause cryptic TypeError with `res.json()` (#7186)

**Cause:** `JSON.stringify()` does not support BigInt natively. Passing an object containing BigInt values to `res.json()` throws a `TypeError` without a clear message.

**Solution:** Convert BigInt values to strings or numbers before sending:

```javascript
res.json({ id: bigintValue.toString() });
```

### Issue: Single-item array query parameter not parsed correctly (#7178)

**Cause:** When using the default `'simple'` query parser, single-element arrays in query strings may not parse as expected, particularly behind certain hosting platforms.

**Solution:** Switch to the `'extended'` query parser: `app.set('query parser', 'extended')`.

> [!CAUTION]
> When deploying behind reverse proxies (nginx, cloud load balancers), always configure `trust proxy` correctly. An incorrect setting causes `req.ip`, `req.protocol`, `req.hostname`, and `req.secure` to return wrong values, potentially breaking redirects, HTTPS detection, and rate limiting.

### Issue: Mounting at `'//'` does not work as expected (#4557)

**Cause:** `app.use('//', handler)` does not mount at the double-slash path as one might expect.

**Solution:** Avoid double-slash mount paths. Use single-slash paths and handle URL normalization upstream in your reverse proxy.

### Debugging

Enable Express debug logs by setting the `DEBUG` environment variable:

```bash
DEBUG=express:* node app.js
```

```text
express:application booting in development mode +0ms
express:router use / query +2ms
express:router:route new / +0ms
```

Narrow debug output to specific modules:

| Pattern | Shows |
|---|---|
| `express:application` | App initialization and settings |
| `express:router` | Route matching and dispatch |
| `express:view` | Template lookup and rendering |

## 7. FAQ

**Q: How do I structure a large Express application?**

Use the Router to split routes into separate files by feature or resource. Each file exports a router, and the main app mounts them with `app.use('/prefix', router)`. See the `examples/route-separation` and `examples/multi-router` patterns included in the Express repository.

**Q: How do I handle async/await errors in route handlers?**

Express 5 automatically catches rejected promises from async route handlers and forwards the error to your error-handling middleware. You do not need a `try/catch` wrapper or a separate `asyncHandler` utility.

**Q: Can I use Express with TypeScript?**

Yes. Install `@types/express` for type definitions: `npm install --save-dev @types/express`. Express itself is written in JavaScript, but TypeScript typings are maintained by the DefinitelyTyped community.

**Q: How do I disable the `X-Powered-By` header?**

```javascript
app.disable('x-powered-by');
```

**Q: What is the difference between `res.send()` and `res.json()`?**

`res.send()` auto-detects the body type: strings are sent as HTML, objects/arrays are serialized as JSON (delegating to `res.json()`), and Buffers are sent as binary. `res.json()` always serializes as JSON and respects `json replacer`, `json spaces`, and `json escape` settings.

**Q: How do I serve an SPA (Single-Page Application) with Express?**

Serve static assets with `express.static()`, then add a catch-all route that sends your `index.html`:

```javascript
app.use(express.static('dist'));
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});
```

**Q: How do I redirect HTTP to HTTPS?**

```javascript
app.set('trust proxy', 1);
app.use((req, res, next) => {
  if (!req.secure) {
    return res.redirect(301, `https://${req.hostname}${req.originalUrl}`);
  }
  next();
});
```

**Q: How do I set cookies that cannot be accessed by client-side JavaScript?**

Use the `httpOnly` option: `res.cookie('session', token, { httpOnly: true, secure: true })`.

**Q: What query parser should I use?**

Use `'simple'` (default) for flat key=value pairs. Use `'extended'` if your frontend sends nested objects (`user[name]=tobi`) or arrays (`colors[]=red&colors[]=blue`).

**Q: Does `app.get()` handle settings and routes?**

Yes. With one argument, `app.get('setting')` returns a setting value. With two or more arguments, `app.get('/path', handler)` defines a GET route. This dual behavior is intentional.

**Q: How do I handle CORS?**

Use the `cors` middleware package (`npm install cors`) or set headers manually:

```javascript
app.use((req, res, next) => {
  res.set('Access-Control-Allow-Origin', '*');
  res.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
  res.set('Access-Control-Allow-Headers', 'Content-Type');
  next();
});
```

---

_Generated May 2026 from expressjs/express at 6340c1e. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
