Skip to content
AI & Agents
Skill

/experience-ui-bundle-salesforce-data-access

MUST activate when a uiBundles/*/src/ project does ANY Salesforce record operation — reading, creating, updating, deleting, or caching/refreshing query results. Triggers: code importing @salesforce/platform-sdk, calls to sdk.graphql.query / sdk.graphql.mutate / sdk.fetch,

From plugin
sf-skills
803161 skills6 agents10 commands3 MCP
Install
$ npx -y skills add forcedotcom/afv-library --skill experience-ui-bundle-salesforce-data-access --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/experience-ui-bundle-salesforce-data-access

Context preview

The summary Claude sees to decide when to auto-load this skill.

MUST activate when a uiBundles/*/src/ project does ANY Salesforce record operation — reading, creating, updating, deleting, or caching/refreshing query results. Triggers: code importing @salesforce/platform-sdk, calls to sdk.graphql.query / sdk.graphql.mutate / sdk.fetch,

SKILL.md

experience-ui-bundle-salesforce-data-access.SKILL.md
name: experience-ui-bundle-salesforce-data-access
description: "MUST activate whenever a uiBundles/*/src/ project reads, writes, or displays Salesforce data — INCLUDING building a page, list, table, card grid, dashboard, or form that shows, filters, counts, or edits records of any object (e.g. Property__c, Account, Case), even when the prompt names only the UI or the object and never says query, GraphQL, or SDK. Records behind such a component come from Salesforce, so use this ALONGSIDE experience-ui-bundle-frontend-generate: that skill styles the component, this one wires its data. Also triggers on @salesforce/platform-sdk imports, sdk.graphql.query / mutate / sdk.fetch calls, *.graphql files, or stale data needing force-refresh. New read/write work uses the current @salesforce/platform-sdk API; migrate only EXISTING old @salesforce/sdk-data callable code. Not for pure styling/layout with no records, app shell, file upload, or auth/search scaffolding. DO NOT TRIGGER for OAuth, object/field schema changes, Bulk/Tooling/Metadata API, or declarative automation."
metadata:
  version: "2.2"
  minApiVersion: "66.0"
  relatedSkills:
    - "experience-ui-bundle-frontend-generate"
    - "platform-metadata-deploy"
  cliTools:
    - tool: ["node"]
      semver: ">=18.0.0"
    - tool: ["npm"]
      semver: ">=9.0.0"
    - tool: ["npx"]
      semver: ">=9.0.0"
    - tool: ["sf"]
      semver: ">=2.0.0"

Salesforce Data Access (UI bundles)

All Salesforce data access in a UI bundle goes through the **`@salesforce/platform-sdk`** data SDK. The SDK handles auth, CSRF, and base-URL resolution, and — on the WebApp surface — caches every GraphQL query by default.

This file is the **workflow + guardrail spine**. Depth lives in linked docs:

  • **[references/graphiti-cli.md](references/graphiti-cli.md)** — the **`graphiti` CLI** (`sf-gql-*`

commands) that compiles a small JSON spec into a schema-correct, guardrail-applied query + variables + types. The preferred way to author the GraphQL in steps below; falls back to the schema-grep script when unavailable.

  • **[references/sdk-api.md](references/sdk-api.md)** — the new call API: `query`/`mutate`,

`QueryResult`, typing, error-handling stances.

  • **[references/caching.md](references/caching.md)** — on-by-default cache + the **two refresh

modes** (`result.refresh`/`subscribe` vs per-call `cacheControl`).

  • **[references/graphql-hand-authoring.md](references/graphql-hand-authoring.md)** — schema lookup, read /

mutation templates, every platform guardrail (`@optional`, pagination, limits, semi-join, wrappers, error table…).

  • **[references/rest-and-integration.md](references/rest-and-integration.md)** — `sdk.fetch`,

the supported-API allowlist, and the reactive/lifecycle integration patterns.

  • **[references/migration.md](references/migration.md)** — old `@salesforce/sdk-data` callable code

→ new namespace. The **only** place the dead API appears as usable code.

The one-paragraph mental model

`const sdk = await createDataSDK()`. Then `sdk.graphql` is a **namespace**, not a function: **`sdk.graphql!.query({...})`** for reads, **`sdk.graphql!.mutate({...})`** for writes. On WebApp, **every `query()` is cached by default** (300s). HTTP 200 never means success — always check `result.errors`. Verify every entity and field against the schema before you query it: one unverified field fails the *whole* query at runtime, and `schema.graphql` is too large to eyeball — look it up.

import { createDataSDK, gql } from "@salesforce/platform-sdk"; // gql tags the query string so codegen + eslint validate it

const sdk = await createDataSDK();
const result = await sdk.graphql!.query({ query: GET_ACCOUNTS, variables });
if (result.errors?.length) throw new Error(result.errors.map((e) => e.message).join("; "));
const rows = result.data?.uiapi?.query?.Account?.edges?.map((e) => e.node) ?? []; // unwrap edges/node; read field values via .value

Typed call params (`query<GetAccountsQuery, GetAccountsQueryVariables>`), the `CacheControl` type, and `NodeOfConnection<T>` (extracts a node type from a Connection for clean typing) all live in [references/sdk-api.md](references/sdk-api.md).

> **This changed (breaking — PR #502).** The previous callable `sdk.graphql(...)` form and the > previous package name are **dead** — the code above is the only correct form. If you encounter > the old API in existing code (or a stale `dist/` artifact), don't copy it; convert it per > [Working on existing code](#working-on-existing-code-migration). > > **`sdk.graphql!` is WebApp-only.** The non-null assertion above is correct *only* if the > bundle runs solely on WebApp. On other surfaces it can crash — decide before you write it. > See **[Surfaces — `!` vs guard](#surfaces--sdkgraphql-vs-guard)** below.

---

Ground the SDK contract on the installed types (tier-2a)

`@salesforce/platform-sdk` force-publishes on a shared version line and moves fast. This SKILL's prose is a point-in-time snapshot of the call contract; the **installed declarations are authoritative for the version you actually have**. Before writing any `query`/`mutate`, read the installed types and let them win:

  • `node_modules/@salesforce/platform-sdk/dist/core/data.d.ts` — `query`/`mutate`

signatures, `QueryResult` (has `subscribe`/`refresh`) vs `MutationResult` (has neither, by design), the `CacheControl` union, the default TTL.

  • `node_modules/@salesforce/platform-sdk/dist/data/index.d.ts` — `createDataSDK`,

`gql`, `NodeOfConnection`.

**Precedence — installed `.d.ts` beats this SKILL's prose.** If a signature, type, or default here disagrees with the installed declaration, follow the declaration and note the drift; do not "correct" the types to match the prose.

**Grounding ladder** (one model, two axes):

| Tier | Grounds | Answers | Via | |---|---|---|---| | tier-1 | GraphQL **schema** | *what data exists* | graphiti / `graphql-search.sh` (Precondition #2) | | tier-2a |

Read more
Ships withsf-skills

This repository provides a curated collection of Salesforce agent skills for building applications.

Get the whole plugin

Other skills on sf-skills.