// Stay in touch?
Products
Encore CloudEncore Cloud
Encore.tsEncore.ts
Encore.goEncore.go
PricingPricing
Book a DemoBook a Demo
Use Cases
AI-Powered DevelopmentAI-Powered Development
Event-Driven SystemsEvent-Driven Systems
Distributed SystemsDistributed Systems
Case StudiesCase Studies
ShowcaseShowcase
Resources
DocsDocs
InstallInstall
Example AppsExample Apps
Demo videoDemo video
ArticlesArticles
ResourcesResources
GitHub ReleasesGitHub Releases
Systems Operational
Company
About UsAbout Us
Swag ShopSwag Shop
ContactContact
JobsJobs
PressPress
TermsTerms
Privacy PolicyPrivacy Policy
Data Processing AgreementData Processing Agreement
Enterprise SLAEnterprise SLA
Encore
© 2026 EncoreAll rights reserved
© 2026 Encore All Rights Reserved
GitHubDiscordYouTube

GraphQL vs REST APIs

Choosing the right API architecture for your backend

03/20/26
5 Min Read
Ivan Cernja
03/20/26

GraphQL vs REST APIs

Choosing the right API architecture for your backend

Ivan Cernja
5 Min Read

REST gives you predictable endpoints, HTTP caching, and universal tooling. GraphQL gives you flexible queries, a typed schema, and fewer round trips. The tradeoff is where the complexity lives: REST puts it on the client (multiple requests, over-fetching), GraphQL puts it on the server (resolvers, data loaders, depth limiting).

For most backend services, REST is the simpler and better-supported path. GraphQL earns its place when multiple clients need different views of deeply nested data.

REST

REST APIs are built around resources. Each resource has a URL. You interact with it using HTTP methods:

  • GET /users/42 - retrieve a user
  • POST /users - create a new user
  • PUT /users/42 - replace a user
  • DELETE /users/42 - remove a user

Responses are JSON. Status codes tell you what happened. A typical endpoint:

GET /api/orders/123 { "id": 123, "status": "shipped", "customer_id": 42, "items": [ { "product_id": 7, "name": "Keyboard", "quantity": 1, "price": 89.99 }, { "product_id": 12, "name": "Mouse", "quantity": 1, "price": 49.99 } ], "total": 139.98 }

Why it works: HTTP methods are well-understood. Caching works at every layer - browser, CDN, reverse proxy. Every monitoring tool, HTTP client, and debugging proxy supports REST natively. Each request is self-contained, so horizontal scaling is straightforward.

GraphQL

GraphQL exposes a single endpoint where clients specify exactly what data they need. A typed schema defines all available data and operations:

type User { id: ID! name: String! email: String! orders: [Order!]! } type Query { user(id: ID!): User }

Clients query for specific fields:

query { user(id: "42") { name orders { id status total } } }

Only the requested fields come back. One request can traverse relationships that would take three REST calls.

Why it works: No over-fetching or under-fetching. The schema doubles as documentation. Adding fields is non-breaking since clients only request what they need. Especially valuable when mobile apps, web apps, and third-party consumers all need different views of the same data.

How they compare

DimensionRESTGraphQL
Data fetchingFixed response per endpointClient specifies exact fields
Over/under-fetchingCommon (mitigate with sparse fieldsets)Solved by design
CachingHTTP caching works nativelyRequires application-level caching
Type safetyOpt-in (OpenAPI + codegen)Built into the schema
ToolingUniversalSpecialized (GraphiQL, Apollo Studio)
Server complexityLow (route → handler)High (schema, resolvers, data loaders, depth limits)
PerformancePredictable per endpointVariable (clients can construct expensive queries)
AuthPer-endpointPer-field (more granular, more work)

Caching is REST's biggest structural advantage. Every URL is a cache key. CDNs, browsers, and reverse proxies all work without configuration. GraphQL sends POST requests to a single URL, which breaks URL-based caching entirely. You need Apollo Client's normalized cache, persisted queries, or a CDN layer like Stellate.

Flexibility is GraphQL's biggest structural advantage. A mobile app that only needs a user's name and avatar makes one request and gets exactly that. The same API serves a web dashboard that needs the user's full profile, orders, and payment history - also one request. REST would need separate endpoints or sparse fieldsets for each.

Complexity is the tiebreaker. REST is straightforward to build, monitor, and debug. Each endpoint does one thing, and performance is predictable. GraphQL requires resolvers, data loaders (to avoid N+1 queries), query depth limiting, and field-level authorization. That complexity is worth it when client flexibility is genuinely needed. It's overhead when it's not.

When to use REST

  • CRUD on well-defined resources
  • Caching matters (content delivery, read-heavy workloads)
  • Service-to-service APIs where both sides are under your control
  • Small teams that want to minimize backend complexity
  • Broad compatibility with third-party tools and integrations

When to use GraphQL

  • Multiple clients (web, mobile, third-party) need different views of the same data
  • Deep, interconnected data relationships
  • Public APIs where consumer flexibility is a priority
  • Mobile apps where reducing round trips on poor connections matters
  • Frontend teams that want to iterate on data requirements without backend changes

Building REST APIs with Encore.ts

REST is the right default for most backends. Encore.ts is built around that assumption.

Endpoints are TypeScript functions with typed request and response objects. Encore handles routing, validation, serialization, and documentation:

import { api } from "encore.dev/api"; interface Order { id: number; status: string; items: OrderItem[]; total: number; } export const getOrder = api( { method: "GET", path: "/orders/:id", expose: true }, async ({ id }: { id: number }): Promise<Order> => { return await orderService.findById(id); } );

You get type-safe request validation, automatic API documentation that stays in sync with your code, type-safe service-to-service calls, and built-in distributed tracing - without configuring any of it. The api() function pattern is also straightforward for AI coding agents to follow. Agents generate endpoints matching your existing structure, and TypeScript types ensure the generated code is valid. No separate schema definitions to maintain.

For a complete walkthrough, see How to Build a REST API with TypeScript in 2026. Encore.ts also includes primitives for databases, Pub/Sub, cron jobs, caching, and secrets. When you deploy with Encore Cloud, everything provisions automatically in your own AWS or GCP account.

Related reading

  • API Types: REST, GraphQL, gRPC, and More
  • gRPC vs JSON for Microservices
  • Best TypeScript Backend Frameworks in 2026
  • Event-Driven Architecture
Contents
REST
GraphQL
How they compare
When to use REST
When to use GraphQL
Building REST APIs with Encore.ts
Related reading

A development platform for your own cloud on AWS & GCP

Encore automates infrastructure management, observability, and documentation. Your team can focus on shipping product.

Ready to build your next backend?

Encore is the Open Source framework for building robust type-safe distributed systems with declarative infrastructure.