---
title: Middleware
---

# Middleware

Used to extend the built-in Web Server of Modern.js, unlike [Hook](/apis/app/runtime/web-server/hook), Middleware can directly operate Node's origin request and response, and can be extended using the framework plugin.

:::note

In the next major release, Modern.js will use new middleware to replace this approach.

It is recommended to use [UnstableMiddleware](/apis/app/runtime/web-server/unstable_middleware) to handle page requests.

:::

:::note

For more detail, see [Extend Web Server](/guides/advanced-features/web-server).

:::

## Usage

```ts
import { Middleware } from '@modern-js/runtime/server';

export const middleware: Middleware = async (context, next) => {};
export const middleware: Middleware[] = [
  async (context, next) => {},
  async (context, next) => {},
];
```

:::info
Before using this API, please execute `pnpm run new` to create a new "Custom Web Server" source code directory.

```bash
pnpm run new
? Please select the operation you want: Create Element
? Please select the type of element to create: New "Custom Web Server" source code directory
```

:::

## Function Signature

```ts
type Middleware = (
  context: MiddlewareContext,
  next: NextFunction,
) => Promise<void> | void;

type MiddlewareContext = {
  response: {
    set: (key: string, value: string) => void;
    status: (code: number) => void;
    getStatus: () => number;
    cookies: {
      set: (key: string, value: string, options?: any) => void;
      clear: () => void;
    };
    raw: (
      body: string,
      { status, headers }: { status: number; headers: Record<string, any> },
    ) => void;
    locals: Record<string, any>;
  };
  request: {
    host: string;
    pathname: string;
    query: Record<string, any>;
    cookie: string;
    cookies: {
      get: (key: string) => string;
    };
    headers: IncomingHttpHeaders;
  };
  source: {
    req: IncomingMessage;
    res: ServerResponse;
  };
};
```

### Input

- `context`: Middleware context.
  - `response`: provides a series of methods to process the response.
  - `request`: provides a series of methods to get request info.
  - `source`: provides Node.js native `req` and `res` object.
- `next`: call next listener (not affect the server process, only current hook).

:::warning
The execution of the `next` function does not affect built-in processes, only controls whether the next middleware executes. Rendering processes are interrupted only when the response is written.
:::

## Example

### Tracking

```ts
export const Middleware = () => async (ctx, next) => {
  const start = Date.now();
  ctx.source.res.once('finish', () => {
    console.log(Date.now() - start);
  });
};
```

### Inject Tools & Data

Modern.js provides `res.locals` to store local variables for the current request.

```ts
export const Middleware = () => async (ctx, next) => {
  ctx.response.locals.id = 'Modern.js';
  ctx.response.locals.rpc = createRpcInstance();
};
```

### Framework Extension

Middleware can also use runtime framework extensions like BFF.

When using framework runtime extensions, type information is exported from `@modern-js/runtime/{namespace}`. Middleware can use framework syntax, such as framework middleware writing, the following is pseudo-code:

```ts
import { SomeType } from '@modern-js/runtime/{namespace}';

export const middleware: SomeType = (ctx, next) => {
  console.log(ctx.url);
  next();
};
```

By default, the framework extension capability of Web Server is turned off after installing the framework extension plugin. If you want to use the framework extension, you can turn it on through ['server.enableFrameworkExt'](/configure/app/server/enable-framework-ext.html).

:::info
The type name exported by the framework extension may not 'Middleware', but is named by the framework extension plugin.
:::
