Some GETs build the same JSON for every anonymous caller. Running the action every time is wasted work. Output caching stores that response. It is not the tool that remembers a computed price inside a command.
The object cache, including Redis, is the caching guide. This post does not repeat it. Hub: Caching.
Real-world analogy
IMemoryCache is a note on the prep counter: the cook still cooks, but they glance at the note for the oven temperature. Output cache is a tray of plated lunches under a lamp. The next identical order does not go back through the kitchen. The danger is handing table 4 the plate you made for table 9 because the orders looked similar and the ticket had a name you ignored.
Worked example
GET /api/v1/categories hits the database 40 times a minute and returns the same twelve rows. Adding IMemoryCache inside the action still runs routing, the action, and the serializer. .CacheOutput() on that endpoint returns the stored body and skips the action until the window ends. The same attribute on GET /api/v1/orders, which depends on the caller, serves the first user's orders to the second user for 30 seconds. Take the attribute off any route that reads the current user, or vary the cache by a claim you set yourself. Do not vary by the raw Authorization header and then log that key.
| Store | What is saved | Skip the action? |
|---|---|---|
IMemoryCache | An object you name | No |
| Output cache | The HTTP response | Yes |
| Redis (see the other guide) | A value every instance can read | No, unless you build that yourself |
Code
builder.Services.AddOutputCache();
app.UseOutputCache();
app.MapGet("/api/v1/categories", ListCategories)
.CacheOutput(policy => policy.Expire(TimeSpan.FromSeconds(30)));
UseOutputCache sits after routing, with the rest of the pipeline you already ordered in middleware order. A 30-second window is a product decision. A catalog that changes when an admin clicks save needs a tag eviction or a shorter window, not a hope that nobody notices. Authenticated order lists stay uncached.
Public catalog reads of this shape: Ecom_NET10.