---
schema_version: "1"
id: 3ccd04476f89f15c48080ef6347db2c7e3e9aeb26c6f12f345841fea3421bf46
title: Work with Data SDK (Beta)
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/salesforcedx/einsteinfordevs/guides/files/reactdev-data-sdk-intro.md
canonical_url: https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/reactdev-data-sdk-intro.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: dd3f84d6d8db2925b20efb4c2fea324202aff215611557be9389945dc2bcb2be
products:
  - Agentforce Vibes Developer Guide (Deprecated)
  - salesforcedx
---
# Work with Data SDK (Beta)

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`.

```javascript
import { createDataSDK, gql } from "@salesforce/platform-sdk/data";
import type { DataSDK, SDKOptions, NodeOfConnection } from "@salesforce/platform-sdk/data";
const 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.

| Export                | Type             | Description                                                                                                               |
| :-------------------- | :--------------- | :------------------------------------------------------------------------------------------------------------------------ |
| `createDataSDK`       | `async function` | Factory that creates a new DataSDK instance                                                                               |
| `gql`                 | template tag     | Identity template literal for inline GraphQL queries, which also enables editor syntax highlighting and codegen detection |
| `DataSDK`             | `interface`      | The SDK surface type with `graphql` and `fetch` methods                                                                   |
| `SDKOptions`          | `interface`      | Base options type with optional surface override                                                                          |
| `NodeOfConnection<T>` | utility type     | Extracts the node type from a GraphQL connection with edges and node response                                             |

## createDataSDK(options?)

Creates a new DataSDK instance.

```typescript
async function createDataSDK(options?: DataSDKOptions): Promise<DataSDK>;
```

### Parameters

- `options`: `DataSDKOptions`-Optional configuration for `createDataSDK`

**DataSDKOptions**

- `surface`: `string`-For automatic surface detection
- `webapp`: WebApp`DataSDKOptions`-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

```typescript
Promise<DataSDK>
```

The return type for `createDataSDK(options?)`, which resolves to a promise with the `DataSDK` object.

The [GraphQL cache](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/reactdev-data-sdk-cache-control.md) 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.

<!-- prettier-ignore -->
```javascript
// Both instances share the same GraphQL cache
const sdk1 = await createDataSDK();
const sdk2 = await createDataSDK();

// Query from sdk1 populates the cache
await sdk1.graphql?.query<AccountData>({ query: GET_ACCOUNTS });

// Query from sdk2 can read from the same cache (cache hit)
await 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.

```javascript
import { createDataSDK, gql } from "@salesforce/platform-sdk/data";

const MY_QUERY = gql`
  query MyQuery {
    uiapi {
      ...
    }
  }
`;
```

See [GraphQL Queries in Data SDK](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/reactdev-data-sdk-graphql.md).

## 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.

```javascript
interface DataSDK {
  graphql?: DataSDKGraphQL;
  fetch?: typeof fetch;
}
```

### graphql()

GraphQL is the preferred way to work with record data.

<!-- prettier-ignore -->
```javascript
import { createDataSDK } from "@salesforce/platform-sdk/data";
const dataSdk = await createDataSDK();
// GraphQL — use optional chaining
const result = await dataSdk.graphql?.query<MyQueryType>({
  query,
  variables,
});
```

To account for the lack of availability of GraphQL in some environments, use optional chaining (`graphql?`). See [GraphQL Queries in Data SDK](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/reactdev-data-sdk-graphql.md).

### 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()`.

```javascript
import { createDataSDK } from "@salesforce/platform-sdk/data";
const dataSdk = await createDataSDK();
// Prefer GraphQL for record/user data:
const me = await dataSdk.graphql?.query({
  query: gql`
    query {
      uiapi {
        currentUser {
          Id
          Name {
            value
          }
        }
      }
    }
  `,
});

// Use fetch only for REST endpoints GraphQL doesn't cover.
// Replace {version} with the API version you want to use, for example `67.0`.

// Example: UI API
const result2 = await dataSdk.fetch?.("/services/data/v{version}/ui-api/records/{recordId}");
const 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.

```javascript
interface DataSDKGraphQL {
  /**
   * Runs a GraphQL query.
   *
   * Resolves with { data, errors, subscribe, refresh } once the underlying
   * request settles — either from the cache (cached surfaces only) or from
   * the network. subscribe() streams subsequent snapshots; refresh() re-issues
   * the request, bypassing the cache where one exists and propagating the
   * result to subscribers.
   */
  query<T, V = Record<string, unknown>>(options: QueryOptions<V>): Promise<QueryResult<T>>;

  /**
   * Runs a GraphQL mutation. Pass-through to the underlying transport — does
   * not read or write the cache. Queries and subscriptions passed here are
   * rejected via the resolved errors field.
   */
  mutate<T, V = Record<string, unknown>>(options: MutateOptions<V>): Promise<MutationResult<T>>;
}
```

## QueryOptions Interface

Describes the options for `graphql.query()`. See [GraphQL Query Parameters](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/reactdev-data-sdk-query.md).

```javascript
interface QueryOptions<V = Record<string, unknown>> {
  query: string;
  variables?: V;
  operationName?: string;
  cacheControl?: CacheControl;
}
```

## MutateOptions Interface

Describes the options for `graphql.mutate()`. See [GraphQL Mutate Parameters](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/reactdev-data-sdk-mutate.md).

```javascript
interface MutateOptions<V = Record<string, unknown>> {
  mutation: string;
  variables?: V;
  operationName?: string;
}
```

## QueryResult<T> Interface

Describes the reactive query result that's returned by `graphql.query()`.

```javascript
interface QueryResult<T> {
  data: T | undefined;
  errors?: GraphQLError[];
  subscribe(cb: (snapshot: QuerySnapshot<T>) => void): Unsubscribe;
  refresh(): Promise<void>;
}
```

## MutationResult<T> Interface

Describes the one-shot result returned by `graphql.mutate()`.

```javascript
interface MutationResult<T> {
  data: T | undefined;
  errors?: GraphQLError[];
}
```

## QuerySnapshot<T> Interface

Describes the snapshot object passed to `subscribe()` callbacks.

```javascript
interface QuerySnapshot<T> {
  data: T | undefined;
  errors?: GraphQLError[];
}
```

## GraphQLError Interface

Defines the shape of GraphQL error objects returned by the Data SDK. See [Error Handling in Data SDK](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/reactdev-data-sdk-graphql-error.md).

```javascript
interface GraphQLError {
  message: string;
  locations?: { line: number, column: number }[];
  path?: string[];
}
```

## CacheControl

Describes supported cache control values for `graphql.query()`. See [Cache Control in Data SDK](https://developer.salesforce.com/docs/platform/einstein-for-devs/guide/reactdev-data-sdk-cache-control.md).

```javascript
type Unsubscribe = () => void;

type 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.

**tip:** The read-data examples in the [Multi-framework recipes repo](https://github.com/trailheadapps/multiframework-recipes) demonstrate how to call Chatter Connect API, Apex REST, and UI API REST.

## `NodeOfConnection<T>`

Extracts the node type from a UIAPI connection response shape with the edges and node pattern.

```typescript
import { type NodeOfConnection } from "@salesforce/platform-sdk/data";
// Extract Account node type from the query response
type 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.method`                                                                    | `dataSdk.fetch?.()` against `/services/apexrest/...`                                                   |
| `@salesforce/schema/Object.Field`                                                                  | Hardcode the API name as a string in your GraphQL query                                                |
| `@salesforce/user/Id`, `/CurrentUserId`                                                            | GraphQL `uiapi.currentUser` query via `dataSdk.graphql?.query(...)`                                    |
| `lightning/uiRecordApi`: `get*` calls such as `getRecord` and `getListUi`                          | `dataSdk.graphql?.query(...)`                                                                          |
| `lightning/uiRecordApi`: mutation calls such as `createRecord`, `updateRecord`, and `deleteRecord` | `dataSdk.graphql?.mutate(...)`                                                                         |
| `@wire` decorator                                                                                  | React `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](https://github.com/trailheadapps/multiframework-recipes). 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.
