API Gateway AWS Best Practices for Production
Amazon API Gateway is easy to get running in an afternoon and easy to misconfigure in ways that only surface under real traffic — unbounded throttling, missing request validation, authorizers that add 200ms to every call, or a stage with no rollback plan. This article covers the configuration choices that actually matter once you move from a demo to production.
The short version: set explicit throttling limits per usage plan, validate requests at the gateway instead of in your Lambda, cache aggressively for read-heavy endpoints, pick the right authorizer for your latency budget, and instrument everything with CloudWatch and X-Ray before you need it, not after an incident.
Throttling and usage plans
API Gateway applies account-level and stage-level throttling by default, but relying on defaults means one noisy client can degrade the API for everyone else.
- Create usage plans with per-API-key rate and burst limits rather than one global limit.
- Set stage-level throttling below your backend's actual capacity, not at the API Gateway maximum — the gateway will happily forward more requests than your Lambda concurrency or database connection pool can absorb.
- Use API keys only for metering and coarse rate limiting, never as an authentication mechanism. They're not secrets in any meaningful sense.
aws apigateway create-usage-plan \
--name "partner-tier-1" \
--throttle burstLimit=50,rateLimit=20 \
--quota limit=100000,period=MONTH
Authorization: pick based on latency, not defaults
You have four realistic options, and they have very different cost/latency profiles:
- IAM authorization — good for internal service-to-service calls already inside AWS. No extra latency, but painful for external clients.
- Cognito authorizers — built-in JWT validation, no Lambda cold start, reasonable default for consumer-facing APIs.
- Lambda authorizers (custom) — maximum flexibility (API keys, HMAC, custom claims) but adds a cold-start-prone extra hop. Always enable authorizer result caching (
authorizerResultTtlInSeconds), otherwise every request pays the full authorizer latency. - Resource policies — for IP allowlisting or VPC-only access, applied at the gateway level with no compute cost.
If you're building an authorization layer specifically to front a model API — say, giving each customer their own scoped key for calling Claude — building and operating a custom Lambda authorizer, key rotation, and usage dashboards from scratch is a lot of infrastructure for something that isn't your core product. SubToAPI issues per-application sub_live_... keys with usage metadata and team seats already wired up, so you can skip that layer entirely if the gateway you're building is really just an AI API proxy. See the quickstart for how the keys map to requests.
Request validation before it hits your backend
API Gateway can validate request bodies against a JSON Schema and reject malformed payloads with a 400 before invoking any compute:
{
"requestValidator": "Validate body",
"validateRequestBody": true,
"validateRequestParameters": true
}
This is cheap, fast, and eliminates an entire class of Lambda invocations you're currently paying for just to return a 400. Combine it with models defined per method so the schema lives with the API definition, not scattered across handler code.
Caching for read-heavy endpoints
REST API caching (not available on HTTP APIs) can cut backend load significantly for endpoints that don't change per-request:
- Enable caching per stage, then override TTL per method for anything that needs finer control.
- Cache keys should include only the parameters that actually vary the response — including everything by default inflates your cache size and hit-miss ratio for no benefit.
- Remember cache costs are billed hourly regardless of hit rate, so this only pays off above a certain request volume. Below that, invest in backend-level caching instead.
Deployment safety: stages, canaries, and rollback
Treat API Gateway deployments with the same discipline as any other production release:
- Use stage variables to parameterize Lambda aliases or backend URLs per stage instead of hardcoding environment-specific values into the API definition.
- Enable canary releases on production stages so a percentage of traffic hits the new deployment before a full cutover. Watch the canary's CloudWatch metrics for elevated 5xx or latency before promoting.
- Keep deployment history — API Gateway retains prior deployments, so rollback is a matter of pointing the stage back at the last known-good deployment ID, not redeploying from scratch.
Timeouts and payload limits you can't configure around
Two hard limits catch teams by surprise in production:
- 29-second maximum integration timeout. There is no way to raise this. If your backend can genuinely take longer, you need async patterns (return a 202 and poll, or use WebSockets/Server-Sent Events) rather than a synchronous request.
- 10 MB payload limit on both request and response. Large file uploads should go through S3 presigned URLs, not through the gateway.
If you're proxying to an LLM API specifically, both of these matter more than usual — long completions and streaming responses don't fit cleanly into the 29-second synchronous model, which is one reason a lot of teams end up building or buying a purpose-built proxy rather than wiring API Gateway directly to a model provider. If that's your situation, streaming support and tool-use forwarding are handled for you rather than requiring a custom Lambda-and-WebSocket setup.
Observability: turn it on before you need it
- Enable execution logging and access logging separately — access logs (custom format, includes latency and response size) are what you'll actually query during an incident.
- Turn on X-Ray tracing per stage to see the full request path including downstream Lambda and database calls, not just the gateway hop.
- Set CloudWatch alarms on
4XXError,5XXError,Latency, andIntegrationLatencyseparately — a spike in integration latency with flat gateway latency points at your backend, not the gateway.
Network exposure
- Use private APIs with VPC endpoints for anything that shouldn't be internet-reachable — internal admin APIs, service-to-service calls within a VPC.
- Attach AWS WAF to public-facing REST APIs for rate-based rules and managed rule groups (SQLi, XSS) at the edge, before requests consume Lambda invocations.
- Use a custom domain name with an ACM certificate and Route 53 alias rather than the default
execute-apiURL — this also lets you swap the underlying API without changing client configuration.
Questions
Should I use HTTP APIs or REST APIs on AWS? HTTP APIs are cheaper and lower-latency but lack request validation, caching, and some authorizer options. Use REST APIs when you need those features; use HTTP APIs for simple proxy integrations where cost matters more.
How do I handle authentication for a public AWS API Gateway? Cognito authorizers cover most standard JWT-based auth with no added compute cost. Reach for a custom Lambda authorizer only when you need logic Cognito can't express, and always enable authorizer caching.
Is API Gateway a good fit for proxying LLM API calls? It can work, but the 29-second timeout and 10MB payload limit conflict with streaming completions, and you'll need to build key management and usage tracking yourself. Tools like SubToAPI handle that layer directly — see pricing if you want to compare the build-vs-buy cost.