Work with Data SDK

The Data SDK handles authentication, CSRF tokens, and base path resolution internally. To work with Data SDK, import the functions from @salesforce/platform-sdk/data.

1import { createDataSDK, gql } from "@salesforce/platform-sdk/data";
2import type { DataSDK, SDKOptions, NodeOfConnection } from "@salesforce/platform-sdk/data";
3const dataSdk = await createDataSDK();

With the Data SDK, you can query and update Salesforce records extensively from your web app by using simple bindings for running GraphQL queries and mutations.

ExportTypeDescription
createDataSDKasync functionFactory that creates a new DataSDK instance
gqltemplate tagIdentity template literal for inline GraphQL queries, which also enables editor syntax highlighting and codegen detection
DataSDKinterfaceThe SDK surface type with graphql and fetch methods
SDKOptionsinterfaceBase options type with optional surface override
NodeOfConnection<T>utility typeExtracts the node type from a GraphQL connection with edges and node response

createDataSDK(options?) 

Creates a new DataSDK instance.

1async function createDataSDK(options?: DataSDKOptions): Promise<DataSDK>;

Parameters 

  • options: DataSDKOptions-Optional configuration for createDataSDK

DataSDKOptions

  • surface: string-For automatic surface detection
  • webapp: WebAppDataSDKOptions-Options specific to the web app surface

WebAppDataSDKOptions

  • basePath: string-Base URL prefix for Salesforce API calls
  • on401: () => Promise<unknown> | void-Optional callback
  • on403: () => Promise<unknown> | void-Optional callback

Returns 

1Promise<DataSDK>

The return type for createDataSDK(options?), which resolves to a promise with the DataSDK object.

The GraphQL cache is shared across all DataSDK instances that use the same base URL, which improves performance and consistency when multiple components query the same data. Multiple calls to createDataSDK() share the same GraphQL cache. Cache updates from one SDK instance are visible to all other instances with the same base URL.

1// Both instances share the same GraphQL cache
2const sdk1 = await createDataSDK();
3const sdk2 = await createDataSDK();
4
5// Query from sdk1 populates the cache
6await sdk1.graphql?.query<AccountData>({ query: GET_ACCOUNTS });
7
8// Query from sdk2 can read from the same cache (cache hit)
9await sdk2.graphql?.query<AccountData>({ query: GET_ACCOUNTS });

gql Template Tag 

The gql tag is a template literal for inline GraphQL query definitions. When GraphQL queries are defined with TypeScript code, the Data SDK requires the use of gql to understand and apply special processing to your GraphQL queries at different stages of the component lifecycle. The use of the gql tag enables org-aware GraphQL syntax highlighting when using Agentforce Vibes.

1import { createDataSDK, gql } from "@salesforce/platform-sdk/data";
2
3const MY_QUERY = gql`
4  query MyQuery {
5    uiapi {
6      ...
7    }
8  }
9`;

See GraphQL Queries in Data SDK.

DataSDK Interface 

Defines the top-level SDK surface that exposes optional GraphQL and fetch APIs. Both graphql and fetch methods are optional as they’re supported in specific environments only.

1interface DataSDK {
2  graphql?: DataSDKGraphQL;
3  fetch?: typeof fetch;
4}

graphql() 

GraphQL is the preferred way to work with record data.

1import { createDataSDK } from "@salesforce/platform-sdk/data";
2const dataSdk = await createDataSDK();
3// GraphQL — use optional chaining
4const result = await dataSdk.graphql?.query<MyQueryType>({
5  query,
6  variables,
7});

To account for the lack of availability of GraphQL in some environments, use optional chaining (graphql?). See GraphQL Queries in Data SDK.

fetch() 

Use dataSdk.fetch?.() for Salesforce REST endpoints that aren’t covered by GraphQL. Use optional chaining to account for environments that don’t support fetch().

1import { createDataSDK } from "@salesforce/platform-sdk/data";
2const dataSdk = await createDataSDK();
3// Prefer GraphQL for record/user data:
4const me = await dataSdk.graphql?.query({
5  query: gql`
6    query {
7      uiapi {
8        currentUser {
9          Id
10          Name {
11            value
12          }
13        }
14      }
15    }
16  `,
17});
18
19// Use fetch only for REST endpoints GraphQL doesn't cover.
20// Replace {version} with the API version you want to use, for example `67.0`.
21
22// Example: UI API
23const result2 = await dataSdk.fetch?.("/services/data/v{version}/ui-api/records/{recordId}");
24const userData = await result2?.json();

The fetch wrapper handles:

  • CSRF token management
  • Base path resolution
  • 401/403 callback hooks

Consider using the dataSdk.fetch() call for:

  • Apex REST endpoints (e.g. /services/apexrest/auth/…)
  • Salesforce REST endpoints (e.g. /services/data/v{version}/…)

DataSDKGraphQL Interface 

Defines the GraphQL methods available on the Data SDK, including queries and mutations.

1interface DataSDKGraphQL {
2  /**
3   * Runs a GraphQL query.
4   *
5   * Resolves with { data, errors, subscribe, refresh } once the underlying
6   * request settles — either from the cache (cached surfaces only) or from
7   * the network. subscribe() streams subsequent snapshots; refresh() re-issues
8   * the request, bypassing the cache where one exists and propagating the
9   * result to subscribers.
10   */
11  query<T, V = Record<string, unknown>>(options: QueryOptions<V>): Promise<QueryResult<T>>;
12
13  /**
14   * Runs a GraphQL mutation. Pass-through to the underlying transport — does
15   * not read or write the cache. Queries and subscriptions passed here are
16   * rejected via the resolved errors field.
17   */
18  mutate<T, V = Record<string, unknown>>(options: MutateOptions<V>): Promise<MutationResult<T>>;
19}

QueryOptions Interface 

Describes the options for graphql.query(). See GraphQL Query Parameters.

1interface QueryOptions<V = Record<string, unknown>> {
2  query: string;
3  variables?: V;
4  operationName?: string;
5  cacheControl?: CacheControl;
6}

MutateOptions Interface 

Describes the options for graphql.mutate(). See GraphQL Mutate Parameters.

1interface MutateOptions<V = Record<string, unknown>> {
2  mutation: string;
3  variables?: V;
4  operationName?: string;
5}

QueryResult<T> Interface 

Describes the reactive query result that’s returned by graphql.query().

1interface QueryResult<T> {
2  data: T | undefined;
3  errors?: GraphQLError[];
4  subscribe(cb: (snapshot: QuerySnapshot<T>) => void): Unsubscribe;
5  refresh(): Promise<void>;
6}

MutationResult<T> Interface 

Describes the one-shot result returned by graphql.mutate().

1interface MutationResult<T> {
2  data: T | undefined;
3  errors?: GraphQLError[];
4}

QuerySnapshot<T> Interface 

Describes the snapshot object passed to subscribe() callbacks.

1interface QuerySnapshot<T> {
2  data: T | undefined;
3  errors?: GraphQLError[];
4}

GraphQLError Interface 

Defines the shape of GraphQL error objects returned by the Data SDK. See Error Handling in Data SDK.

1interface GraphQLError {
2  message: string;
3  locations?: { line: number, column: number }[];
4  path?: string[];
5}

CacheControl 

Describes supported cache control values for graphql.query(). See Cache Control in Data SDK.

1type Unsubscribe = () => void;
2
3type CacheControl = "no-cache" | "only-if-cached" | { type: "max-age", maxAge: number };

Salesforce API Calls 

These API endpoints are supported.

  • /services/apexrest
  • /services/data/v{version}/ui-api/records
  • /services/data/v{version}/ui-api/search-info
  • /services/data/v{version}/ui-api/layout
  • /services/data/v{version}/ui-api/session/csrf
  • /services/data/v{version}/connect/file/upload/config
  • /services/data/v{version}/connect/proxy/ui-telemetry
  • /services/data/v{version}/chatter/users/me
  • /services/data/v{version}/chatter/users/{userId}
  • /sfsites/c/_nc_external/system/security/session/SessionTimeServlet
  • /secur/logout.jsp

We recommend that you use optional chaining fetch?.() instead of a non-null assertion fetch!.(). Optional chaining is useful when you want to use fetch in a shared or cross-surface utility. If you’re not sure where your code is run, use optional chaining and handle the response appropriately.

The read-data examples in the Multi-framework recipes repo demonstrate how to call Chatter Connect API, Apex REST, and UI API REST.

Tip

NodeOfConnection<T> 

Extracts the node type from a UIAPI connection response shape with the edges and node pattern.

1import { type NodeOfConnection } from "@salesforce/platform-sdk/data";
2// Extract Account node type from the query response
3type AccountNode = NodeOfConnection<GetHighRevenueAccountsQuery["uiapi"]["query"]["Account"]>;

Use NodeOfConnection when your GraphQL response uses the Salesforce connection shape (edges and node) and you want a clean, strongly-typed node type. For example:

  • Query returns: Account { edges { node { ... } } }
  • You define: type AccountNode = NodeOfConnection<MyQuery["uiapi"]["query"]["Account"]>
  • Use AccountNode for transforms, props, and list rendering

If your query doesn’t use connection fields or you already have simple flat generated types, you don’t need to use NodeOfConnection.

Data SDK Considerations 

When using the Data SDK to access Salesforce data use standard web APIs and npm packages only. These functionalities aren’t supported:

  • @salesforce scoped modules, except @salesforce/platform-sdk/data
  • Lightning base components and lightning/* modules
  • @wire service

Coming from LWC, here’s what to use instead in React.

Don’t use (LWC-only)Use instead in React
@salesforce/apex/Class.methoddataSdk.fetch?.() against /services/apexrest/...
@salesforce/schema/Object.FieldHardcode the API name as a string in your GraphQL query
@salesforce/user/Id, /CurrentUserIdGraphQL uiapi.currentUser query via dataSdk.graphql?.query(...)
lightning/uiRecordApi: get* calls such as getRecord and getListUidataSdk.graphql?.query(...)
lightning/uiRecordApi: mutation calls such as createRecord, updateRecord, and deleteRecorddataSdk.graphql?.mutate(...)
@wire decoratorReact useEffect hook and dataSdk.graphql?.query(...); QueryResult.subscribe for reactive updates

Use @salesforce/platform-sdk/data for all Salesforce API calls. The SDK handles authentication and CSRF validation. Follow these data access guidelines in order of preference.

  • Use GraphQL queries and mutations as the preferred way to access data. dataSdk.graphql?.query() and dataSdk.graphql?.mutate() send a POST request to Salesforce GraphQL.
  • Use UI API via sdk.fetch?.() for data access that calls /services/data/v{version}/ui-api/* or another Salesforce REST endpoint, such as an Apex controller that’s exposed via Apex REST.
  • Use GraphQL with sdk.fetch?.() if GET request is required, such as when your query and variables are small enough to fit in URL constraints. Or use a GraphQL GET request if you have a dependency on a roundtrip fetch of a CSRF token.
  • Use Apex REST when you want custom logic that GraphQL doesn’t support.
  • Don’t call fetch() or axios directly for Salesforce endpoints.

Data SDK Examples 

Review the examples in the React App Recipes GitHub repo. Install the app in a scratch org and explore each recipe to understand how to complete a specific task, whether it’s querying data with GraphQL or handling loading, an empty state, or error responses.