← Back to Integration & Data
INTG-012 Integration & Data 20 min read For: Salesforce Architects & Tech Leaders

GraphQL for Salesforce: What It Means and Why It Matters

Salesforce launched its GraphQL API in 2023 and it has been gaining traction with front-end developers and mobile teams ever since. Understanding what problem it solves — and the significant limitations it carries — is essential before committing to it as your primary API pattern for new integrations.

VS

Vishal Sharma

Salesforce Architecture Specialist · Updated May 2026

What you will learn...
  • What GraphQL is and why it was designed as an alternative to REST
  • How Salesforce's GraphQL API works — the schema, queries, and mutations
  • The over-fetching and under-fetching problems GraphQL solves in the Salesforce REST API context
  • Current limitations of Salesforce GraphQL versus the REST and SOQL APIs
  • Which use cases GraphQL is well-suited for in the Salesforce ecosystem
  • Performance characteristics and rate limit implications of the GraphQL API

Why GraphQL Exists

GraphQL was developed by Facebook in 2012 and open-sourced in 2015 to solve a fundamental REST API problem: the impedance mismatch between what an API returns and what the client actually needs. REST APIs return fixed resource shapes — a GET /accounts/{id} returns a predefined set of Account fields. If the mobile app only needs three of those thirty fields, it is still fetching all thirty (over-fetching). If it also needs the related Contacts, it makes a second API call (under-fetching, leading to the N+1 query problem).

GraphQL addresses this with a client-driven query model: the client specifies exactly which fields it needs, including related resources, and the server returns only those fields. A single GraphQL query can retrieve an Account with its primary Contact and open Opportunities — without the client knowing the server's object model in detail, and without making three separate REST API calls.

For the Salesforce use case, this is genuinely valuable for front-end applications (Lightning web components, mobile apps, external portals) that need to compose custom views of Salesforce data efficiently. The traditional alternative — a custom REST endpoint built in Apex that assembles the specific data shape needed by the UI — still works but requires Apex development for every new UI requirement. GraphQL shifts that composition responsibility to the query layer.

💡
GraphQL is not a replacement for SOQL: Salesforce GraphQL is a query protocol that translates to SOQL under the hood. It cannot perform everything SOQL can — aggregate functions, complex subqueries, and certain join patterns are not fully supported. GraphQL is an API protocol, not a query language with the expressiveness of SOQL.

Salesforce GraphQL API Architecture

The Salesforce GraphQL API is available at /services/data/v{version}/graphql. It uses the same OAuth 2.0 authentication as the REST API and respects the same object-level and field-level security (FLS) permissions. The GraphQL schema is auto-generated from the Salesforce org's metadata — every object and field accessible to the authenticated user is available in the GraphQL schema without any additional configuration.

Queries are the primary operation for reading data. A GraphQL query specifies the object type, the fields to retrieve, and optional filter and sort parameters. Mutations handle DML operations — creating, updating, and deleting records. Unlike REST where the operation type is conveyed by the HTTP method (GET, POST, PATCH, DELETE), GraphQL uses a single HTTP POST endpoint for all operations, with the operation type and parameters in the request body.

// Salesforce GraphQL query — Account with related Contacts
POST /services/data/v60.0/graphql
Content-Type: application/json
Authorization: Bearer {token}

{
  "query": "query GetAccountWithContacts($acctId: ID!) {
    uiapi {
      query {
        Account(where: { Id: { eq: $acctId } }) {
          edges {
            node {
              Id
              Name
              Industry
              AnnualRevenue { value }
              Contacts {
                edges {
                  node {
                    Id
                    FirstName
                    LastName
                    Email { value }
                    Title { value }
                  }
                }
              }
            }
          }
        }
      }
    }
  }",
  "variables": { "acctId": "001XXXXXXXXXXXX" }
}

The Problems It Solves vs The Problems It Creates

GraphQL solves the multi-object fetch problem elegantly. The query above retrieves an Account and all its Contacts in a single HTTP request — without a second API call for the Contacts related list. In REST, this would require a GET /accounts/{id} followed by a GET /accounts/{id}/contacts — two API calls, two network round trips, and the client assembling the response. GraphQL eliminates this overhead for UI-rendering scenarios.

GraphQL also solves the field selection problem for bandwidth-constrained clients (mobile apps on cellular, high-traffic APIs where payload size affects cost). A mobile app that only needs Account Name and Industry from an Account record can request exactly those two fields, receiving a response roughly 10x smaller than the full REST Account response. For an app making thousands of Account queries, this reduces bandwidth materially.

The problems GraphQL creates are query complexity management and the N+1 query problem in the server implementation. When a GraphQL query requests a list of 100 Accounts and for each Account requests its Contacts, the naive server implementation makes 100 separate database queries — one for each Account's Contacts. Salesforce's implementation uses DataLoader batching to mitigate this, but deep nested queries with large collections can still generate significant server-side processing. Query depth and complexity limits exist to prevent abuse.

Current Limitations of Salesforce GraphQL

Salesforce's GraphQL API, while growing, has significant limitations compared to the REST and SOQL API as of 2026. Aggregate queries (COUNT, SUM, AVG, GROUP BY) are not supported — reporting use cases requiring aggregations must use the SOQL-based REST API or Reports API. SOQL features like HAVING clauses, complex subqueries, and polymorphic fields are either not supported or have limited support in GraphQL.

Bulk operations — creating, updating, or deleting hundreds or thousands of records — are not appropriate for GraphQL. GraphQL mutations operate on individual records or small batches. High-volume DML operations must continue to use the Bulk API 2.0. GraphQL is optimised for the query-and-display use case, not the data processing use case.

Rate limits for GraphQL are shared with the REST API limits — each GraphQL request counts as one API call against the 24-hour limit. However, because a well-designed GraphQL query can replace multiple REST calls, the net API call consumption can be lower for GraphQL-native applications. The inverse risk: a poorly designed GraphQL query with deep nesting that generates many server-side sub-queries can have disproportionate impact on server load even with normal API call count.

⚠️
GraphQL introspection exposes the full schema: GraphQL's introspection capability allows clients to query the full schema of the API — every object, every field, every type. For internal applications, this is useful for development tooling. For externally-accessible Salesforce APIs (Experience Cloud sites, public APIs), introspection should be carefully considered — it reveals your full data model to any authenticated caller, which may expose more than intended.

When to Use Salesforce GraphQL

GraphQL is well-suited for Lightning web component data fetching where the component needs to retrieve composite data (parent + children + related) in a single network request. The @wire adapter for GraphQL in LWC allows declarative data fetching with the GraphQL query syntax, providing better field-level control than the equivalent @wire adapters for specific Salesforce APIs. For complex UI components that currently make multiple wire calls or use imperative Apex, GraphQL wire can reduce both Apex development and API call overhead.

External mobile applications built by front-end teams unfamiliar with SOQL benefit significantly from GraphQL — the query model is familiar to React Native and Flutter developers, and the type system auto-generated from Salesforce metadata provides developer-friendly schema documentation. The GraphQL schema serves as the contract between Salesforce and the mobile app without requiring the mobile team to understand Salesforce's object model deeply.

GraphQL is not appropriate as the primary API for integration middleware, ETL operations, bulk data export, or analytics queries requiring aggregation. These use cases should continue to use the REST API with SOQL queries or the Bulk API 2.0. The decision is clear: UI-facing, field-selective, relationship-traversing queries benefit from GraphQL. Data-volume, analytics, and automation use cases do not.

Key Takeaways

  • GraphQL solves over-fetching (receiving fields the client doesn't need) and under-fetching (needing multiple API calls for related data) by allowing clients to specify exactly what fields and related resources they need in a single query.
  • Salesforce GraphQL auto-generates its schema from the org's metadata and respects all existing FLS and object-level security — no additional configuration is required to start querying accessible objects.
  • A single GraphQL query can traverse parent-child relationships and retrieve nested data without multiple API round trips — the primary value for UI-rendering scenarios.
  • Aggregate queries (SUM, COUNT, GROUP BY), complex SOQL subqueries, and bulk DML operations are not supported by Salesforce GraphQL. These use cases must continue using the REST SOQL API or Bulk API.
  • GraphQL is best suited for Lightning web components with complex data requirements and external mobile/web applications built by front-end teams — not for integration middleware, ETL, or analytics workloads.
  • GraphQL introspection exposes the full object and field schema to authenticated callers — consider carefully before enabling on externally-accessible Salesforce APIs.

Test Your Understanding

1. A React Native mobile app displays a sales rep's Account list with the rep's name, Account Name, last activity date, and count of open Opportunities. The current implementation makes three REST API calls per Account to assemble this view. What does GraphQL provide here?

Nothing material — three REST API calls is an acceptable number for a mobile application with modern network speeds
GraphQL allows the mobile app to request Account Name, last activity date, and the Opportunity count in a single query — eliminating the three-call pattern and reducing payload size to only the fields the app needs, which is valuable for cellular bandwidth and API limit efficiency
GraphQL eliminates authentication overhead — the mobile app no longer needs OAuth tokens to access the Salesforce GraphQL endpoint

2. A data analyst wants to use the Salesforce GraphQL API to generate a report showing total Opportunity value by Account industry, grouped by fiscal quarter. Is GraphQL appropriate for this use case?

Yes — GraphQL can handle aggregate queries including GROUP BY and SUM as part of its query DSL
No — GraphQL does not support aggregate functions (SUM, GROUP BY). This analytical query should use the SOQL REST API: SELECT Industry, SUM(Amount), CALENDAR_QUARTER(CloseDate) FROM Opportunity GROUP BY Industry, CALENDAR_QUARTER(CloseDate)
Yes, but only if the analyst uses the @aggregate directive available in Salesforce GraphQL v60.0 and later

3. A GraphQL query requests 500 Accounts, and for each Account requests all related Contacts. If each Account has an average of 8 Contacts, how many database-level sub-queries does a naive GraphQL server implementation execute for this request?

2 — one query for the 500 Accounts and one query for all related Contacts
4,000 — one query per Contact record (500 × 8)
501 — one query for the 500 Accounts, then one Contact query per Account (500 additional queries). This N+1 problem is why Salesforce's implementation uses DataLoader batching to combine Contact queries — but deep nesting with large collections still generates significant server load

Discussion & Feedback