Rate limiting protects API capacity, preserves fairness, and reduces the usefulness of automated abuse. DDoS protection addresses a wider availability problem that may include network floods, protocol exhaustion, expensive application requests, and dependency overload. The controls overlap, but a single requests-per-second counter cannot solve every failure mode.

Useful limits begin with the resource being protected. A cached read and a password verification request may each count as one HTTP call while consuming very different CPU, database, cryptographic, and third-party capacity. Design budgets around operation cost, identity, tenant, and shared infrastructure, then layer network, gateway, application, queue, and dependency controls.

Define the protection goal

Rate limits can serve several goals: prevent one client from crowding out others, bound financial cost, slow credential attacks, protect a fragile dependency, enforce a contractual plan, or keep background work within processing capacity. State the goal because it determines the key, time window, response, and monitoring. A billing quota is not the same as an emergency overload limit.

Separate steady-state policy from incident controls. Normal budgets should be predictable enough for clients to design against. Emergency protections may become more restrictive when saturation, attack signals, or dependency failures occur. Make the transition observable and reversible. An undocumented manual block that lasts indefinitely is operational debt, not a resilient control.

Choose dimensions beyond source IP

IP addresses can be useful at an unauthenticated edge, but many legitimate users share addresses and attackers can distribute traffic. Authenticated limits should consider client ID, API key, user, tenant, workload, route, and operation. High-risk actions may need a per-account or per-resource limit even when overall request volume is low. Combine dimensions so one tenant cannot exhaust shared capacity while one compromised user cannot consume the tenant’s full allocation.

Be careful with identifiers supplied by untrusted proxies. Define which network components may set forwarding headers and strip conflicting values at the edge. Normalize client identities before using them as limit keys. If a key is missing or invalid, place traffic into a bounded anonymous pool rather than an unlimited fallback.

Model request cost and concurrency

Weighted limits assign more budget to expensive operations. A simple lookup might cost one unit, a full-text export fifty, and a cryptographic signing operation ten. The weights do not need to predict CPU perfectly; they need to reflect meaningful differences and be reviewed against telemetry. Apply separate limits to endpoints that trigger third-party charges or long-running work.

Concurrency limits complement rate limits. A client sending ten large requests that each run for a minute can consume more capacity than a client sending a hundred fast requests. Bound in-flight work, queue depth, response size, query complexity, and execution time. GraphQL and batch APIs often need complexity or item-count limits in addition to request frequency.

Select an algorithm that matches the behavior

Fixed windows are simple but allow bursts at boundaries. Sliding windows smooth the calculation but may require more state. Token buckets permit controlled bursts while enforcing an average rate. Leaky buckets shape traffic into a steadier flow. Distributed systems also need to decide how strictly counters are synchronized. Perfect global precision can become a latency and availability bottleneck.

Use local limits for immediate protection and a broader shared budget for fairness across replicas. Accept a small, understood amount of counter drift rather than making every request depend on a single remote counter. For high-value quotas, reconcile usage asynchronously and define how overage is handled. The limit store itself needs capacity isolation, bounded timeouts, and secure failure behavior.

Return responses clients can handle safely

When a request is rejected because the client exceeded a limit, return a clear status and stable error code. RFC 6585 defines HTTP status 429, Too Many Requests, and notes that a response may include information about retry timing. Use a Retry-After value when the server can make a meaningful statement, and avoid revealing sensitive details about other tenants or internal capacity.

Clients should use exponential backoff with jitter and respect server guidance. Immediate synchronized retries can turn a small overload into a sustained incident. For asynchronous work, consider accepting a bounded job and returning a status resource rather than holding an expensive connection. Idempotency keys help clients retry state-changing operations without creating duplicates, but they need their own storage and abuse limits.

Layer DDoS and application protections

Network and edge providers can absorb volumetric traffic before it reaches the application. Web application firewalls and gateways can block malformed requests, known attack patterns, and obvious bots. Application limits understand authenticated identities, resource ownership, query cost, and business workflows. Downstream services need bulkheads so one saturated dependency does not consume every worker.

Do not assume a provider automatically protects every origin. Restrict direct origin access so traffic cannot bypass the edge. Protect alternate domains, IPv6 paths, administrative ports, and health endpoints. Validate that autoscaling does not simply convert an attack into an unbounded bill or overload a non-scaling database.

Design graceful degradation and lockdown modes

When capacity is constrained, preserve the most important functions. Disable expensive optional features, reduce response sizes, serve safe cached data, delay background work, or prioritize authenticated critical clients. Define which operations may be shed and which must remain available. A lockdown mode can temporarily narrow access to essential routes or stronger identities, but it should be predesigned, tested, and auditable.

Degradation should not weaken authorization or input validation. Under pressure, teams are tempted to bypass policy calls or increase timeouts indefinitely. Instead, use bounded caches and explicit fallbacks for low-risk operations while failing closed for sensitive changes. Record when degraded behavior is active and who enabled it.

Measure saturation, fairness, and false positives

Monitor request rates, weighted cost, concurrent work, queue depth, rejection reasons, latency, error rates, dependency health, and resource utilization. Break metrics down by tenant, client, route, and region where cardinality controls allow. A global dashboard can look healthy while one tenant is entirely blocked or one expensive route is exhausting a database pool.

Review false positives and evasion. Legitimate clients may use bursty batch workflows; attackers may stay just under a simple threshold or distribute activity across identities. Connect rate-limit events to authentication failures, unusual resource access, and transaction outcomes. Keep configuration changes versioned and record which policy produced each rejection.

Test overload behavior before production

Load tests should include realistic request mixes, slow dependencies, large payloads, retrying clients, and uneven tenants. Verify that limits trigger at the intended layer, errors remain stable, and healthy tenants retain service. Test failure of the counter store and edge provider integration. A limit that fails open during a store outage may remove protection exactly when the system is least stable.

Run game-day scenarios for credential attacks, export floods, queue buildup, and direct-origin traffic. Confirm that operators can tighten and restore controls without a code release. Document contacts and decision authority for upstream providers. Preserve forensic data while limiting log volume so an attack does not exhaust the evidence system.

Resilience checklist

  • State whether each limit protects fairness, cost, abuse, or a dependency.
  • Key limits by authenticated identity and tenant where possible, not only IP.
  • Weight expensive operations and bound concurrency, payload size, and queue depth.
  • Return stable 429 responses and encourage backoff with jitter.
  • Restrict origin access so edge controls cannot be bypassed.
  • Predefine graceful degradation and lockdown modes without weakening authorization.
  • Test counter-store failure, retries, uneven tenants, and direct-path attacks.

Protect capacity as a security boundary

Rate limiting works when it represents real consumption and real identities. DDoS resilience works when controls exist at multiple layers and the application can shed work without losing its security model. Start with the expensive and business-critical operations, define fair budgets, and test how the whole dependency chain behaves under pressure.

The API Protection guide combines these controls with gateway policy and incident response. Pair it with the authentication guide for trustworthy client keys and the zero-trust guide for service identity and containment.