How the stack works
When you callclient.send(command):
- Input parameters enter the top of the stack.
- Each middleware calls the next one in order, passing the (potentially modified) arguments.
- The HTTP handler sends the request to the service.
- The response travels back up through the same middleware in reverse order.
- The deserialized output is returned to your code.
Lifecycle steps
Every middleware is assigned to one of five lifecycle steps, executed in this order:| Step | Purpose |
|---|---|
initialize | Adds default input values. The HTTP request has not been constructed yet. |
serialize | Builds the HTTP request from input parameters. Validates input and creates the request object. Downstream middleware have access to args.request. |
build | Augments the serialized request with stable headers such as Content-Length or a body checksum. Changes here apply to all retry attempts. |
finalizeRequest | Prepares the request for transmission: request signing, retry logic, hop-by-hop headers. The request is semantically complete at this stage. |
deserialize | Converts the raw HTTP response into a structured output object. The upstream middleware have access to result.output. |
Adding middleware
Useclient.middlewareStack.add() to insert a function into the stack. Middleware added to a client applies to all commands sent by that client.
next: The next middleware in the stack. You must call it and return its result (unless you intentionally short-circuit).context: An object containingclientNameandcommandName, plus any data shared across middleware.args.input: The command’s input parameters.args.request: The serialized HTTP request object (available from thebuildstep onward).result.output: The deserialized response (available from thedeserializestep onward).
Options
A unique identifier for this middleware. Used when removing it or preventing duplicates with
override.The lifecycle step to attach to:
"initialize", "serialize", "build", "finalizeRequest", or "deserialize".Execution order within a step.
"high" runs before normal middleware; "low" runs after.When
true, replaces any existing middleware with the same name instead of adding a second copy. Provide both name and override: true to avoid accidental duplication.Arbitrary labels for grouping or identifying middleware. Not used by the SDK itself.
Removing middleware
Remove middleware by the name you assigned when adding it:Examples
Logging requests and responses
This example from the SDK README logs the command context, input parameters, and output for every operation sent by the client:Injecting request headers
Add a custom header to every request. Becauseargs.request is available at the build step and persists across retries, this is the right place for stable header injection:
Detailed request/response logging
For full request and response debugging, logargs.request and result.response directly:
Specifying priority
When you need to control the order of multiple middleware within the same step, use thepriority option:
Client-level vs command-level middleware
Middleware added toclient.middlewareStack applies to every command sent by that client.
You can also add middleware to a single command instance’s middleware stack. It will apply only to that specific invocation:
For more detail on the middleware stack design, see the AWS SDK blog post on middleware.