GitHub REST API vs GraphQL API: The Complete Difference, Explained

GitHub REST API vs GraphQL API: The Complete Difference, Explained

A deep, beginner-friendly guide to how GitHub exposes its data through two very different API architectures — what each one actually is, how they work under the hood, when GitHub itself recommends one over the other, and how real integrations are architected around both.

Imagine walking into a massive library and asking the librarian for “everything about the history of bridges.” A librarian working under strict, old-fashioned rules hands you seven different books — one on Roman architecture, one on 19th-century engineering, one on famous collapses, one on modern materials — because each book only covers one fixed topic, and you have to read all seven cover to cover to piece together what you actually wanted. A more modern librarian, instead, sits down with you, listens to exactly what you’re after, and hands you a single custom-assembled folder with precisely the chapters you asked for, nothing more, nothing less. That difference — fixed, pre-packaged responses versus a single, precisely shaped answer to a precisely shaped question — is, at its core, the entire difference between GitHub’s REST API and GitHub’s GraphQL API. Both let a program ask GitHub for information about repositories, issues, pull requests, and users. But how they ask, how GitHub answers, and how efficiently that conversation happens are built on two fundamentally different philosophies of API design. This guide walks through both, from the ground up, with no assumed prior knowledge.

AWhat Is an API, and Why Does GitHub Have Two?

Before comparing REST and GraphQL, it helps to be completely clear on what an API is doing in the first place, and why a platform as large as GitHub would maintain two separate ways of doing the same basic job.

An API (Application Programming Interface) is a defined way for one piece of software to ask another piece of software for data or to trigger an action, without needing to know how that other software works internally. When you use a tool that shows your GitHub pull requests inside your code editor, or a bot that automatically labels new issues, that tool is not somehow reading GitHub’s website — it is making structured requests to a GitHub API and receiving structured data back.

GitHub exposes two separate APIs for this purpose:

REST API

The Original, Resource-Based API

Organizes GitHub’s data into fixed “resources” — repositories, issues, users — each reachable at its own predictable web address, returning a fixed shape of data for each address.

GRAPHQL API

The Newer, Query-Based API

Exposes GitHub’s data as one single flexible endpoint where the caller writes a precise query describing exactly which fields, and how deeply nested, they want back.

GitHub did not build GraphQL to replace REST — both are actively maintained, and GitHub’s own official guidance is that the right choice depends on what you are building. Understanding why requires understanding how each one actually works, which is where the next several chapters go.

Everyday Analogy

REST is like a restaurant with a fixed menu: you can order “the Caesar salad,” and you get exactly what’s printed on the menu, with all its standard ingredients, whether you wanted the croutons or not. GraphQL is like a restaurant where you can tell the chef exactly which ingredients to include and which to leave off, and the kitchen prepares that one custom dish — no more, no less.

BHow the GitHub REST API Is Built

REST has been GitHub’s primary API since the platform’s early years, and its design directly reflects a style of API architecture called Representational State Transfer, first described in the early 2000s and adopted almost universally across the web since.

In REST, every piece of data GitHub knows about is modeled as a resource, and every resource lives at its own fixed web address, called an endpoint. A specific repository is a resource. The list of issues on that repository is a resource. A single pull request is a resource. Each of these has its own dedicated endpoint address, and asking for that resource means sending a request to that specific address.

flowchart LR
    Client["Client Application"] -->|"GET /repos/owner/repo"| E1["Repository Endpoint"]
    Client -->|"GET /repos/owner/repo/issues"| E2["Issues Endpoint"]
    Client -->|"GET /repos/owner/repo/pulls"| E3["Pull Requests Endpoint"]
    Client -->|"GET /users/username"| E4["User Endpoint"]
    E1 --> R1["Fixed Repository JSON Shape"]
    E2 --> R2["Fixed Issues Array Shape"]
    E3 --> R3["Fixed Pull Requests Array Shape"]
    E4 --> R4["Fixed User JSON Shape"]
    

FIG 1 — Every REST resource lives at its own fixed endpoint, each returning a fixed response shape

HTTP Verbs as Actions

REST reuses the standard verbs already built into the web’s own HTTP protocol to describe what action is being taken on a resource: retrieving data, creating something new, updating something existing, or deleting something. This mapping — action expressed through the verb, target expressed through the address — is one of REST’s defining characteristics, and it is why REST endpoints tend to read almost like plain English once you know the pattern: “retrieve the issues on this repository,” “create a new issue on this repository,” “update this specific issue,” “delete this specific comment.”

Fixed Response Shapes

Every REST endpoint has a predetermined response structure designed and documented by GitHub in advance. Requesting a repository’s data always returns the same set of fields — name, description, star count, owner, and dozens more — regardless of whether the calling application actually needs all of them. This predictability is a strength for simple use cases and a weakness for precise ones, a tension that becomes the central theme of this entire guide.

Versioning

Because REST endpoints have a fixed, documented shape, changing that shape in a way that removes or renames a field would break every application depending on the old shape. GitHub manages this by publishing dated API versions, allowing existing integrations to keep working against an older, stable version while new integrations can opt into newer versions with different behavior.

i
What An Interviewer May Ask

“Why does REST tie actions to HTTP verbs instead of just using one verb for everything?” A strong answer explains that reusing HTTP’s own semantics lets REST APIs be understood, cached, and secured using infrastructure the entire web already relies on — browsers, proxies, and firewalls all already understand what a retrieval request versus a deletion request implies.

CHow the GitHub GraphQL API Is Built

GraphQL takes a fundamentally different starting point: instead of many endpoints each returning a fixed shape, there is exactly one endpoint, and the shape of the response is decided by the caller, every single time.

GraphQL is a query language for APIs, originally developed at a major social media company to solve exactly the kind of over-fetching and under-fetching problems described later in this guide, and GitHub adopted it as an official, fully supported second API surface. Rather than many resource addresses, GraphQL exposes a single endpoint. Every request sent to that endpoint carries a query — a structured description, written in GraphQL’s own syntax, of exactly which pieces of data the caller wants, including how deeply to follow relationships between them.

flowchart LR
    Client["Client Application"] -->|"POST / with a Query
    describing exact fields needed"| Single["Single GraphQL Endpoint"]
    Single --> Schema["GitHub's GraphQL Schema
    (the full graph of available data)"]
    Schema --> Resolve["Resolvers Fetch Only
    the Requested Fields"]
    Resolve --> Response["Response Shaped
    Exactly Like the Query"]
    

FIG 2 — GraphQL exposes one endpoint; the query itself determines the shape of the response

The Schema: A Typed Map of Everything Available

GraphQL APIs are built around a schema — a complete, strongly typed description of every kind of data available, every field on every type, and how those types connect to one another. GitHub’s GraphQL schema describes repositories, issues, pull requests, users, organizations, and how each connects to the others, forming something closer to a navigable graph of related data than a list of separate resources — which is where GraphQL gets its name.

Queries: Asking for Exactly What You Need

A GraphQL query mirrors the shape of the data it wants back. If a caller wants only a repository’s name and its five most recent open issues’ titles, the query says exactly that, and GitHub’s response contains exactly that — no star count, no owner details, no extra issue fields the caller never asked for.

Mutations: Making Changes

Where REST uses different HTTP verbs to express different actions, GraphQL uses a single request mechanism for everything, but distinguishes read operations (called queries) from write operations (called mutations) at the language level. A mutation to open a new issue looks structurally similar to a query, but is explicitly named and typed as an action that changes data rather than merely reading it.

Everyday Analogy

If REST is a library with many separate labeled shelves, GraphQL is a single, enormous, interconnected card catalog where every card points to related cards — a book links to its author, the author links to their other books, those books link to their reviews — and you can follow exactly as many links as you actually need in one single request, instead of pulling one card, walking to a new shelf, and starting over.

DThe Core Problem: Over-Fetching and Under-Fetching

To really understand why GitHub built a second API architecture instead of just improving REST, you need to understand the two specific inefficiencies GraphQL was designed to eliminate.

Over-Fetching

Over-fetching happens when a REST endpoint’s fixed response shape includes far more data than the calling application actually needs. A mobile app that only wants to display a repository’s name and star count still receives the repository’s full description, its license details, its default branch name, its homepage URL, and dozens of other fields — all transmitted over the network, parsed, and then immediately discarded, wasting bandwidth and processing time on both ends for no benefit.

Under-Fetching

Under-fetching is the opposite problem: a single REST endpoint often does not include everything a caller needs in one response, forcing the application to make several separate requests to different endpoints and manually stitch the results together. Displaying a repository along with its five most recent contributors’ profile pictures might require one request for the repository, then a separate request per contributor to fetch their avatar — a pattern commonly called the “N+1 requests” problem, because one initial request for a list frequently balloons into N additional requests, one per item in that list.

flowchart TD
    Need["Goal: Repo Name + 5 Contributors' Avatars"] --> R1["REST: Request 1
    GET repository"]
    R1 --> R2["REST: Request 2
    GET contributor 1"]
    R1 --> R3["REST: Request 3
    GET contributor 2"]
    R1 --> R4["REST: Request 4..6
    GET contributors 3-5"]
    Need --> G1["GraphQL: Single Request
    repo name + first 5 contributors' avatars,
    nothing else"]
    

FIG 3 — REST often needs multiple round trips for related data; GraphQL expresses the same need in one request

1
GRAPHQL REQUEST CAN REPLACE SEVERAL CHAINED REST REQUESTS
N+1
CLASSIC REST PATTERN FOR FETCHING A LIST’S RELATED DETAILS
0
UNUSED FIELDS IN A WELL-WRITTEN GRAPHQL RESPONSE
!
Why This Matters for Mobile and Low-Bandwidth Clients

Over-fetching and under-fetching are mostly an inconvenience on a fast office connection, but on a mobile network with limited bandwidth and higher latency per request, both problems compound — every wasted field and every extra round trip directly costs the user time and data, which is part of why GraphQL originated at a company building mobile-first applications.

EA Side-by-Side Walkthrough (Conceptual, No Code)

To make the difference concrete without diving into syntax, walk through the same real task — “show a repository’s name, its open issue count, and the usernames of the last three people who commented on its most recent issue” — through both architectures.

1

REST Approach: Request the Repository

The caller first requests the repository resource, receiving its full fixed shape — name, description, star count, and much more, most of it unused for this task.

2

REST Approach: Request the Issues List

A second request retrieves the repository’s issues, sorted by recency, again returning full issue objects with many fields the caller does not need, just to identify the most recent one.

3

REST Approach: Request That Issue’s Comments

A third request fetches the comments on that specific issue, from which the caller manually extracts just the usernames of the last three commenters, discarding the rest of each comment’s data — its body text, timestamps, and reaction counts.

4

GraphQL Approach: One Request, One Query

A single GraphQL query describes exactly this nested shape — the repository’s name, its open issue count, its most recent issue, and that issue’s last three commenters’ usernames — and GitHub’s GraphQL endpoint returns precisely that structure in one response, with every intermediate step resolved server-side instead of round-tripped back to the caller.

Notice what changed: the REST version required three separate network round trips, each returning far more data than needed, with the caller doing the work of stitching the results together. The GraphQL version required one round trip, returning exactly the requested shape, with GitHub’s own servers doing the work of following the relationships internally.

“REST asks ‘what resource do you want?’ GraphQL asks ‘what shape of answer do you want?'”

FRate Limiting: A Fundamentally Different Model

Because REST and GraphQL count “cost” so differently, GitHub also has to rate-limit them differently — and this is one of the most practically important differences for anyone building against these APIs at scale.

REST: Counting Requests

GitHub’s REST API enforces a limit on the raw number of requests an authenticated caller can make within a given time window, regardless of how much or how little data each individual request returns. A request for a tiny piece of data and a request for a massive list of results both count as exactly one request against the same limit.

GraphQL: Counting Query Complexity

Because a single GraphQL query can request an arbitrarily large, deeply nested amount of data — following relationships many layers deep in one call — counting raw requests would be meaningless; a single enormous query could pull far more data than a hundred REST requests combined. GitHub instead assigns every GraphQL query a calculated point cost based on the complexity and depth of what it requests, and limits the total points a caller can spend within a time window, rather than the number of queries itself.

DimensionREST APIGraphQL API
What is limitedNumber of requestsTotal query “points” (complexity-based)
Cost of a requestAlways exactly 1, regardless of sizeVaries with fields requested and nesting depth
Easiest way to hit the limitMaking many small, repeated requestsWriting very deep or very broad single queries
PredictabilitySimple to predict — count your callsRequires understanding query cost before running at scale
i
What An Interviewer May Ask

“Why can’t GraphQL just count requests the same way REST does?” Because a single GraphQL request has no fixed size — it can be trivially small or enormous depending entirely on what the caller writes into the query — so a request-counting limit would be either too permissive for huge queries or too restrictive for tiny ones. A complexity-based points system is the only way to fairly bound the actual load a query places on GitHub’s servers.

GAuthentication and Access Control

Both APIs sit behind the same underlying identity system, but the way permissions are scoped and checked differs slightly in practice.

Shared Identity Foundation

Both the REST API and the GraphQL API authenticate callers using the same underlying mechanisms available on GitHub — personal access tokens, GitHub App installation tokens, and OAuth tokens issued through an authorized application. A single valid token generally works for both APIs, and the same scoped permissions model governs what either API is allowed to see or change on the caller’s behalf.

Field-Level Access in GraphQL

Because GraphQL queries can request deeply nested, cross-cutting data in a single call, GitHub’s GraphQL layer checks permissions at a finer grain — evaluating whether the caller’s token is allowed to see each individual field being requested, not just whether it can access the top-level resource. A query that spans a public repository and a private one nested inside its data graph will return the public data while quietly omitting or erroring on the private portion the token cannot see.

Resource-Level Access in REST

REST’s access checks map more directly onto each endpoint: a request either has permission to hit that specific endpoint for that specific resource, or it does not, and the entire request succeeds or fails as a unit rather than partially succeeding field by field.

Practical Effect

In REST, a permission problem tends to fail an entire request outright. In GraphQL, a permission problem can produce a partially successful response — the fields you’re allowed to see, alongside explicit errors describing exactly which requested fields you were denied — which changes how error handling has to be written on the calling side.

HWhen to Use Which: GitHub’s Own Guidance

GitHub does not present these as competing replacements for one another — its own documentation frames them as complementary tools suited to different situations.

REST Tends to Fit Better When…

  • The integration is simple, needs a small number of well-known fields, and doesn’t benefit from custom shaping
  • Webhooks are involved, since GitHub’s webhook payloads are structured similarly to REST responses
  • The task is a single, isolated action — creating one issue, fetching one file’s contents
  • Broad ecosystem tooling and simpler caching behavior (thanks to REST’s use of standard HTTP semantics) matter more than raw efficiency

GraphQL Tends to Fit Better When…

  • The task needs several related pieces of data at once — a dashboard combining repositories, issues, and contributors in one view
  • Minimizing the number of network round trips matters, such as in a mobile app or a rate-limit-sensitive integration
  • The exact fields needed vary by use case, and a single flexible query is easier to maintain than many narrow REST calls
  • The integration needs to explore deeply nested relationships — following from an organization to its repositories to their pull requests to those pull requests’ reviewers, in one call

GitHub Actions and Automation

Many automation scripts and GitHub Actions workflows still lean on the REST API for simple, well-defined operations — labeling an issue, merging a pull request — precisely because those tasks map cleanly onto a single REST endpoint and a single HTTP verb, with no benefit from GraphQL’s flexible shaping.

Dashboards, Analytics, and Data-Heavy Tools

Tools that build rich views across many related GitHub entities at once — project management integrations, analytics dashboards, custom internal tooling that combines organization, repository, and contributor data — tend to gravitate toward GraphQL, because the alternative in REST would mean orchestrating and combining the results of many separate calls by hand.

IPagination: Two Different Philosophies

Any API returning potentially huge lists — every issue ever filed on a large repository, for instance — has to break results into manageable pages, and REST and GraphQL approach this differently as well.

REST: Page Numbers

GitHub’s REST API commonly uses simple page-number-based pagination for list endpoints, where a caller requests a given page of a given size, and moves to the next page by incrementing a page number parameter on subsequent requests.

GraphQL: Cursor-Based Pagination

GitHub’s GraphQL API uses a more robust pattern called cursor-based pagination, where each page of results comes with an opaque “cursor” marker pointing to exactly where that page ended, and the next request simply says “give me the next page after this cursor.” This approach is more resilient to items being added or removed from a list while paging through it, since it tracks position relative to a specific item rather than a raw page number that can shift if the underlying list changes mid-traversal.

Everyday Analogy

Page-number pagination is like being told “go to page 4 of the book.” If someone inserts new pages near the front while you’re reading, “page 4” now means something different than it did a moment ago. Cursor-based pagination is like a bookmark placed after a specific sentence — no matter what gets added or removed elsewhere in the book, “continue from right after this bookmark” always means the same thing.

i
What An Interviewer May Ask

“Why would cursor-based pagination be preferred for a constantly changing dataset like GitHub issues?” Because new issues can be created and existing ones closed at any moment; page-number pagination risks skipping or duplicating items as the underlying list shifts mid-traversal, while a cursor anchored to a specific item’s position avoids that entirely.

JError Handling and Response Status

How each API reports that something went wrong is another meaningful divergence, and it affects how integration code has to be written.

REST: HTTP Status Codes

REST leans heavily on standard HTTP status codes to communicate outcomes — a successful retrieval, a successful creation, a request for something that doesn’t exist, a request the caller isn’t authorized to make, and so on. Calling code can often make high-level decisions just by inspecting the status code, before even looking at the response body.

GraphQL: Always 200, Errors in the Body

GraphQL requests almost always return the same successful HTTP status regardless of whether the query itself fully succeeded, because the HTTP request itself did succeed — the GraphQL endpoint received the query and responded. Any problems with the query — a field that doesn’t exist, a permission failure on part of the requested data, a downstream error resolving one branch of the query — are instead reported inside the response body itself, in a dedicated errors section, potentially alongside the successfully resolved parts of the response.

flowchart TD
    ReqR["REST Request"] --> StatusR{"HTTP Status Code"}
    StatusR -->|"Success Range"| BodyR["Response Body = Data"]
    StatusR -->|"Error Range"| ErrR["Response Body = Error Details"]
    ReqG["GraphQL Request"] --> StatusG["HTTP Status: Success"]
    StatusG --> BodyG["Response Body Contains
    BOTH data AND errors sections,
    possibly at the same time"]
    

FIG 4 — REST signals success or failure primarily through HTTP status; GraphQL signals it inside the response body

Why This Trips Up New Integrators

Developers used to REST’s pattern of “check the status code first” sometimes assume a GraphQL response is fully successful just because the HTTP call itself didn’t fail, and miss a partial error buried in the response body describing that one nested field couldn’t be resolved — making it essential to always inspect the body’s errors section explicitly when working with GraphQL.

KCaching Behavior

Caching — storing a previous response so a repeated request doesn’t have to be fully recomputed — behaves very differently across the two architectures, largely as a consequence of how their endpoints are structured.

REST’s Natural Fit with HTTP Caching

Because every REST resource lives at its own fixed, predictable address, and returns a consistent shape, REST responses can be cached using the web’s standard HTTP caching mechanisms almost for free — a cache simply needs to remember “the last response for this exact address,” which works cleanly because the same address always means the same kind of request.

GraphQL’s More Complex Caching Story

Because every GraphQL request goes to the same single endpoint, and the specific data requested varies with every differently written query, the same simple “cache by address” approach does not work. Effective GraphQL caching instead typically happens at a finer grain — caching individual pieces of data by their own unique identity within the response, so that overlapping queries requesting the same underlying entity from different angles can still reuse already-fetched data, a pattern that generally requires more deliberate client-side tooling to implement well.

!
Trade-off to Weigh

GraphQL’s flexibility in shaping exactly the data you want comes at the direct cost of losing REST’s simple, built-in cacheability — a factor worth weighing for integrations that repeatedly request largely similar data and would benefit heavily from straightforward caching.

LDesign Patterns and Anti-patterns

Teams building against either API tend to fall into a recognizable set of good and bad habits. Naming them makes them easier to catch during design review.

Pattern: Matching the API to the Shape of the Task

Choosing REST for simple, isolated, single-resource operations, and GraphQL for tasks that genuinely need several related pieces of data assembled together — rather than defaulting to one API for everything regardless of the task’s actual shape.

Pattern: Requesting Only What Is Displayed

In GraphQL specifically, writing queries that request exactly the fields a given screen or feature actually renders, and nothing more — resisting the temptation to request broad, “just in case” data that reintroduces the very over-fetching problem GraphQL exists to solve.

Anti-pattern: Treating GraphQL Queries Like REST Endpoints

Writing one enormous, fixed GraphQL query that always requests every field any part of the application might ever need, and reusing it everywhere — which throws away GraphQL’s core advantage and can even reintroduce over-fetching in a new form.

PATTERN-002 ANTI-PATTERN
Pattern

Using GraphQL for every single call in an integration, including simple, single-resource operations that REST already handles cleanly.

Why It Feels Reasonable

Standardizing on one API surface seems simpler to maintain than juggling two.

Why It Fails

Simple operations gain nothing from GraphQL’s flexibility, while inheriting its more complex error handling, more complex caching, and less predictable rate-limit cost — added complexity with no corresponding benefit for that specific call.

Anti-pattern: Deeply Nested, Unbounded GraphQL Queries

Writing a GraphQL query that follows relationships many layers deep without limiting how many items are requested at each layer — for example, every repository in an organization, each with every one of their pull requests, each with every one of their reviews — which can produce an enormous point cost and a slow, resource-heavy response, sometimes rejected outright for exceeding complexity limits.

MBest Practices and Common Mistakes

A handful of habits separate integrations that scale smoothly from ones that hit rate limits, break on edge cases, or become difficult to maintain.

BEST PRACTICE

Profile Before Choosing

Sketch out the actual data your integration needs before deciding between REST and GraphQL, rather than picking based on preference alone.

BEST PRACTICE

Always Inspect GraphQL’s Errors Section

Never assume a successful HTTP status means a fully successful GraphQL response — check the body’s errors section explicitly, every time.

BEST PRACTICE

Respect Both Rate-Limit Models

Track REST’s request count and GraphQL’s point cost separately, and design retry and backoff logic around whichever model applies.

BEST PRACTICE

Bound Query Depth and List Sizes

In GraphQL, explicitly limit how many items are requested at each nested level to avoid runaway complexity costs.

BEST PRACTICE

Prefer Cursor Pagination for Large, Changing Lists

Use GraphQL’s cursor-based pagination for lists likely to change during traversal, to avoid skipped or duplicated results.

BEST PRACTICE

Mix Both APIs Where It Makes Sense

It is entirely normal, and often optimal, for one integration to use REST for simple actions and GraphQL for complex reads, in the same codebase.

Common Mistakes

  • Assuming GraphQL is unconditionally “better” and migrating simple REST calls to GraphQL for no functional benefit.
  • Forgetting that GraphQL’s rate limit is based on query complexity, and being surprised when a single large query consumes far more of the limit than expected.
  • Treating REST’s fixed response shape as if it were customizable, and manually filtering unused fields client-side instead of recognizing that GraphQL exists precisely for that need.
  • Writing GraphQL queries with unbounded nested lists, leading to unexpectedly expensive or slow responses.

NReal-World Usage Patterns

Seeing how established tools and platforms actually choose between the two makes the earlier guidance feel concrete rather than theoretical.

1

CI/CD Automation Scripts

Simple automation — closing stale issues, adding a label, posting a comment — overwhelmingly favors the REST API, since each action maps directly onto one endpoint and one HTTP verb with no benefit from custom data shaping.

2

IDE and Editor Integrations

Tools that surface pull requests, review comments, and issue statuses directly inside a code editor commonly use GraphQL, because a single view often needs to combine data from several related GitHub entities at once, and minimizing round trips keeps the editor feeling responsive.

3

Analytics and Reporting Dashboards

Internal tools that summarize engineering activity across many repositories — contribution trends, review turnaround times, issue aging — lean toward GraphQL, since these reports are exactly the kind of broad, precisely shaped, cross-entity query GraphQL was designed for.

4

Webhook-Driven Bots

Bots that react to GitHub webhook events — a new pull request opened, a comment posted — typically pair the incoming webhook payload with follow-up REST calls to perform simple actions, since the webhook payload’s shape already resembles REST’s resource model.

OFrequently Asked Questions

Q1Is GitHub planning to retire the REST API in favor of GraphQL?
No. GitHub actively maintains both APIs and presents them as complementary tools suited to different situations, not as an old version being phased out in favor of a new one.
Q2Can the same access token be used for both APIs?
Yes. Both APIs authenticate against the same underlying identity and permission system, so a single properly scoped token generally works for both, though GraphQL enforces some permission checks at a finer, per-field level.
Q3Is GraphQL always faster than REST?
Not necessarily. GraphQL tends to be more efficient for tasks needing several related pieces of data in one response, but for a single simple lookup, a well-designed REST endpoint can be just as fast, with the added benefit of simpler HTTP-level caching.
Q4Why does a GraphQL request sometimes return partial data alongside errors?
Because GraphQL resolves each requested field somewhat independently, a permission issue or a downstream problem affecting one part of a query does not necessarily prevent the rest of the query from succeeding — the response can legitimately contain both successfully resolved data and specific errors for the parts that failed.
Q5Do REST and GraphQL share the same rate limit?
No. They are tracked separately — REST counts the number of requests made, while GraphQL tracks a calculated point cost based on query complexity, so activity on one does not directly consume the other’s limit.
Q6Which one should a beginner learn first?
REST is generally the easier starting point, since its fixed, predictable endpoints and reliance on standard HTTP verbs and status codes are more approachable before layering on GraphQL’s schema-based query language and its more nuanced error and rate-limit handling.

PSummary and Key Takeaways

Key Takeaways

  • REST organizes GitHub’s data into many fixed-address resources, each returning a predetermined response shape, with actions expressed through standard HTTP verbs.
  • GraphQL exposes a single endpoint and a typed schema, letting the caller write a precise query that shapes the exact response it needs, following related data in one request instead of several.
  • Over-fetching and under-fetching — receiving more data than needed, or needing several chained requests to gather related data — are the core inefficiencies GraphQL was built to eliminate.
  • Rate limiting differs fundamentally: REST counts raw requests, while GraphQL counts a calculated complexity-based point cost, since a single GraphQL query has no fixed size.
  • Error handling differs: REST reports outcomes primarily through HTTP status codes, while GraphQL almost always returns a successful status and reports problems inside the response body itself, sometimes alongside partially successful data.
  • Caching is naturally simpler in REST, thanks to its fixed, predictable addresses, while GraphQL requires more deliberate, finer-grained caching strategies due to its flexible, per-query response shapes.
  • Neither API is a strict upgrade over the other: GitHub actively maintains both, and mature integrations frequently use REST for simple, isolated actions and GraphQL for complex, related, or bandwidth-sensitive reads within the very same codebase.