middlewareStack property. You can add custom behavior to any step of the request lifecycle — logging, header injection, retry hooks, and more — without modifying client internals.
Middleware function anatomy
A middleware is a higher-order function with this signature:context properties:
| Property | Type | Description |
|---|---|---|
clientName | string | e.g., "S3Client" |
commandName | string | e.g., "GetObjectCommand" |
logger | Logger | The client’s logger instance |
inputFilterSensitiveLog | Function | Redacts sensitive fields from input |
outputFilterSensitiveLog | Function | Redacts sensitive fields from output |
The five lifecycle steps
initialize — args.input only
initialize — args.input only
The API call is being set up. Default option values are injected and derived parameters computed. No HTTP request exists yet.Available in
args: input only.Typical uses: injecting default input values, validating logical constraints before serialization.serialize — HTTP request is constructed
serialize — HTTP request is constructed
The input is serialized into an HTTP request. Input validation runs here. The downstream middleware receives
args.request.Available in args: input, request (newly created).Typical uses: inspecting or validating the serialized request before it is modified.build — modify stable request headers
build — modify stable request headers
The HTTP request exists and can be modified. Any changes here apply to all retries. This is the most common step for injecting custom headers.Available in
args: input, request.Typical uses: adding custom headers (Content-Length, checksums, correlation IDs), logging the raw request.finalizeRequest — signing and retries
finalizeRequest — signing and retries
The request is semantically complete. This is where request signing and retry logic run. Only alter the request to match recipient expectations (hop-by-hop headers, auth signatures).Available in
args: input, request (signed on downstream pass).Typical uses: retry hooks, custom auth headers, conditional request modification.deserialize — result.output available
deserialize — result.output available
The raw HTTP response is deserialized into a structured JavaScript object. Upstream middleware (running after
await next(args)) see the final result.output.Available in result: output (structured response), response (raw HTTP).Typical uses: inspecting response metadata, transforming output, recording metrics.middlewareStack.add(middleware, options)
Adds middleware at an absolute position in a step.
Which lifecycle step to run in. One of:
"initialize", "serialize", "build", "finalizeRequest", "deserialize".Unique string identifier. Required when using
override: true or remove().Execution order within the step.
"high" runs first, "low" runs last. When two middleware share the same priority, they run in insertion order.Array of string tags. Used with
removeByTag() to remove groups of middleware.When
true, replaces any existing middleware with the same name instead of throwing. Provide both name and override: true to avoid accidental duplication.middlewareStack.addRelativeTo(middleware, options)
Adds middleware relative to another named middleware, regardless of step.
"before" to run before the target middleware, "after" to run after.The
name of the middleware to position relative to.Identifier for the new middleware.
Tags for the new middleware.
Replaces an existing middleware with the same name.
middlewareStack.remove(nameOrTag)
Removes a single middleware by name. Returns true if a middleware was removed, false otherwise.
middlewareStack.removeByTag(tag)
Removes all middleware with the given tag. Returns true if any middleware were removed.
middlewareStack.clone()
Returns a deep copy of the stack. Useful when you need to create a modified stack for a single command without affecting the client’s global stack.
middlewareStack.concat(stack)
Merges another MiddlewareStack into this one and returns the result. The original stacks are not mutated.
middlewareStack.use(plugin)
Applies a plugin to the stack. A plugin is any object with an applyToStack(stack) method, which is called with the middleware stack as its argument.
Per-command middleware
Middleware can be added to an individual command instance instead of the client. It is merged with the client stack only for that invocation.Examples
Logging all requests and responses
Injecting a custom header on every request
Measuring operation latency
Custom header that must be present on retries
Middleware stack and cacheMiddleware
By default the resolved middleware function stack is rebuilt on every request, allowing you to modify the stack at any time. If you enable cacheMiddleware: true on the client, the stack is compiled once per (client, command class) pair and reused. This reduces per-request overhead by a few milliseconds but means that stack modifications after the first request have no effect.