---
url: https://node-ts.github.io/bus/guide/middleware.md
description: >-
  Run code around every message the bus reads, before and after it's dispatched
  to handlers.
---

# Middleware

Message read middleware runs between the bus reading a message from the transport and dispatching it to handlers. It wraps the handling of each message, so it can run code before and after it. This page shows two common uses.

A middleware is a function that gets the message as the transport read it and a `next` function. Calling `next()` runs the next middleware, and then the handlers. Register middleware with `withMessageReadMiddleware()`; several run in the order they're registered. It also runs for messages passed to a [receiver](/transports/sqs-lambda).

## Timing messages

Telemetry such as AWS X-Ray, New Relic or Datadog can profile message handling with middleware. That helps find the messages that take longest to handle, and would benefit from tuning.

```ts
const timeMessages: Middleware<TransportMessage<unknown>> = async (
  message,
  next
) => {
  const start = performance.now()
  // Dispatches the message to the next middleware, and then its handlers
  await next()
  console.log('Message handled', {
    messageName: message.domainMessage.$name,
    durationMs: Math.round(performance.now() - start)
  })
}

const bus = Bus.configure()
  .withMessageTypes(messageTypes)
  .withMessageReadMiddleware(timeMessages)
  .build()
```

## Adding context to logs

Middleware can also give every log written while handling a message the context of that message, such as its correlation id. Run `next()` inside an `AsyncLocalStorage`, and have your [logger](/guide/loggers/custom-loggers) read the store:

```ts
interface LogContext {
  correlationId: string | undefined
  messageName: string
}

/**
 * Holds the context of the message being handled, for the logger to add to
 * every log written while handling it
 */
export const logContext = new AsyncLocalStorage<LogContext>()

Bus.configure().withMessageReadMiddleware(async (message, next) =>
  logContext.run(
    {
      correlationId: message.attributes.correlationId,
      messageName: message.domainMessage.$name
    },
    next
  )
)
```

Outside middleware, code that a handler calls can read the message being handled with `bus.getHandlingContext()`.

## See also

* [Lifecycle hooks](/guide/lifecycle-hooks), to react to events without wrapping the handling
* [Correlation id](/guide/message-attributes/correlation-id)
* [`Middleware`](/api/bus-core/type-aliases/Middleware) in the API reference
