GraphQL Query Parameters

The GraphQL query() method in the Data SDK includes several parameters.

1import { createDataSDK, gql } from "@salesforce/platform-sdk/data";
2
3const dataSdk = await createDataSDK();
4
5const result = await dataSdk.graphql?.query<ResponseType, VariablesType>({
6    query: QUERY_STRING,
7    variables: { ... },
8    operationName?: "...",
9    cacheControl?: "no-cache" | "only-if-cached" | { type: "max-age", maxAge: 60 }
10  });
11const QUERY_STRING = gql`
12 query MyQuery {
13   uiapi {
14     ...
15   }
16 }
17`;

graphql.query<T, V = Record<string, unknown>>(options: QueryOptions<V>) 

Runs a GraphQL query with reactive capabilities.

Parameters 

ParameterTypeDescription
querystringThe GraphQL query operation string, which accepts an inline gql template tag or an external .graphql file.
variables?V, defaults to Record<string, unknown>Optional key-value map of GraphQL variables referenced by the query.
operationName?stringOptional operation name for multi-operation documents.
cacheControl?CacheControlOptional cache control settings for the GraphQL request.

UI API Query Structure 

All GraphQL queries follow this UI API structure.

1query {
2  uiapi {
3    query {
4      <ObjectName>(
5        first: Int           # pagination limit
6        after: String        # pagination cursor
7        where: <Object>_Filter
8        orderBy: <Object>_OrderBy
9      ) {
10        edges {
11          node {
12            Id
13            <FieldName> { value }
14          }
15        }
16      }
17    }
18  }
19}

For more information, see Query Objects in the GraphQL API Developer Guide.

Returns 

The return type of dataSdk.graphql?.query(), which resolves to the typed GraphQL response payload.

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

GraphQL record queries return this response structure.

1interface UIAPIQueryResponse {
2  uiapi: {
3    query: {
4      [ObjectName: string]: {
5        edges?: Array<{
6          node?: {
7            Id: string;
8            // Every field is a { value, displayValue } envelope, not a bare scalar.
9            // - value: raw value — use for logic and for writing back to the server
10            // - displayValue: locale-formatted string — use for rendering in the UI
11            [FieldName: string]?: { value?: FieldType | null; displayValue?: string | null } | null;
12          } | null;
13        } | null> | null;
14      } | null;
15    };
16  };
17}
18          } | null;
19        } | null> | null;
20      } | null;
21    };
22  };
23}

Subscribe to Query Updates 

Query results from graphql.query() are reactive and support real-time updates through subscriptions, which you can use to update your UI automatically when data changes.

The subscribe() method listens for updates to a query result. Subscribers are notified when the data changes due to cache updates or explicit refreshes.

1const result = await dataSdk.graphql?.query<AccountData>({
2  query: GET_ACCOUNT,
3  variables: { id: accountId },
4});
5
6// Subscribe to updates
7const unsubscribe = result.subscribe((snapshot) => {
8  console.log("Updated data:", snapshot.data);
9  if (snapshot.errors) {
10    console.warn("Errors:", snapshot.errors);
11  }
12  // Update your UI here
13});
14
15// Clean up when done
16unsubscribe();

Refresh Query Data 

Use the refresh() method to manually re-fetch data, bypassing the cache.

1const result = await dataSdk.graphql?.query<AccountData>({
2  query: GET_ACCOUNT,
3  variables: { id: accountId },
4});
5
6// Subscribe to updates
7result.subscribe((snapshot) => {
8  // UI update logic
9  setAccount(snapshot.data);
10});
11
12// Later, refresh the data (e.g., on button click)
13async function handleRefresh() {
14  await result.refresh(); // Notify subscribers
15}

Example: Query Records from a React App 

Here’s an example on how to query records. The example uses the useState and useEffect React hooks to manage the component state and respond to data changes.

List of records
1/**
2 * List Rendering with Salesforce Records
3 *
4 * Fetches Accounts via UIAPI GraphQL and renders them using .map().
5 * Each item needs a stable key prop; here we use the record Id.
6 *
7 * LWC equivalent: list rendering uses for:each / lwc:for directives on
8 * template elements with a key attribute. React uses .map() in JSX with
9 * a key prop.
10 *
11 * @see ParentToChild — passing data from parent to child components via props
12 */
13import { useEffect, useState } from 'react';
14import { createDataSDK, gql } from '@salesforce/platform-sdk';
15
16const QUERY = gql`
17  query AccountList {
18    uiapi {
19      query {
20        Account(first: 6, orderBy: { Name: { order: ASC } }) {
21          edges {
22            node {
23              Id
24              Name @optional {
25                value
26              }
27              Industry @optional {
28                value
29              }
30            }
31          }
32        }
33      }
34    }
35  }
36`;
37
38interface QueryResponse {
39  uiapi: {
40    query: {
41      Account: {
42        edges: Array<{
43          node: {
44            Id: string;
45            Name: { value: string | null };
46            Industry: { value: string | null };
47          };
48        }>;
49      };
50    };
51  };
52}
53
54interface AccountFields {
55  id: string;
56  name: string;
57  industry: string | null;
58}
59
60export default function ListOfAccounts() {
61  const [accounts, setAccounts] = useState<AccountFields[]>();
62  const [error, setError] = useState<string>();
63
64  useEffect(() => {
65    const fetchAccounts = async () => {
66      const sdk = await createDataSDK();
67      const result = await sdk.graphql?.query<QueryResponse>({ query: QUERY });
68
69      if (result?.errors?.length) {
70        throw new Error(
71          result.errors.map((e: { message: string }) => e.message).join('; ')
72        );
73      }
74
75      const edges = result?.data?.uiapi?.query?.Account?.edges ?? [];
76      setAccounts(
77        edges
78          .map(edge => edge?.node)
79          .filter(Boolean)
80          .map(node => ({
81            id: node.Id,
82            name: node.Name?.value ?? 'Unknown',
83            industry: node.Industry?.value ?? null,
84          }))
85      );
86    };
87
88    fetchAccounts().catch(err => {
89      setError(err instanceof Error ? err.message : 'Request failed');
90    });
91  }, []);
92
93  if (error) return <p className="text-destructive">{error}</p>;
94  if (!accounts) return <p className="text-sm">Loading…</p>;
95
96  return (
97    <ul>
98      {/* .map() replaces LWC's for:each directive. The key must be stable — record Id is ideal. */}
99      {accounts.map(account => (
100        <li
101          key={account.id}
102          className="py-2 -mx-2 px-2 rounded-md transition-colors hover:bg-accent/50"
103        >
104          <p className="text-sm">{account.name}</p>
105          {account.industry && (
106            <p className="text-xs text-muted-foreground">{account.industry}</p>
107          )}
108        </li>
109      ))}
110    </ul>
111  );
112}

For more examples, see the Multi-framework recipes repo.

Tip

Example: Successful GraphQL Query Response 

A successful query response includes record data in the node object.

1{
2  "data": {
3    "uiapi": {
4      "query": {
5        "Account": {
6          "edges": [
7            {
8              "node": {
9                "Id": "001xx000003DHP0AAO",
10                "Name": { "value": "Acme Corp" },
11                "Industry": { "value": "Technology" }
12              }
13            }
14          ],
15          "pageInfo": {
16            "hasNextPage": false,
17            "endCursor": null
18          }
19        }
20      }
21    }
22  }
23}

Example: Partial Success Response 

A partially successful query response includes errors and some data.

1{
2  "data": {
3    "uiapi": {
4      "query": {
5        "Account": {
6          "edges": [
7            {
8              "node": {
9                "Id": "001xx000003DHP0AAO",
10                "Name": { "value": "Acme Corp" }
11              }
12            }
13          ]
14        }
15      }
16    }
17  },
18  "errors": [
19    {
20      "message": "Insufficient access on field AnnualRevenue",
21      "path": ["uiapi", "query", "Account", "edges", 0, "node", "AnnualRevenue"]
22    }
23  ]
24}

See Also