Why request size limits in Apache APISIX decide how much memory the gateway spends
Request size limits decide how much memory a shared Apache APISIX gateway can be forced to spend, so they belong in the design before uploads, form posts or streaming endpoints go live. Teams that expose large bodies through one gateway need a per-route bound on what the gateway accepts and returns, and they need that bound to stop abuse without breaking legitimate uploads. Since APISIX 3.18.0, many plugins accept max_req_body_size and max_resp_body_size settings, with a default of 64 MiB, and the APISIX changelog says this applies to about 19 plugins. Confirm the exact list for your installed version in the plugin documentation before you rely on it for a given route, because a plugin without these fields still needs its own control.
The body limits sit alongside other traffic controls that answer different questions. The limit-req, limit-conn and limit-count plugins cap request rate, concurrency and quota, and client-control and proxy-buffering shape how the gateway handles bodies in flight. None of these replace a body size bound, because a client can stay under a request rate while sending very large payloads. Limits also do not stop slow clients from holding connections open, and they do not inspect content. Plan request limits together with rate limits, timeouts and, where content inspection matters, a separate web application firewall.
Before you set a value, inventory every route that carries a body and record the largest legitimate request and response it needs, including file uploads and any streaming API that should be exempt. Then test each value against real payloads in a non-production environment and confirm which plugin on each route enforces it. Ask your implementation partner or your own platform team to document the chosen limits per route, the owner who approves changes, and the monitoring that shows rejected requests. Those records are what turn a default into a deliberate decision.
Which request size and buffering controls fit which route
This table compares the body size, argument, buffering, rate and logger controls that bound memory and abuse at the gateway. Read each row for what it limits, where it is set and when it fits, and check the value notes before relying on a default. The main takeaway is that body limits, rate limits and buffering address different failure modes, so most routes need more than one.
| Control | What it limits and where it is set | When it fits and main trade-off |
|---|---|---|
| max_req_body_size | Maximum request body size on each plugin that supports it. Added to about 19 plugins in 3.18.0 (changelog), default 64 MiB for the response side on the matching max_resp_body_size key. | Fits routes with predictable payloads. Trade-off: oversized uploads are rejected, so large file routes need a higher or exempt value. Confirm which plugins expose the key in the plugin docs. |
| max_resp_body_size | Maximum response body size on supported plugins, default 64 MiB per the 3.18.0 changelog. | Fits routes that could return very large exports or responses. Trade-off: legitimate large responses get cut off, so test download paths before enforcing. Confirm per-plugin behavior in the docs. |
| max_post_args_readable_size | Maximum size of form body that APISIX reads for post_arg predicates, set at gateway level. Default 64 MiB from 3.18.0 (changelog). | Fits routes that match on form fields. Trade-off: bodies above the limit stop matching, so routes can silently fall through. Raise the value or set it to 0 only after reviewing that route. |
| client-control | Limits request body size and related client behavior per route, not a memory cap for every request. Confirm its exact body setting in the plugin docs. | Fits endpoints where clients are known and should be restricted. Trade-off: it is a per-route control, so routes without it stay open to large bodies. |
| proxy-buffering | Controls whether APISIX buffers upstream responses before sending them to clients. Confirm the directive and memory behavior in the plugin docs. | Fits slow clients and small responses. Trade-off: buffering large or streamed responses increases memory use and delays streaming APIs, so disable it for event streams and large downloads. |
| limit-req | Request rate, using a leaky bucket per key. Limits how often requests arrive, not how large they are. | Fits login and expensive endpoints where request floods are the threat. Trade-off: it does not cap body size, and it depends on a correct client key behind proxies. |
| limit-conn | Concurrent connections per key. Limits simultaneous open requests. | Fits protecting upstreams from many slow concurrent uploads. Trade-off: long-lived streaming and WebSocket connections count against the limit, so set values per route type. |
| limit-count | Request count within a fixed time window per key, with optional shared storage across nodes. Confirm storage options in the plugin docs. | Fits quota-style controls such as per-client daily allowances. Trade-off: window resets can allow bursts, and shared storage adds an operational dependency. |
| request-validation | Validates request bodies and headers against a schema. Confirm supported schema formats and size behavior in the plugin docs. | Fits APIs with strict payload contracts. Trade-off: schema checks run after the body is read, so pair them with a size limit to bound memory. |
| Logger backlog bounds | Maximum pending log entries in logger plugins. Bounded at 8,192 pending entries in 3.18.0 (changelog). | Fits every route that ships logs to external sinks. Trade-off: when the backlog is full, entries are dropped, so size the sink for peak traffic and monitor drops. |
How tight limits affect large uploads and streaming APIs
Body limits, buffering and streaming behave differently on each route, so a single gateway setting rarely fits every API. The four decisions below are made together: a global ceiling, per-route exceptions for uploads, unbounded responses for streams, and buffering only where an upstream needs it. Test each one with the traffic it will carry before it reaches production.
Setting a global body ceiling
Start with one conservative ceiling for every route, then open exceptions deliberately. The 3.18 plugin-level fields max_req_body_size and max_resp_body_size default to 64 MiB, so check which plugins on your routes actually apply that default. A ceiling set too low rejects legitimate payloads with errors that look like upstream failures. A ceiling set too high lets a single client tie up memory on every node. Test with your largest real request and with an oversized one, and confirm the status code clients receive.
Raising limits per route for uploads
Upload routes need their own, higher value, applied only to the path that accepts files, so the rest of the API keeps the tighter ceiling. Scope the exception by route and method, not by host. Raising the limit also affects post_arg matching: routes that match on post arguments stop matching bodies above the max_post_args_readable_size value unless it is raised or set to 0. Test a multi-megabyte upload through the gateway and confirm the upstream receives the complete file and checksum.
Leaving streaming responses unbounded
Server-sent events, long downloads and chunked exports produce responses whose total size is not known in advance. A response body ceiling would cut these streams mid-transfer and corrupt the client's view of the data. Bound the request side instead, where the payload is finite, and leave the response path open for streaming routes. Confirm that a long-lived stream stays open past your normal request timeout, and that idle connections are closed by your timeout settings rather than by a size rule.
Buffering only where the upstream needs it
Proxy buffering holds the full response or request in gateway memory before forwarding. Some upstreams need it, for example older servers that cannot handle slow clients, but most APIs do not, and buffering a large download multiplies memory use per connection. Enable it on specific routes after measuring upstream behavior with slow clients. Test with a throttled client to see whether gateway memory grows under concurrent large transfers, and confirm the behavior on your chosen deployment mode.
Logger backlogs during large payloads
Access and audit loggers queue entries while they wait for delivery. In 3.18 pending entries are bounded at 8,192, so a slow log destination can no longer grow memory without limit. Large payloads make this worse when logs capture bodies. Confirm which fields your logger records, and test what happens when the log endpoint is unreachable during a burst of large uploads. Decide whether dropped entries are acceptable for your audit obligations before rollout.
Why logger backlogs need bounds as well as body limits
A small request can still consume gateway memory. Body limits only cap what a single request carries, but log and observability plugins hold each request's log entry in a queue until it ships to its destination. If the destination slows down, becomes unreachable or cannot keep up with traffic, that queue grows with every request, even when every request is tiny. The backlog, not the body, can become the memory problem.
APISIX 3.18.0 bounds these logger backlogs at 8,192 pending entries. Once a logger's queue reaches that bound, further entries are not held in memory indefinitely. The gateway keeps serving client traffic, but the log entries beyond the bound do not reach the destination. Confirm with your gateway team exactly which entries are discarded, whether the discard is recorded anywhere in the gateway's own error log, and whether the bound applies to every logger plugin you use or only some of them. Do not assume a dropped entry leaves a trace in your log platform.
Decide before go-live what dropped log data means for your obligations. For audit trails, security investigations and payment or access records, a gap is a finding, so plan a second destination, a local fallback or an alert on logger errors and queue depth. Ask whether the destination's outage alerts fire before the queue reaches the bound, and test that by stopping the destination in a non-production environment while you send representative traffic. Record the result so the next upgrade can be checked against it.
Setting body limits on a route in four checks
This sequence turns the gateway's body size settings into a tested configuration: each route is mapped, limits are set and confirmed per plugin, and the results are checked against oversized and in-limit traffic before the route carries production load.
Inventory routes that carry bodies
List every route that accepts request or response bodies, and mark which ones carry file uploads, form posts, large JSON payloads, streaming responses or WebSocket and gRPC traffic. Include the routes that match on post_arg predicates, because those depend on a separate argument limit. The owning application team should confirm the largest legitimate payload each route must accept. This inventory is done when every route has an owner, a payload type and a documented expected maximum size, and streaming routes are flagged for separate treatment.
Set body size fields on the plugins
For each route that needs a different ceiling than the default, set max_req_body_size and max_resp_body_size on the plugins that support them. The APISIX 3.18.0 changelog reports these fields were added to about 19 plugins with a default of 64 MiB, so check the plugin reference for your exact version before relying on a plugin. Where a plugin does not expose the fields, document the gap and the alternative control. The check for this step is that the gateway accepts the configuration through the Admin API or your configuration file, and the effective values appear in the route definition when you read it back.
Set the post argument limit where needed
If any route matches on post_arg predicates, set max_post_args_readable_size to the largest body you expect those routes to inspect, or to 0 if your design requires unlimited readable size and you accept the memory trade-off. The APISIX 3.18.0 changelog states that routes using these predicates stop matching bodies above 64 MiB unless the value is raised or set to 0, so a route that worked before the upgrade can silently stop matching. The check is a test request with a body just under the limit that still matches the route, and one just over it that no longer does.
Confirm logger backlog behavior
Review every logging plugin on the routes in scope and confirm how its buffer behaves when the destination slows or fails. The APISIX 3.18.0 changelog reports that logger backlogs are bounded at 8,192 pending entries, so the team should confirm that this bound fits its audit requirements and that dropped entries are visible in gateway logs or metrics. The check is a deliberate pause of the log destination in a test environment, followed by confirmation that the gateway keeps serving traffic and that the backlog stays bounded.
Test with oversized and in-limit requests
Send a set of requests to each route: bodies just under the configured limit, bodies just over it, and a streaming upload that exceeds the limit. Record the status code, the response body and the time to response for each case. Expected results should be written down before the test, so a 413 or a closed connection is judged against the design, not against whatever the gateway returned. The test is complete when every in-limit request reaches the upstream, every oversized request is rejected as designed, and streaming routes behave as their owners agreed.
Check error responses and memory under load
Confirm that rejected requests return consistent error responses that do not leak upstream details, and that clients can tell a size rejection from an authentication or rate-limit rejection. Then run a sustained load test that mixes in-limit and oversized traffic while watching gateway memory and worker behavior. Compare memory with a baseline run that carries only in-limit traffic. The check passes when memory stays within the range your capacity plan allows and the gateway recovers after the load stops. Ask your load testing team to set the thresholds before the run.
Record the settings and retest on change
Store the final limit values, the plugin list, the expected results and the test outputs in the same repository as the route configuration. Repeat the oversized and in-limit tests after every APISIX upgrade, plugin change or change to a route's payload design, because defaults and plugin support can change between versions. The record is complete when a reviewer can trace each route to its limits, its tests and its owner.
Size settings by traffic type: uploads, streams, form posts and APIs
Uploads are the traffic most likely to need a body limit that differs from the rest of the gateway, so set the limit per route instead of as a shared default. From 3.18.0, plugins that accept request bodies expose max_req_body_size, with a default of 64 MiB. Start from the largest file the upload route must accept, apply that value to the upload route only, and keep other routes at tighter limits.
- Per-route `max_req_body_size`: Set the value in the upload route's plugin configuration so JSON and login endpoints keep their own limits.
- Response bounds: Upload endpoints usually return short confirmations, but check
max_resp_body_sizeif the same route returns generated files. - Buffering and workers: Large bodies held in memory or on disk occupy workers for longer, so review
proxy-bufferingon the route and confirm how the upstream handles slow clients. - Concurrency: Pair the size limit with
limit-connso a small number of clients cannot open many large uploads at once. - Layer alignment: Confirm the application server, any load balancer and any WAF accept the same maximum size, or the rejection will come from the wrong layer.
Test a file at the configured limit to confirm it succeeds, a file just above the limit to confirm the expected rejection status, and check that the upstream receives the complete file.
Streaming responses, server-sent events, WebSocket connections and long polling do not fit a fixed body size model. A response limit can cut a stream off partway through, so confirm whether the route streams or buffers before you set any response bound. Keep these routes in their own definitions so changes for streams do not affect ordinary requests.
- Response limit scope: Confirm in your APISIX version whether
max_resp_body_sizeapplies to streamed responses or only to buffered ones before relying on it for event routes. - Proxy buffering:
proxy-bufferingcontrols whether the gateway holds bytes before sending them to the client. Disabling it for streams avoids delayed events but gives less memory control, so document that trade-off. - Connection limits:
limit-connandlimit-counttrack connections or requests in different ways. Long-lived streams hold connections open, so size these limits for concurrent streams, not only request rate. - Logger queues: Confirm how the logging plugins handle entries for long-running requests, and that queues stay bounded at the 8,192 pending entries that 3.18.0 introduced for logger backlogs.
- Dedicated route set: Give streams their own route and plugin set, and check the plugin list for the traffic plugins available in your version.
Test by holding a stream open longer than your slowest expected event, confirm it is not truncated, and confirm the connection count returns to its baseline after clients disconnect.
Routes that match on post_arg predicates read the request body to decide where traffic goes. In 3.18.0, max_post_args_readable_size means those routes stop matching bodies above 64 MiB unless the value is raised or set to 0. The failure can look like a missing route rather than an error, so it is easy to miss in testing.
- Find every predicate: List each route that uses a
post_argpredicate and record the largest form body it must match before choosing a value. - Raise or disable deliberately: Raise
max_post_args_readable_sizefor the specific form route. Set it to 0 only after confirming that the memory cost is acceptable for that route. - Fallback behavior: Confirm what the client receives when a predicate cannot match, because a fallback route may send the request to the wrong backend.
- Body limit alignment: Check that
max_req_body_sizeon the same route is not lower than the largest form you expect. - Content types: Test multipart and URL-encoded submissions separately, since each can produce different parsed arguments.
Submit a form just under the readable size and one just over it, then confirm that each reaches the intended upstream or falls through as your route design specifies.
JSON APIs usually carry small bodies, so the main goal is a tight, explicit limit that protects workers and logs from oversized payloads. Start from the largest legitimate payload each endpoint accepts, and make the limit visible in configuration review. Leaving the 64 MiB default in place on API routes is a common way to make oversized requests cheap to send.
- Tight request limit: Set
max_req_body_sizeon API routes to the largest documented payload, and confirm that no route still inherits the default by accident. - Schema validation: The
request-validationplugin can reject malformed bodies before they reach the upstream. Confirm the body schema features your version supports. - Request rate:
limit-reqandlimit-countaddress many medium-sized requests, which a size limit alone will not stop. - Response bounds: Review
max_resp_body_sizefor endpoints that return large lists, and confirm the application paginates when responses can grow. - Log content: Large request bodies increase log volume and cost. Confirm that logging records the fields your audit needs rather than full payloads.
Send a payload at the documented maximum, one just above it, and a malformed JSON document, then confirm that each returns the status your API contract specifies.
Abuse scenarios that body limits and rate controls address
Request size limits only protect the gateway when they are paired with controls on concurrency, request rate and client identity. The cards below map common abuse patterns to the APISIX controls that reduce them, the limits the gateway cannot enforce alone, and the signals operations teams should watch.
Oversized request bodies
Large bodies consume buffer memory and upstream capacity before any application check runs. From APISIX 3.18.0, plugins that accept bodies expose max_req_body_size, with a default of 64 MiB across about 19 plugins, so confirm which plugins on your routes carry the field and set values per route. Check that the limit matches your largest legitimate payload, and that rejected requests are logged. The gateway cannot tell a hostile large upload from a valid one, so the limit is a ceiling, not a content check.
Slow and concurrent uploads
A small number of clients can hold many connections open while sending bodies slowly, tying up workers even when each request is under the size limit. Use limit-conn to cap simultaneous connections per key, and consider client-control to bound how long the gateway waits for client data. Size-based limits do not restrict duration, so test with slow-send tooling against a staging route. Watch active connection counts and rejected connection rates per consumer or IP.
Post argument floods
Form bodies with very many fields can be expensive to parse, and routes that match on post_arg predicates read the body to decide routing. Since 3.18.0, max_post_args_readable_size stops those routes from matching bodies above 64 MiB unless you raise the value or set it to 0. Decide whether your routes rely on body matching before changing this value, because a higher setting increases parsing cost. Confirm the behavior in a test environment before rollout.
Request volume and rate abuse
High request rates from one source can exhaust upstream capacity even when every request is small. Apply limit-req for smoothed request rates, or limit-count for fixed windows with quota semantics, keyed on a consumer or client address. These keys are only as accurate as the client IP the gateway sees. If X-Forwarded headers are not sanitized and trusted proxies are not configured, a spoofed header can move traffic into a different bucket, so verify header trust before relying on per-IP limits.
Log amplification from request floods
Access and plugin loggers can grow faster than their sinks under sustained traffic or large bodies logged in full. Since 3.18.0, logger backlogs are bounded at 8,192 pending entries, which caps in-memory queue growth but means entries beyond that limit are dropped. Decide which fields your loggers record, avoid logging full bodies on high-volume routes, and monitor dropped-log indicators and sink ingestion lag so that loss is visible rather than silent.
What teams ask before setting request size limits in Apache APISIX
Can our own team set request size limits in Apache APISIX without a partner?
Yes, a team that already runs APISIX can set body size limits, but the work is mostly inventory and testing rather than configuration. Each route needs a documented expected payload size, which only your API owners can confirm. The plugin-level settings are simple to change, yet a wrong value can break uploads silently, so the change needs staged rollout and regression tests on real traffic. Teams new to APISIX usually benefit from a partner review of the route inventory and plugin mix before changing production values.
What drives the effort of a request size limits project?
Effort rises with four main factors: the number of routes, the variety of upload types (JSON, multipart forms, file streams, large exports), the plugin mix that accepts request bodies, and the logging destinations that buffer entries. Version upgrades add work when the gateway is older than the release that introduced these controls, because behavior and defaults differ across versions. Streaming and long-lived APIs need separate treatment, since a fixed body cap can cut them off. Ask for the route count and upload profile before estimating anything.
How long does testing usually take for size limits on a gateway?
Testing time depends on how many routes carry bodies, how varied their traffic is, and whether you have representative traffic samples. A small set of routes with known payloads is quick to verify, while a gateway with many upload paths needs test cases for each class of request, including oversized requests that should be rejected. No duration is fixed in advance, so ask any provider for a test plan that lists routes, payload classes and the environments used. Plan for at least one monitor-only period before enforcing new limits on production traffic.
What do we need to provide before a size limits engagement starts?
A useful engagement starts with inputs from your side. Prepare a route inventory that lists each route, its methods, its upstream service and the largest legitimate body it receives. Provide traffic samples or access to access logs that show real payload sizes, the upstream limits already set on your services and proxies, and the destinations for gateway logs. Named owners for each API who can confirm expected sizes will shorten review. Missing inputs usually become the main cause of schedule slips.
Which upstream and infrastructure limits must match the gateway settings?
Gateway body limits only help if the layers around them agree. Check the maximum body size at any load balancer, ingress or proxy in front of APISIX, the upstream application server limits, and any file storage or database constraints behind the API. If the gateway accepts a larger body than an upstream service allows, clients receive confusing errors late in the request. Document each limit in one place so changes to one layer prompt review of the others.
What should a quote for request size limits include?
A written quote should follow from a written scope and list the route groups in scope, the APISIX version and deployment mode, the plugins whose body limits will be configured, and the logging destinations to review. It should state which deliverables you receive, such as a limits register, configuration as code, test results and a rollback procedure. It should also separate one-time work from recurring support, and name any assumptions about your environment. Ask whether testing runs in your staging environment and who approves production changes.
Does a body size limit affect file uploads and streaming APIs?
Yes. A fixed body cap rejects legitimate uploads that exceed it, so upload routes need their own documented limits, or a deliberate exception, based on the largest file your business accepts. Streaming and long-running APIs may need limits applied differently, because the body is not a single fixed object. Confirm the behavior of each plugin on these routes in your version before relying on it, and test with real file sizes instead of assumed ones.
Limits to confirm in your environment before you rely on these controls
Size limits only protect you if they fire before memory is exhausted and before a legitimate request breaks. The cards below list what to confirm in your own APISIX version, plugin set and network path, and where each answer should come from, whether the changelog, plugin documentation, the vendor or a test in your environment.
Which plugins honor each size field
The 3.18.0 release added max_req_body_size and max_resp_body_size to about 19 plugins, not to every plugin. Build an inventory of the plugins on your routes and check each one against the changelog and its plugin page for the version you run. A plugin that does not honor the field leaves that route without the bound you assumed, so the gap should be found in staging, not in an incident.
Default 64 MiB post argument limit
Since 3.18.0, max_post_args_readable_size stops post_arg predicate routes from matching bodies above 64 MiB. Confirm whether any route depends on matching large form bodies, then decide whether to raise the value or set it to 0. Setting 0 removes the bound entirely, so ask the team to document why that is acceptable and to test memory use under large posts before choosing it.
Upstream and load balancer body limits
The gateway is rarely the first component that reads a request. Cloud load balancers, ingress layers, web application firewalls and the application server each enforce their own body size limits, and the smallest one rejects first. Trace each hop in your environment, record its limit and error response, and send test bodies at the edge of each value. Your error handling should match the rejection the client actually receives.
Chunked and streamed request bodies
Size fields do not behave the same way for requests sent with chunked transfer encoding, where the total length is unknown when headers arrive. Confirm with a test how each plugin on your route counts and stops a chunked body, and whether a stream that exceeds the limit is cut off before it reaches the upstream. Streaming APIs such as file upload or event feeds need separate test cases, since a limit that suits a JSON call can break them.
Logger backlog bound against your log volume
Logger plugins now hold at most 8,192 pending entries, according to the 3.18.0 release. When the backlog is full, entries are dropped rather than buffered without limit, so audit or security events can go missing under load. Measure your peak request rate, multiply by the time a log sink may be unavailable, and compare the result with the bound. If the two do not fit, the answer is a different log design, not a larger assumed buffer.
Test in your own environment
Vendor and documentation statements describe defaults and intended behavior, not your deployed result. Run a repeatable test set against your exact APISIX version, plugin configuration and network path. Include oversize bodies, chunked bodies, large form posts, slow clients and a stalled log sink, and record the status code, memory use and log output for each. Keep the results with the change record so the next upgrade can be checked against them.
How DeployOpen scopes and delivers request size controls on APISIX
DeployOpen treats request size limits and buffering as a written design decision for each route, not a default left to chance. We scope the limits, build and test them against your real traffic patterns, and hand over the configuration with the reasoning behind every value.
How we scope
- Inventory every route, upload path, streaming API and logger that receives request or response bodies from clients.
- Record which plugins in your gateway version support max_req_body_size and which routes still need an explicit value.
- Agree in writing which large uploads, streaming endpoints and post_arg matching routes are in scope and which are excluded.
- Engagements are fixed-scope, so the scope, deliverables and timeline are confirmed before any configuration changes begin.
How we build
- Set body size limits per route and per plugin, with documented values tied to each API's expected payloads.
- Review max_post_args_readable_size against every route that matches on post_arg predicates before changing behavior.
- Configure logger backlog handling and client-control settings so that a slow log sink cannot exhaust gateway memory.
- Test rejected, boundary-size and oversized requests, plus large uploads and streaming calls, in a non-production environment first.
How we hand over
- Deliver the route configuration as code, with each size limit, buffering setting and its rationale recorded in the repository.
- Document which upstream services depend on limits, and the response a client receives when a limit is reached.
- Provide test scripts and expected results so your team can rerun the verification after each APISIX upgrade.
- Walk your platform and security engineers through the runbook for raising a limit through a reviewed change.
How we support
- Review size limit settings when you upgrade APISIX, since plugin defaults and option names can change between releases.
- Re-run boundary tests after new routes, new upload features or changes to logger destinations are added.
- Ongoing support, upgrades and continuous testing are available as a retainer if your team wants DeployOpen to keep these controls under review.
- Quotes follow from the written scope, so ask for the limits, test cases and handover items to be listed explicitly.

