# How to Add Custom Middleware to AWS SDK v3 Clients to Intercept Requests

> Learn to add custom middleware to AWS SDK v3 clients to intercept requests. Modify arguments and responses seamlessly before they reach the network layer.

- Repository: [Amazon Web Services/agent-toolkit-for-aws](https://github.com/aws/agent-toolkit-for-aws)
- Tags: how-to-guide
- Published: 2026-06-29

---

**You can intercept every AWS SDK v3 request by calling `client.middlewareStack.add()` with a custom function that transforms arguments or responses before they reach the network layer.**

The AWS SDK for JavaScript v3 provides a centralized middleware architecture that allows you to intercept, modify, and monitor requests across all API calls. By leveraging the `middlewareStack` property available on every client instance, you can inject custom logic without modifying individual command invocations. The **agent-toolkit-for-aws** repository documents this pattern extensively, providing production-ready examples for logging, header injection, and request transformation.

## How the Middleware Stack Works in AWS SDK v3

The SDK processes every command through a fixed pipeline of five discrete steps. Each step represents a phase in the request lifecycle, allowing you to hook into specific points depending on your interception needs.

The execution order is:

1. **initialize** – Resolves configuration values like region and credentials
2. **serialize** – Converts command input into HTTP request format
3. **build** – Applies user-defined transformations (logging, custom headers)
4. **finalizeRequest** – Handles signing, retries, and endpoint resolution
5. **deserialize** – Parses the HTTP response back into typed output

A custom middleware is a higher-order function receiving `next` and `context` parameters, returning an async function that processes `args`. The `context` object contains metadata such as `commandName`, while `args` carries the request payload. Calling `await next(args)` passes control to the next middleware in the chain.

### Middleware Configuration Options

When adding middleware via `client.middlewareStack.add()`, you must specify:

- **name**: A unique identifier for the middleware
- **step**: The pipeline phase (`"initialize"`, `"serialize"`, `"build"`, `"finalizeRequest"`, or `"deserialize"`)
- **override**: Boolean flag to replace existing middleware with the same name (default: `false`)

## Adding Custom Middleware to an AWS SDK v3 Client

Insert your middleware after constructing the client but before the first `send()` call. The stack becomes immutable once a request dispatches, so configure all middleware during client initialization.

```typescript
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3";

// Create client outside handlers for Lambda container reuse
const client = new S3Client({ region: "us-east-1" });

// Add logging middleware to intercept all requests
client.middlewareStack.add(
  (next, context) => async (args) => {
    console.log("[Middleware] Command:", context.commandName);
    console.log("[Middleware] Input:", args.input);
    
    const result = await next(args);
    
    console.log("[Middleware] Result:", result);
    return result;
  },
  {
    name: "RequestLogger",
    step: "build",
    override: false,
  }
);

// Middleware runs automatically for every subsequent command
const output = await client.send(
  new GetObjectCommand({ Bucket: "my-bucket", Key: "example.txt" })
);

```

This example, found in [`skills/core-skills/aws-sdk-js-v3-usage/SKILL.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-sdk-js-v3-usage/SKILL.md), demonstrates the `"build"` step which executes after serialization but before request signing.

## Advanced Middleware Use Cases for AWS SDK v3

Different interception points serve different operational needs:

- **Request modification** (`"build"` step): Inject headers like correlation IDs or authentication tokens by modifying `args.request.headers`
- **Payload transformation** (`"serialize"` step): Encrypt or compress `args.input` before it becomes the HTTP body
- **Throttling** (`"initialize"` step): Implement rate limiting by inspecting `context` and rejecting calls early
- **Tracing integration** (`"finalizeRequest"` step): Add OpenTelemetry trace identifiers immediately before signing
- **Global error handling** (`"deserialize"` step): Capture SDK errors and emit metrics after response parsing

According to [`skills/core-skills/aws-sdk-js-v3-usage/references/clients.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-sdk-js-v3-usage/references/clients.md), the `"finalizeRequest"` step is ideal for operations that must occur after the SDK has resolved endpoints and calculated signatures but before network transmission.

## Performance Considerations When Adding Middleware

The AWS SDK v3 enables `cacheMiddleware: true` by default, which caches the resolved middleware stack per client and command combination. When adding custom middleware, maintain this caching behavior to avoid rebuilding the stack on every invocation.

Critical constraints:

- **Immutable after dispatch**: You cannot modify `middlewareStack` after the first `send()` call completes
- **Startup cost**: Add middleware during cold start, not inside Lambda handlers
- **Memory**: Long-lived clients with large middleware chains retain memory between invocations

Reference [`skills/core-skills/aws-sdk-js-v3-usage/references/performance.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-sdk-js-v3-usage/references/performance.md) for detailed guidance on optimizing middleware overhead in serverless environments.

## Key Source Files in agent-toolkit-for-aws

The repository provides authoritative documentation for SDK v3 middleware patterns:

- **[`skills/core-skills/aws-sdk-js-v3-usage/SKILL.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-sdk-js-v3-usage/SKILL.md)**: Contains the primary middleware example and step-by-step usage instructions
- **[`skills/core-skills/aws-sdk-js-v3-usage/references/clients.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-sdk-js-v3-usage/references/clients.md)**: Documents the middleware stack architecture, step ordering, and caching behavior
- **[`skills/core-skills/aws-sdk-js-v3-usage/references/performance.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-sdk-js-v3-usage/references/performance.md)**: Covers `cacheMiddleware` optimization and cold-start considerations
- **[`skills/core-skills/aws-sdk-js-v3-usage/references/effective-practices.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-sdk-js-v3-usage/references/effective-practices.md)**: References `@smithy/middleware-endpoint` and other extension points
- **[`plugins/aws-core/skills/aws-sdk-js-v3-usage/SKILL.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/plugins/aws-core/skills/aws-sdk-js-v3-usage/SKILL.md)**: Mirrors the core skill for plugin-specific implementations

## Summary

- **AWS SDK v3 clients** expose a `middlewareStack` property that accepts custom interception functions
- **Five pipeline steps** (`initialize`, `serialize`, `build`, `finalizeRequest`, `deserialize`) determine when your middleware executes
- **The `"build"` step** is optimal for most request modifications like logging and header injection
- **Configure middleware** immediately after client construction and before the first `send()` call, as the stack becomes immutable after dispatch
- **Enable caching** (`cacheMiddleware: true`) to prevent performance degradation from stack reconstruction

## Frequently Asked Questions

### Can I add middleware to an existing AWS SDK v3 client after it has sent requests?

No. The `middlewareStack` becomes immutable once the client dispatches its first request. You must add all middleware immediately after constructing the client instance and before calling any `send()` methods. This design ensures deterministic request processing and enables internal caching optimizations.

### Which middleware step should I use to add custom HTTP headers?

Use the **`"build"`** step. This phase executes after the SDK serializes the command input into an HTTP request object but before the `"finalizeRequest"` step applies signing and endpoint resolution. At this point, you can safely modify `args.request.headers` to inject correlation IDs, authentication tokens, or custom metadata.

### How does custom middleware affect AWS SDK v3 performance?

When properly configured with `cacheMiddleware: true` (the default), custom middleware adds negligible overhead after the initial cold start. The SDK caches the resolved middleware chain per client/command combination. However, adding middleware inside Lambda handlers or disabling caching forces stack reconstruction on every invocation, significantly impacting latency.

### Where can I find production-ready examples of AWS SDK v3 middleware?

The **agent-toolkit-for-aws** repository maintains canonical examples in [`skills/core-skills/aws-sdk-js-v3-usage/SKILL.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/skills/core-skills/aws-sdk-js-v3-usage/SKILL.md) and [`references/clients.md`](https://github.com/aws/agent-toolkit-for-aws/blob/main/references/clients.md). These files demonstrate logging middleware, header injection, and performance configurations tested against current SDK versions.