One request,
exactly the fields the screen needs
A mobile app screen that needs a user, their recent orders and a product recommendation in one view either makes three separate REST calls and stitches them together, or gets a GraphQL query that asks for exactly that shape in one request. We build GraphQL where screens genuinely vary in what they need, not as a default replacement for a simpler REST API.
What it is
GraphQL is an API query language where a client specifies exactly which fields it needs across potentially several related entities in one request, and the server resolves that query and returns exactly that shape, nothing more, nothing less. Unlike REST, where each endpoint returns a fixed shape and a client often needs several requests stitched together to assemble a full screen’s worth of data, GraphQL lets the client’s actual data need drive the request.
When you need it (and when you do not)
It earns its cost when different clients or different screens within the same product need meaningfully different, often nested, data shapes from the same underlying entities, a mobile app screen needing a lean subset of fields on a slow connection, a desktop dashboard needing the same entities with far more detail. A multi-vendor marketplace platform we built benefits from this: a seller dashboard, a buyer-facing storefront and an admin view all need different slices of the same product and order data.
It is the wrong tool for a simple API with a small number of clear resource types and one main consumer; REST is simpler to build, simpler to cache at the HTTP level, and easier for a new developer to reason about without learning a query language first. We recommend REST as the default and reach for GraphQL specifically when the variable-data-shape problem is real, not because it is the more interesting technology to build.
How we build it
Schema design is the real engineering work in a GraphQL API: we map the schema to actual business entities and the real relationships between them, not a one-to-one copy of database tables, since a schema that just mirrors the database exposes implementation details a client should never need to know about. This is done with both the frontend team and the backend team in the room, since the schema is the contract both sides will live with.
Resolver batching is built in from the start using DataLoader or an equivalent, specifically to avoid the N+1 query problem, where naively resolving a list of items triggers one database query per item instead of one batched query for the whole list. This is the single most common performance mistake in GraphQL APIs we have seen in audits, and it is far cheaper to prevent than to retrofit once a query pattern is already in production.
Authorization happens at the field level where the data actually requires it: a query for a product might expose different fields depending on whether the requester is the seller, an admin, or a public visitor, resolved per field rather than per endpoint. We also set query complexity limits, since GraphQL’s flexibility means a client, malicious or just careless, can construct a single deeply nested query that is far more expensive than any REST endpoint would allow, and an API without a complexity limit has no real ceiling on that.
What to watch
GraphQL’s caching story is genuinely more complex than REST’s; a REST GET request caches cleanly at the HTTP and CDN level, while a GraphQL query over POST needs its own caching strategy, usually at the resolver or data-loader level rather than the transport level. We plan this explicitly rather than discovering it as a performance problem after launch. Query complexity limits and rate limiting need to be real, not theoretical, since GraphQL’s expressiveness is exactly what makes an unprotected endpoint a bigger liability than an equivalent REST API. And a schema that grows without discipline, fields added ad hoc for one screen’s convenience, becomes as tangled as the REST sprawl GraphQL was meant to avoid; we review schema changes against the same entity model discipline from the first version onward.
Price and timeline
| Option | Price | What it covers | Timeline |
|---|---|---|---|
| Core schema and API | from $4,000 | Schema design, batched resolvers, authorization | 3 to 5 weeks |
| Multi-client API with complexity limits | from $9,000 | Several consuming apps, query complexity limits, caching strategy | 5 to 7 weeks |
Running cost is backend hosting, typically $30 to $250 a month depending on query volume and complexity.
Related
This pairs with API-first backend with OpenAPI as the alternative contract style worth comparing before committing, and with websocket real-time features when some of the same data also needs live updates. See the development service page for our full build process. For real examples, see the multi-vendor marketplace platform and ProBay’s own marketplace infrastructure.
Stitching together several REST calls per screen right now? Get in touch and we will tell you honestly if GraphQL is actually the fix.
FAQ
How much does a GraphQL API cost?
From $4,000 for a schema covering your core entities with batched resolvers and authorization, 3 to 7 weeks. A larger API serving a complex marketplace or multi-app product runs $8,000 to $16,000.
Should we use GraphQL or REST?
GraphQL earns its cost when clients, especially mobile apps on variable connections, need different nested data shapes per screen and reducing request count matters, or when several frontends need different subsets of the same data. REST is simpler to build, cache and reason about, and remains the better default for most APIs. We assess your actual client needs honestly rather than defaulting to whichever is more fashionable.
What is the N+1 problem and do I need to care?
It is a common GraphQL performance bug where resolving a list of items triggers one database query per item instead of one batched query for all of them, which can quietly turn a reasonable API into a slow one under real load. We build resolver batching with DataLoader or an equivalent from the first version specifically to avoid this, rather than fixing it after a performance complaint.
Can different users see different fields?
Yes, field-level authorization is a core part of schema design: a public query might expose a product's name and price while hiding internal cost data, resolved per field based on who is asking, not just per endpoint the way REST authorization usually works.
Who owns the schema and the server?
You. The GraphQL schema, resolvers and server code live in your repository, with schema documentation generated automatically so it never falls out of sync with what the API actually serves.