When Apache APISIX proxy-cache fits your API traffic
The proxy-cache plugin fits read-heavy APIs where backends repeat identical work. If many clients request the same product catalog, reference data or public content, and the upstream recomputes the same answer each time, the gateway can store the upstream response and serve repeats without calling the service. The APISIX proxy-cache plugin does this at the gateway layer. By default it stores entries on disk, though memory is also available, builds the cache key from the host and request URI, caches GET and HEAD requests that return status 200, 301 or 404, and keeps entries for 300 seconds. Those defaults are a starting point, not a recommendation for your traffic, so confirm each one against the responses your services actually return.
Caching at the gateway does not fix a slow or inefficient backend. It hides the cost for some requests, while cache misses still reach the service and writes still go through unchanged. Before enabling the plugin, check whether the expensive query can be indexed, whether the service can return correct Cache-Control headers, and how often the underlying data changes. A short TTL on volatile data may save little, while a long TTL on data that changes often will serve stale answers.
Authenticated responses need particular care. Since 3.17.0, the plugin partitions the cache by authenticated identity by default, so one user's response should not be served to another. Confirm that your authentication plugin sets the identity before the cache lookup, and test with two different consumers to verify isolation. Responses containing personal data, session tokens or account-specific financial figures should be excluded from caching entirely, and the exclusion rules belong in your design review, not only in the gateway configuration.
Proxy-cache options and when each fits
This table compares the main proxy-cache settings against their documented defaults and the situations where each one should change. Read the default column first, then check the trade-off before you move away from it. Confirm exact parameter names and schema on the proxy-cache plugin page before you write any configuration.
| Option | Default and what it does | When to change it and the trade-off |
|---|---|---|
| Cache storage (disk or memory) | Disk is the default storage, per the proxy-cache docs | Memory suits small, hot responses where latency matters most, but cached entries compete with node memory. Disk holds more data and survives more load, at the cost of slower reads than memory. |
| cache_key | Host and request URI by default | Add variables only when responses differ by them, such as a language header. Every added variable splits the cache into more entries, which lowers hit rates and raises storage use. |
| cache_method | GET and HEAD by default | Keep the default for most APIs. Caching other methods is rarely safe, since a write request that returns a cached response can hide a change from the client. |
| cache_http_status | 200, 301 and 404 by default | Remove 404 if missing resources are created often, so clients do not see stale not-found results. Add other statuses only for responses you can justify as safe to replay. |
| cache_ttl | 300 seconds by default | Shorten the TTL for data that changes often or drives decisions, and lengthen it for reference data. A longer TTL reduces backend load but increases the window in which clients see outdated data. |
| Per-identity partitioning | On by default since 3.17.0, keyed to the authenticated identity | Leave it on for any route that returns user-specific data. Turning it off lets one consumer receive another consumer's cached response, so confirm the exact behavior on the plugin page before any change. |
| Upstream Cache-Control handling | Confirm the behavior for your APISIX version on the plugin page | Decide whether upstream cache headers should override your TTL. If services send accurate headers, honoring them keeps policy in one place. If they send none or inaccurate ones, set the TTL at the gateway and test it. |
Setting up proxy-cache on a route
This sequence takes proxy-cache from an idea to a verified setting on one low-risk route. Each step ends with a check, so you know whether to continue, adjust or roll back before the cache reaches more traffic.
Confirm the upstream sends cacheable responses
Before enabling anything, your platform engineers call the chosen endpoint directly, bypassing the gateway, and record its status codes, Cache-Control, Expires, Vary and Set-Cookie headers. Confirm the responses for the route are the same for every caller that would share a cache entry. Done when you have a written note for the route stating which responses are safe to store and why. If the upstream sets cookies or varies by user without a Vary header, plan to fix that first or pick a different route.
Choose a single non-sensitive route
Select one read-heavy route whose responses contain no personal, financial or health data and no per-user content. Avoid routes behind authentication plugins until you have confirmed how identity affects the cache key. Record the route ID, the upstream it targets and the owner who can answer questions about its data. Done when the route is named in your change record and its owner has agreed to the test window.
Enable proxy-cache on the route
Add the proxy-cache plugin to the route through the Admin API or your configuration-as-code repository, leaving the defaults in place for the first test. The defaults cache GET and HEAD responses with status 200, 301 and 404 for 300 seconds, and use disk storage. Look up the exact configuration keys in the proxy-cache plugin documentation rather than copying settings from older examples. Done when the Admin API returns the route with the plugin attached and no validation error.
Choose storage, cache keys and TTLs
Decide between disk and memory storage based on response size, expected volume and how much memory the gateway nodes can spare. Review the default cache key, which uses the host and request URI, and add any request header or query parameter that changes the response. Set TTLs and the methods and status codes to cache, keeping them as narrow as the route needs. Confirm each choice with the owner of the upstream. Done when the final values are committed to the same place as the route definition and reviewed by a second person.
Verify misses and hits with response headers
Send the same request twice from the same client and read the cache status header that the plugin adds to responses. The first response should report a miss and the second should report a hit, while the upstream access log shows a single request. Then send a request with a different query string and confirm it is treated as a separate cache entry. Done when the miss, hit and key-separation results match what your configuration should produce.
Check cache state through the Admin API
Query the Admin API for the route and confirm the plugin configuration matches the reviewed values, then check the gateway logs and metrics for unexpected errors or storage growth. Watch the cache directory or memory usage over a short period of normal traffic. Done when the stored configuration matches the change record and no error or storage trend requires a change. Note that the Admin API port and access control should follow your hardening standards, and confirm that access before using it.
Test the rollback path
Remove the plugin from the route, or disable it through your configuration-as-code process, and send the same requests again. Confirm that every response now comes from the upstream and that the cache status header no longer appears. Record how long the removal took to apply in your own environment and who has permission to perform it. Done when the rollback has been tested in a non-production environment and the team knows the exact steps to repeat it in production.
Data that must never be cached at the gateway
A gateway cache serves the same stored copy to every caller that matches its key, so one wrong rule can expose one user's data to another. The cards below cover the categories to exclude in proxy-cache and how to scope each exclusion by method, status code and route before the plugin goes live.
Personal and regulated data
Responses that carry personal, health, payment or other regulated data should stay out of the cache, even when the request is a GET. Set the cache to apply only to routes that serve public or non-personal content, and keep account, profile and record endpoints out of scope by route. Ask the data owner and your compliance lead to sign off on each cached route, because the cache holds a copy outside the service that owns the data.
Tokens and session data
Responses that issue, refresh or echo tokens, cookies or session identifiers must never be stored and replayed. If an authenticated response is cached under a shared key, a later caller may receive another user's credentials. Exclude token endpoints, login callbacks and any route that sets a Set-Cookie header. Confirm the cache honors your authentication plugin ordering, so responses from authenticated routes are not written before identity is checked.
Responses varying by headers outside the key
By default proxy-cache keys on host and request URI, so a response that changes with Authorization, Accept-Language, tenant headers or a cookie will be served to callers who send different values. Either add those headers to the cache key or exclude the route. Review each route's upstream logic for header-based variation, and test with two different headers before enabling caching. This is the most common source of silent data leaks.
Write methods
POST, PUT, PATCH and DELETE change state on the upstream, so replaying a stored response would skip the write and report success falsely. Limit the cache to GET and HEAD, which is also the default behavior, and confirm the plugin configuration does not add other methods. A cached response to a write can also mislead clients into thinking the change happened on a fresh request.
Error responses that mask outages
Caching a 500 or 503 keeps a failure in place for the full TTL after the upstream recovers. The default list includes 404 and 301 along with 200, so review that list for each route. Remove error codes from the cached statuses, use a short TTL for any route where a 404 could appear after a resource is created, and test the recovery path by stopping an upstream during a load test.
Responses with private Cache-Control
When the upstream marks a response private or no-store, the origin has told shared caches not to keep it. Confirm how your APISIX version interprets upstream Cache-Control headers before relying on it, and do not assume the gateway will honor every directive. Where the origin's headers are unreliable, enforce the exclusion in the route configuration instead. Ask your upstream team to label private responses consistently.
How upstream Cache-Control headers interact with proxy-cache
The first thing to confirm is whether the proxy-cache plugin in your deployed APISIX version honors the caching directives your upstream services send, such as Cache-Control, Expires and Vary, or whether it applies only the TTL and key rules you configure on the route. The supplied facts establish the plugin's defaults: it caches GET and HEAD responses with status 200, 301 and 404 for 300 seconds, and it partitions by authenticated identity since 3.17.0. They do not establish how the plugin reads upstream headers, so do not assume either behavior. Treat header handling as a version-specific question and answer it from the proxy-cache plugin documentation for the exact release you run.
Test the behavior before you rely on it. Build a short test route in a non-production environment that returns responses with known headers: one with a Cache-Control value that forbids storage, one with a max-age shorter than the configured TTL, one with Vary set on a request header, and one with no caching headers at all. Send each request twice and record whether the second response is served from cache. Watch for the cache status indicator the plugin exposes in its response headers, and confirm the header name in the docs for your version. Repeat the test with an authenticated consumer to check that the upstream headers do not defeat per-identity partitioning.
Check the APISIX CHANGELOG for entries on proxy-cache between your current version and the target version, and record any change to header handling in your upgrade notes. Decide in advance which rule wins when the upstream and the gateway disagree, and document it for the service owners. If the plugin ignores upstream directives in your version, either set the TTL and bypass conditions at the gateway explicitly or keep caching decisions in the service. Either way, a confirmed test result, not the default, should decide the configuration.
Security and operational risks of caching API responses
Caching at the gateway saves upstream calls, but it also stores responses that may belong to someone else, may have been shaped by an attacker, and may outlive the data they describe. The cards below cover the risks that connect the cache key, the storage tier, and the invalidation rules, and the checks to run before a route is cached.
Cross-user data leaks from shared keys
If two users request the same host and URI and the cache does not separate them, one user can receive another user's account data from a cached response. Since 3.17.0, the proxy-cache plugin partitions the cache by authenticated identity by default, but you should confirm that behavior in your version and test it with two accounts. Also check that responses carrying personal data are not cached on routes where identity is set by a header instead of an authenticated credential.
Cache poisoning through request inputs
A cache key built only from host and URI means that any request input left out of the key can change what gets stored. Query strings, headers the upstream reads, or request bodies that alter the response can let a crafted request store a bad response that is then served to everyone. Review which headers and parameters the upstream uses, add them to the key where they change the response, and avoid caching routes that accept free-form input.
Disk capacity and eviction planning
The default disk cache lives on each gateway node, so capacity is consumed per node and not shared across the cluster. Plan the cache size against the number of cacheable routes, the response sizes, and the TTL, and check how eviction behaves when the disk fills. In decoupled or traditional deployments with several data plane nodes, each node builds its own cache, so a cold node will miss until it warms up.
Invalidation and purge gaps
A cached response stays valid until its TTL expires unless something removes it, so a fix deployed upstream may not reach users for minutes. Confirm how your APISIX version exposes cache purge, whether it applies to all nodes, and who is allowed to trigger it. Make the purge step part of the release runbook for any cached route, and test it on a staging gateway before relying on it.
Method and status code rules
The plugin caches GET and HEAD responses with status 200, 301 and 404 by default, and any change to those lists is a decision about what can be replayed. Caching a 404 or a redirect that depends on the caller can serve the wrong answer to later clients. Keep the lists narrow, and review each route when the upstream adds new response codes or conditional logic.
Stale data and hit ratio monitoring
A high hit ratio can hide stale or incorrect responses, so track the ratio alongside error rates and the age of served content. Add cache status to access logs or metrics so you can tell a hit from a miss during an incident. Ask your operations team to define an alert for an unexpected drop or rise in hits on a route, and to review the logs when a customer reports an out-of-date value.
Questions teams ask before caching API responses
What drives the cost of a proxy-cache rollout?
The main cost driver is how many routes need caching and how much each one needs to be verified. Each cacheable route requires a decision on its cache key, methods, status codes and TTL, plus tests that prove authenticated and sensitive responses are never shared. The cost also depends on whether the cache sits alone or alongside rate limiting, authentication changes and observability, and on whether you run disk or memory storage on nodes you already operate. Ask for a quote that lists the routes in scope, the environments covered, the test cases and the handover material. Most of the work is one-time design and verification. Ongoing cost comes from reviewing cache rules as APIs change and from monitoring hit rates and stale responses.
How long does a proxy-cache pilot take, and what sets that length?
The length of a pilot depends on the number of routes, how many upstream services they call, and how much existing behavior must be proven unchanged. A pilot on one or two read-only routes usually moves faster than a pilot that spans several teams' services with different Cache-Control habits. Other factors include access to a staging environment that mirrors production traffic, the time needed to agree on what data may never be cached, and any change windows for the gateway. A fixed-scope engagement sets the timeline in writing before work starts, so ask for the milestones and the client dependencies behind each one.
What does the work need from our team?
Caching decisions depend on knowledge only your teams hold, so expect time from several roles:
- Service owners who confirm which endpoints are idempotent, which responses vary by user and which upstream headers are reliable.
- Security and data owners who classify responses and approve the exclusion list.
- Platform engineers who provide the APISIX environment, access to etcd or the chosen deployment mode, and a way to test changes safely.
- Operations staff who will read cache metrics and respond to stale-data reports after go-live.
Can an internal team set up proxy-cache alone?
Yes, an internal platform team with APISIX experience can configure the proxy-cache plugin on its own, because the plugin is documented and its configuration is compact. The harder part is deciding what is safe to cache and proving it. That requires reading every endpoint that will be cached, understanding how upstream services set Cache-Control, and testing that personal or account-specific data is partitioned correctly. Teams new to the gateway often benefit from a review of their design before rollout. Consider whether your team has the time to build that test coverage and to maintain it after each release of your APIs.
How should we choose TTLs for cached responses?
Choose TTLs by asking how long a stale answer stays acceptable for each endpoint, not by copying a default. Read-heavy catalog data that changes rarely can tolerate longer lifetimes than account balances or inventory counts. Check whether the upstream service already sends Cache-Control or Expires headers, and decide whether the gateway should honor them or override them. The proxy-cache plugin uses a default TTL of 300 seconds for GET and HEAD responses with status 200, 301 and 404, so review each route rather than relying on that value. Document the business owner for each TTL so changes go through the same approval as other API behavior.
Does response caching fit regulated data?
Caching can fit regulated data only for responses where stale or shared copies create no unacceptable exposure. Responses containing personal health information, payment details, authentication tokens or other sensitive records usually belong on the exclusion list. Even for permitted data, you must consider where cached copies live, whether disk storage sits inside your controlled boundary, how long they persist and how they appear in audit logs. Ask your compliance and security owners to approve the list before configuration begins. DeployOpen prepares controls and evidence for compliance assessments, but independent auditors and certification bodies make the final determination.
How does a partner scope a fixed-scope proxy-cache engagement?
A partner scopes the work by listing the routes, environments, data classes and deliverables in writing before any build starts. Most engagements are fixed-scope, so the agreed document states what is caching-ready, what tests prove it, what runbooks are handed over and what is excluded. Expect the scope to name which upstream services are included, who owns the approval steps and how changes after go-live are handled. If you want ongoing tuning of TTLs or regular review of cache rules, that is typically a separate retainer. Ask for a written scope that lists assumptions, so you can see which client decisions the timeline depends on.
How DeployOpen scopes and delivers APISIX caching
DeployOpen plans, builds and hands over proxy-cache configuration as part of a self-hosted APISIX gateway in infrastructure you control. Each engagement starts from a written scope that names the routes, cache rules and data classes involved before any configuration changes.
How we scope
- Inventory which routes return cacheable GET and HEAD responses and which carry personal or regulated data
- Agree the cache backend, disk or memory, and the sizing assumptions in the written scope
- Define cache key fields, TTLs and excluded status codes per route, with upstream Cache-Control handling documented
- Confirm your APISIX version, since per-consumer cache partitioning depends on release 3.17.0 or later
How we build
- Configure proxy-cache on named routes or plugin configs, with keys and methods set explicitly rather than left at defaults
- Test cache hits, misses and bypass behavior with authenticated and anonymous requests against staging upstreams
- Verify that responses from private or consumer-specific endpoints are never stored or served to another identity
- Record each cached route, its TTL and its key design in configuration kept under version control
How we hand over
- Deliver the written configuration, test cases and results for each cached route in the agreed scope
- Document the cache policy, excluded endpoints and the steps to purge or change a rule safely
- Walk your platform and security teams through monitoring of cache behavior and upstream load
- Provide a list of open decisions, such as memory limits or shared cache sizing, for your own owners to confirm
How we support
- Engagements are fixed-scope, with deliverables and timelines agreed in writing before work starts
- Ongoing support, upgrades and continuous testing are available as a retainer after handover
- Review cache rules when new routes are added or when APISIX is upgraded to a newer release
- Quotes follow from the written scope, so ask for the cache rules and routes each quote covers

