GraphQL in Enterprise: When It Makes Sense and When to Stay with REST¶
GraphQL has a decade of production use behind it — from Facebook to Shopify to Atlassian. In 2026, it is no longer hype, but a mature technology with clear use cases. The problem is that most companies deploy it incorrectly.
What GraphQL Solves (and What It Doesn’t)¶
Real Advantages¶
Elimination of over-fetching. A REST endpoint returns the entire object. A mobile client needs 3 fields out of 50. With GraphQL, it asks for exactly what it wants.
# GraphQL in Enterprise: When It Makes Sense and When to Stick with REST
query {
customer(id: "123") {
name
email
lastOrder {
total
status
}
}
}
One endpoint, multiple sources. Instead of 5 REST calls for a dashboard (customer + orders + invoice + address + preferences), one GraphQL query.
Strong typing. Schema is a contract. Frontend and backend know exactly what the API returns. Auto-generated TypeScript types, validation, documentation for free.
Evolution without versioning. Adding a new field doesn’t break existing clients. Deprecation at the field level, not entire endpoints.
What GraphQL Doesn’t Solve¶
- Server performance — shifts complexity from client to server. The N+1 problem is real.
- Caching — HTTP caching works on URLs. GraphQL POST requests bypass it.
- Security — arbitrary queries = potential DoS. You must handle query depth, complexity limits, rate limiting.
- Simplicity — for CRUD APIs, REST is simpler and more straightforward.
When GraphQL in Enterprise: YES¶
1. BFF (Backend for Frontend) vrstva¶
You have microservices with REST APIs and need to aggregate data for the frontend. GraphQL as a BFF layer is ideal:
Mobile App ──→ GraphQL BFF ──→ User Service (REST)
Web App ──→ GraphQL BFF ──→ Order Service (REST)
──→ Payment Service (REST)
Frontend teams define queries as needed. Backend services remain REST (simple, cacheable).
2. Multiple Clients with Different Needs¶
Web needs a detailed view, mobile a compact one, IoT devices minimal data. One GraphQL endpoint serves all without custom endpoints.
3. Rapidly Changing Product Requirements¶
A startup or early-stage product where the schema changes weekly. GraphQL allows frontend developers to iterate without waiting for the backend.
4. Data mesh / federation¶
A large organization with dozens of teams. Apollo Federation or a similar solution allows each team to own its part of the graph:
# Team A owns User
type User @key(fields: "id") {
id: ID!
name: String!
email: String!
}
# Team B extends User with orders
extend type User @key(fields: "id") {
id: ID! @external
orders: [Order!]!
}
When GraphQL: NO¶
CRUD API for Internal Services¶
You have a microservice that does CRUD on a single entity. REST is simpler, faster to implement, better cacheable.
High-throughput Services¶
API with millions of requests per second where every millisecond matters. GraphQL parsing and validation adds overhead. gRPC is a better choice.
File upload / streaming¶
GraphQL has no native support for binary data. Multipart upload exists (specification), but it is a hack.
Simple Backend, Single Client¶
If you have one frontend and a simple backend, GraphQL adds complexity without benefit.
Production Architecture¶
Schema design¶
Schema-first approach is the standard in enterprise:
- Design the schema with the product team
- Generate types for both backend and frontend
- Implement resolvers
- Schema is a contract — changes via PR review
# Schema as a contract
type Query {
"""Returns customer by ID. Requires auth scope: customer:read"""
customer(id: ID!): Customer
"""Full-text customer search. Max 100 results."""
searchCustomers(query: String!, limit: Int = 20): CustomerConnection!
}
type Customer {
id: ID!
name: String!
email: String!
createdAt: DateTime!
orders(first: Int = 10, after: String): OrderConnection!
# deprecated field — use `name` instead
fullName: String @deprecated(reason: "Use `name` field")
}
N+1 Solution: DataLoader¶
The most common performance problem. Solution: DataLoader pattern (batching + caching):
# Without DataLoader: N+1 queries
# customer.orders → SELECT * FROM orders WHERE customer_id = 1
# customer.orders → SELECT * FROM orders WHERE customer_id = 2
# ... N dotazů
# With DataLoader: 1 query
# batch_load_orders([1, 2, 3, ...]) →
# SELECT * FROM orders WHERE customer_id IN (1, 2, 3, ...)
Security hardening¶
In production, you MUST address:
Query depth limiting — limiting the depth of nested queries (typically max 10):
# This would pass without a limit and kill the server:
query {
user {
orders {
items {
product {
reviews {
author {
orders {
# ... infinitely
}
}
}
}
}
}
}
}
Query complexity analysis — each field has a cost, the sum must not exceed the limit.
Persisted queries — in production, you don’t accept arbitrary queries. The client sends a hash, the server looks up the registered query. Eliminates injection and DoS.
Rate limiting — per-field or per-operation, not per-request.
Monitoring¶
GraphQL endpoints always return HTTP 200 (even on errors). Standard monitoring doesn’t work. You need:
- Per-resolver metrics — latency, error rate at the field level
- Query complexity tracking — average/maximum query complexity
- Slow query log — queries above threshold
- Field usage analytics — which fields nobody uses → candidates for deprecation
Tools: Apollo Studio, GraphQL Hive (open-source), Grafana + custom exporter.
Technologies in 2026¶
| Category | Recommendation |
|---|---|
| Server (Node.js) | Apollo Server 4, Yoga (Envelop) |
| Server (JVM) | Netflix DGS, Spring for GraphQL |
| Server (Python) | Strawberry, Ariadne |
| Server (.NET) | Hot Chocolate |
| Federation | Apollo Federation 2, Cosmo Router |
| Client | Apollo Client, urql, Relay |
| Codegen | GraphQL Code Generator |
| Monitoring | Apollo Studio, GraphQL Hive |
Recommended Approach for Czech Companies¶
- Start with a BFF layer — keep backend services on REST, add a GraphQL aggregation layer
- Schema-first — design the schema together with the frontend team
- Persisted queries from the start — security and performance
- DataLoader always — without exception, even for “simple” resolvers
- Federation only when you need it — not prematurely, the complexity is real
GraphQL is not a replacement for REST. It is a complement for specific use cases. Deploy it where it solves a real problem, and leave REST where it works.
CORE SYSTEMS designs and implements API architectures for enterprise clients — REST, GraphQL, and gRPC. Get in touch for an architectural consultation.
Need help with implementation?
Our experts can help with design, implementation, and operations. From architecture to production.
Contact us