API Gateway, BFF, and GraphQL Explained for System Design Interviews
Preparing for System Design Interviews? Join ByteByteGo now for a structured preparation. They are also offering a rare 50% discount now on their lifetime plan.
Hello guys, Modern applications rarely serve just one type of client anymore. A single backend often needs to support web apps, mobile apps, internal tools, third-party integrations, and even IoT devices, each with very different needs.
This is where API Gateway, Backend for Frontend (BFF), and GraphQL come into the picture. At first glance, these concepts can feel interchangeable. All three sit between clients and backend services, all aim to simplify communication, and all promise cleaner APIs.
But they solve different problems and make different trade-offs. Choosing the wrong one can lead to over-fetching, tight coupling, duplicated logic, or systems that become painful to evolve at scale.
Codemia.io (60% OFF) (Sponsored)
Codemia.io is a hands-on system design learning platform that helps you practice designing real systems step-by-step. It gives you challenges like designing YouTube, WhatsApp, or URL Shorteners and provides guided feedback as you iterate.
If you are preparing for System Design interview then you can use Codemia.io to solve real problems and learn what it takes to explain your solution on real interview. Their platform is both AI powered and give you tools to architect and explain you solution.
In this article, Ashutosh Maheshwari , will break down API Gateway, BFF, and GraphQL in plain terms—what each pattern is, when it makes sense, and when it doesn’t.
You’ll learn how they differ in responsibility, how they impact performance and team ownership, and how to choose the right approach for your system design, whether you’re building a production system or preparing for a system design interview.
With that, over to Ashutosh to take you through the rest of the article
You have 50 microservices, each with its own API. Your frontend team is struggling. To build a single page, they’re making ten, maybe fifteen network calls. The app is slow. Users are complaining.
How do you fix this?
The first instinct is often wrong. It’s not about making the frontend code more complex or trying to optimize every single one of those fifty services.
The real problem is that you are exposing the chaos of your internal system directly to the client. The architectural fix is to build a smart layer in between.
Let’s talk about three ways to do this.
First, the foundational solution: the API Gateway.
Think of it as a traffic cop or a concierge for your backend. The client makes one single call to the gateway. For example, GET /product-details.
The gateway then turns around and does the hard work. It calls your product service, your inventory service, your pricing service, and your reviews service. It gathers all those responses, combines them into one clean package, and sends that single package back to the client.
This immediately solves the biggest problem: the client isn’t chatty anymore. It makes one call and gets one response. The complexity is now on the backend, where it belongs.
Now, we can get more sophisticated. What if your mobile app and your web app need different data? This leads to the second pattern: Backends for Frontends, or BFF.
This is a simple but powerful idea. Instead of one giant, general-purpose gateway, you create a separate, tailored gateway for each client. You have a Web BFF that serves the data exactly as the web app needs it. And you have a Mobile BFF that serves a leaner, more concise payload for the mobile app.
This decouples your frontend teams. The iOS team can now get changes made to their API without having to wait on, or potentially break, the web team. It’s a powerful pattern for autonomy.
Finally, let’s talk about the third, and most flexible approach: GraphQL.
Both the Gateway and the BFF pattern are decided on the backend. The backend engineer defines the endpoint and what data it returns.
GraphQL flips that script. It gives the power to the client.
You create one, single, powerful endpoint, /graphql. The frontend team can then send a query that specifies the exact data fields it needs. No more, no less.
If they need the product’s name and price, that’s all they ask for. If they need the name, price, and the top two reviews, they ask for that. They get exactly what they need in a single round trip.
This eliminates the problems of both over-fetching and under-fetching data.
So, to recap: An API Gateway to aggregate calls. A BFF to tailor responses for different clients. And GraphQL to give the client the power to ask for exactly what it needs.
But the choice of tool is less important than the philosophy behind it.
Here is the key takeaway: Stop designing your APIs from the inside-out.
Start by asking what the client needs. Design from the outside-in. Your job isn’t just to expose your services; it’s to provide a clean, simple, and performant contract to the applications that consume them.
That is how you solve the microservice mess.
I have also recorded a YT Video explaining this concepts :
And, if you like this post, don’t forget to subscribe to Ashutosh’s substack,
Other System Design Article you may like














Really appreciate the outside-in design philosophy mentioned here - the shift from thinking about internal services to thinking about client needs is where alotta teams get stuck. The BFF pattern for mobile vs web is brilliant for decoupling teams, but I'm curious bout the operational overhead - now you're maintaining multiple gateways instead of one. GraphQL solves over-fetching elegantly but the resolver complexity can bite you at scale, specially when you got nested queries hitting multiple services. The key insight is there's no one-size-fits-all - each pattern shines in different scenarios.