The Problem: APIs Built for the Browser
Most backend engineers build APIs with web clients in mind. That makes sense. The web was there first. But mobile is not a smaller browser. It is a fundamentally different environment with its own constraints.
A phone on a cellular network deals with high latency, limited bandwidth, and a battery that drains with every network call. Users switch between WiFi and LTE mid-request. They walk into elevators. They close the app and reopen it thirty seconds later expecting the same state.
When your API ignores these realities, mobile engineers end up writing layers of workaround code on the client. That means more bugs, slower releases, and frustrated teams on both sides. Here is what we have learned building APIs that mobile engineers actually want to consume.
Payload Size Matters More Than You Think
On a web app running over fiber, an extra 50KB in a JSON response is invisible. On a phone over 3G in a parking garage, it is the difference between a snappy experience and a loading spinner.
Every byte costs battery. The radio on a phone powers up for each network request and stays active for a cooldown period after. Larger payloads keep the radio on longer. Multiply that across dozens of API calls and you are measurably draining the user's battery.
- Return only the fields the client needs. Avoid dumping entire database rows into responses.
- Use a
fieldsquery parameter so mobile clients can request sparse fieldsets. - Compress responses with gzip or Brotli. This is table stakes, but many APIs still skip it.
- Avoid deeply nested JSON. Flat structures are cheaper to parse on low-end devices.
Pagination Done Right: Cursor-Based, Not Offset
Offset-based pagination breaks on mobile. A user scrolls through a feed, the dataset shifts underneath them, and suddenly they see duplicate items or miss entries entirely. This is not a theoretical problem. It happens constantly in production.
Cursor-based pagination solves this. Instead of saying "give me page 5," the client says "give me the next 20 items after this cursor." The cursor is an opaque token that points to a stable position in the dataset.
- Cursors survive inserts and deletes in the underlying data.
- They work naturally with infinite scroll, which is the dominant mobile UI pattern.
- Include a
has_moreboolean in the response so clients know when to stop fetching.
A good pagination response includes three things: the data array, a next cursor, and a has_more flag. Nothing else is needed.
Error Responses Mobile Clients Can Actually Parse
Returning a raw 500 with an HTML error page is not helpful to a mobile client trying to show a toast message. Mobile apps need structured, predictable error responses they can parse programmatically and present to the user in context.
Every error response should follow the same shape. We use a simple structure across all our projects:
- A machine-readable
error_codestring likeINVALID_TOKENorRATE_LIMITED. - A human-readable
messagestring the app can display directly if needed. - An optional
fieldkey for validation errors, so the client knows which input to highlight. - A consistent HTTP status code. Do not return 200 for errors. Ever.
Mobile engineers should never have to regex-match an error message to figure out what went wrong.
Versioning That Does Not Break Old App Versions
Web apps deploy instantly. You push a change and every user gets it. Mobile apps do not work that way. Users on version 2.1 of your app might not update for months. Some never will. Your API has to support them all.
We version APIs in the URL path: /v1/users, /v2/users. It is explicit and impossible to miss. Header-based versioning sounds elegant but causes debugging nightmares when someone forgets to set the right header.
- Never remove fields from an existing API version. Only add.
- Deprecate old versions with a sunset header and a long timeline. Six months minimum.
- Build a forced-update mechanism into the app from day one. You will need it eventually.
Caching Headers and ETags for Mobile
Mobile networks are unreliable. Good caching turns your API from unusable to resilient. Every response should include proper Cache-Control headers and ETags.
With ETags, a mobile client can make a conditional request. If the data has not changed, the server returns a 304 Not Modified with no body. That saves bandwidth, battery, and time. For data that changes infrequently, like user profiles or app configuration, this is a massive win.
- Set
Cache-Control: max-agefor static or slow-changing resources. - Use
ETagandIf-None-Matchfor dynamic data that the client polls. - Return
Last-Modifiedheaders so clients can do conditional GETs.
GraphQL vs REST for Mobile: A Practical Take
GraphQL lets mobile clients request exactly the data they need. No over-fetching. No under-fetching. In theory, it is perfect for mobile. In practice, it depends.
GraphQL shines when your mobile app has many screens with different data requirements hitting the same underlying models. Instead of building dozens of bespoke REST endpoints, you expose a graph and let the client query what it needs.
REST wins when your API surface is small and well-defined. It is simpler to cache at the HTTP layer. It is easier to monitor and rate-limit. The tooling is more mature.
Pick the tool that matches your team and your problem. Do not pick GraphQL because it is trendy. Do not avoid it because it is unfamiliar.
In our projects, we often use REST for straightforward CRUD operations and introduce GraphQL selectively for screens that aggregate data from multiple sources. Pragmatism beats purity.
Build APIs With Mobile in Mind From Day One
Retrofitting mobile-friendliness into an existing API is painful and expensive. The best time to think about payload size, pagination, caching, and versioning is before you write the first endpoint.
If you are building a product that will have a mobile client, involve a mobile engineer in your API design review. They will catch problems that backend engineers simply do not think about.
We design APIs this way at DEVSFLOW because we build both sides. Our backend and mobile teams sit in the same room and review the same contracts. That is the difference between an API that works and one that works well on a phone in a subway tunnel.
Tell us about your project and we will walk you through how we would design the API layer for your mobile app.