Solving Mobile Latency: Why Facebook Moved from REST to GraphQL
Discover how Facebook solved mobile data inefficiencies by replacing REST with GraphQL to eliminate over-fetching and reduce network round-trips.
07 Oct 2025, 12:30 UTC

The Payload Problem: When REST Becomes a Bottleneck
Mobile applications face a constant battle with network latency and limited bandwidth. In the early days of the Facebook mobile app, the engineering team relied on REST (Representational State Transfer) APIs. While REST is straightforward, it creates a rigid contract: the server defines the response, not the client.
This led to two primary inefficiencies: over-fetching and under-fetching. Over-fetching occurs when a client requests a resource (like a user profile) but receives 50 fields when it only needs the username and profile picture. Under-fetching happens when a single endpoint doesn't provide enough data, forcing the app to make multiple sequential network requests to populate a single screen. On slow 3G or 4G connections, these extra round-trips and bloated payloads directly translated to slower render times and a poor user experience.
The Thesis: Client-Driven Data Fetching
The solution was to shift the power of data definition from the server to the client. By implementing GraphQL, Facebook moved away from multiple resource-specific endpoints to a single endpoint that accepts a query describing exactly what data is required. This approach eliminates unnecessary data transfer and collapses multiple API calls into a single request, significantly reducing the time to first meaningful paint on mobile devices.
Architecture: The GraphQL Layer
GraphQL acts as an orchestration layer between the client and the backend data stores. Instead of hitting a database directly, the client sends a query to the GraphQL server, which then resolves the request through a set of resolvers—functions that fetch the data from the appropriate microservice or database.
- Single Endpoint: All requests go to one URL (typically
/graphql), simplifying network configuration. - Strong Typing: A schema defines exactly what types of data exist and how they relate, allowing for automatic validation of queries before they hit the backend.
- Batching: To prevent the "N+1 problem" (where the server makes one query for a list and then N queries for the details of each item), the layer uses batching to group data requests together.
Worked Example: Fetching a User Feed
Consider a scenario where a mobile app needs to display a feed of posts, including the author's name and the number of likes for each post.
The REST Approach (Multiple Round-trips)
The client might have to perform these calls sequentially:
GET /feed→ Returns a list of post IDs and author IDs.GET /user/{id}→ Called for every unique author in the feed to get names.GET /post/{id}/likes→ Called for every post to get the like count.
The GraphQL Approach (Single Round-trip)
The client sends a single POST request to the GraphQL endpoint with the following query body:
{
feed {
id
content
author {
name
profilePicture
}
likesCount
}
}
The server processes this query and returns a JSON object that mirrors the shape of the request, containing only the requested fields. This reduces the payload size and eliminates the latency of multiple TCP handshakes.
The Trade-off: Server-Side Complexity
While GraphQL solves client-side latency, it shifts the complexity to the server. Unlike REST, where you can easily cache responses at the HTTP level (using CDNs or Varnish) because each URL is a unique resource, GraphQL uses a single endpoint. This makes standard HTTP caching ineffective.
Engineers must implement field-level caching or use specialized clients like Relay to manage a normalized cache on the frontend. Additionally, because clients can write their own queries, there is a risk of "expensive" queries—requests that join too many tables or nest too deeply—which can spike CPU usage and crash a backend service if not guarded by query depth limiting or cost analysis.
Practical Verification
To determine if GraphQL is the right choice for your project, perform a payload audit. Use a network proxy (like Charles Proxy or Chrome DevTools) to capture the total bytes transferred for a primary feature in your app using REST. Then, prototype a GraphQL schema for that same feature and compare the response size. If your REST responses are consistently returning fields that the UI ignores, or if you are making more than three sequential calls to load a single view, the migration is likely justified.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.