Most APIs eventually have to handle large collections, expensive operations, or many small requests, and a handful of patterns cover these needs. Pagination splits a large result set into pages using query parameters—either offset-limit style with ?page=2&limit=20 or cursor-based style with an opaque token that points to the next slice. Offset pagination is intuitive and supports random access, but it grows inefficient as offsets get larger because the database still skips earlier rows; cursor pagination is faster at scale and stable in the face of new data arriving mid-scroll, but it only supports forward navigation. The right choice depends on the dataset size and access pattern, and many APIs offer both.
Beyond pagination, clients frequently need to slice collections differently: filtering parameters such as ?status=active narrow the set, sorting parameters such as ?sort=-created_at order it, and field selection such as ?fields=name,email trims each response down to the data the client asked for. Bulk and batch operations reduce round-trips when a client needs to act on many resources; a typical pattern is POST /users/batch accepting an array of operations and returning per-item results and errors so a single failure does not abort the whole call. Long-running work that cannot finish within a request is handled asynchronously: the API returns 202 Accepted with a Location header pointing at a status URI such as /tasks/123, which the client polls via GET until it reaches a terminal state of success or failure.
Caching is the other major performance lever. ETags act as resource version identifiers, and conditional requests with headers like If-None-Match or If-Modified-Since let clients avoid re-downloading unchanged representations. Cache-Control directives such as max-age and no-cache let servers control how long intermediaries and browsers may cache responses, which can dramatically reduce load for read-heavy APIs. Request bundling—a specific form of batching—combines multiple related calls into a single POST /batch to reduce chatty interactions on slow networks, trading a small amount of complexity for large latency gains on mobile clients.