Skip to main content

Command Palette

Search for a command to run...

React Inside Salesforce: A Strategic Look at the New Multi-Framework SDK (Open Beta)

I built a Sales Pipeline Intelligence Dashboard using React 19, GraphQL, and the new Multi-Framework SDK inside a Salesforce scratch org โ€” here's everything I learned.

Updated
โ€ข11 min read
React Inside Salesforce: A Strategic Look at the New Multi-Framework SDK (Open Beta)
H
Software engineer by day. Bob the Builder by night ๐Ÿ˜‰ Always learning, always shipping, always tweaking one more time. The goal: stay curious, keep pushing the limits, and write about what I find on the way; what I learn, what I break, and what I'd build differently next time.

I built a Sales Pipeline Intelligence Dashboard using React 19, GraphQL, and the new Multi-Framework SDK inside a Salesforce scratch org โ€” here's everything I learned.

By Sumanth Shyam Hegde ยท Software Engineer @ ABSYZ


๐Ÿ“Œ TL;DR

Salesforce just shipped something the developer community has been asking for years โ€” native React support on the platform. No static resource hacks. No LWC wrappers. Real React, running inside Salesforce with auth, FLS, and governance built in.

I built a Sales Pipeline Intelligence Dashboard as a POC to pressure-test this. Here's what actually works, what doesn't, and whether it's worth your time right now.

๐Ÿ”— Repo: github.com/hegdesumanth/sf-multiframework-react-graphql ๐Ÿ“ฃ Official announcement: Build with React, Run on Salesforce


The Problem Worth Solving

If you've built on Salesforce long enough, you know the trade-off. You get base components, Lightning Data Service, and a declarative composition model โ€” but you give up the broader frontend ecosystem. Want to use a charting library? Static resource. Want npm packages? Manual loader scripts. Want React? Good luck.

Multi-Framework changes that math.

It's a framework-agnostic runtime on the Agentforce 360 Platform that lets React apps run natively while still respecting FLS, CRUD, and sharing rules. React is supported today; Vue and others are on the roadmap.

Two related shifts are worth knowing about:

What Why it matters
@salesforce/sdk-data New SDK for GraphQL, Apex, and UI API access built for React
lightning/graphql (Winter '26) Supersedes lightning/uiGraphQLApi in LWC โ€” adds optional fields and dynamic queries

Salesforce isn't just bolting on React support. They're modernising data access across the board.


What I Built: Sales Pipeline Intelligence Dashboard

The POC surfaces five sections: KPI cards, a stage funnel, a dynamic query toggle, an opportunity table, and an optional-fields demo panel. Each one was chosen to highlight a specific capability that was previously awkward or impossible on the platform.

Stack used: React 19 ยท TypeScript ยท Vite 7 ยท Tailwind CSS v4 ยท GraphQL ยท @salesforce/sdk-data ยท shadcn/ui ยท Recharts

No LWC. No Apex. No SLDS. No SOQL.


Three Things the POC Actually Demonstrates

1. Dynamic Query Construction at Runtime

This is the headline differentiator and the biggest gap between LWC and Multi-Framework.

With LWC's @wire, your query string is frozen at compile time:

// LWC โ€” query must be known statically
@wire(gql, { query: STATIC_QUERY })
wiredData;

With Multi-Framework, you just pick the query at runtime:

const query = isExtended ? EXTENDED_QUERY : CORE_QUERY;
const { data } = await sdk.fetch(query);

In the POC, a single toggle flips between a core query (Opportunity + Account.Name + Owner.Name) and an extended query that adds Industry, Annual Revenue, and Owner Title. No re-mount. No Apex workaround. No fragment gymnastics.

Open DevTools and flip that toggle โ€” watching the query string change in real time is the moment the LWC limitation visibly lifts.


2. Graceful FLS Handling with @optional

Field-Level Security has long been a sharp edge for GraphQL on Salesforce. A single inaccessible field would fail the entire query with FIELD_NOT_ACCESSIBLE.

The @optional directive changes that. Mark a field as optional and the query succeeds even if the user lacks permission โ€” the inaccessible field is silently omitted from the response.

query {
  uiapi {
    query {
      Opportunity {
        edges {
          node {
            Name { value }
            Amount { value }
            AnnualRevenue { value } @optional   # omitted if user lacks access
          }
        }
      }
    }
  }
}

๐Ÿ’ก Treat @optional as the default. Missing it on even one inaccessible field will blow up the entire query in real orgs with mixed permissions.

The Optional Fields panel in the POC classifies each field as resolved, skipped, or error and renders a colored status dot per field โ€” proving the query survives partial FLS access in production-like conditions.


3. The npm Ecosystem, Without the Static-Resource Dance

npm install recharts

That single line replaces what used to be a multi-step ritual just to render a chart inside Salesforce.

Recharts, shadcn/ui, lucide-react, date-fns, sonner โ€” all installed via plain npm install. No static resource manifests, no manual loader scripts, no CSP gymnastics for first-party libraries.


Architecture Overview

The repo is a Salesforce DX project containing a Vite + React UI Bundle. The structure mirrors any modern React app:

sf-multiframework-react-graphql/
โ”œโ”€โ”€ force-app/
โ”‚   โ””โ”€โ”€ main/default/
โ”‚       โ””โ”€โ”€ uiBundles/
โ”‚           โ””โ”€โ”€ pipelineDashboard/
โ”‚               โ”œโ”€โ”€ src/
โ”‚               โ”‚   โ”œโ”€โ”€ components/
โ”‚               โ”‚   โ”œโ”€โ”€ hooks/
โ”‚               โ”‚   โ””โ”€โ”€ queries/
โ”‚               โ”œโ”€โ”€ vite.config.ts
โ”‚               โ””โ”€โ”€ package.json
โ””โ”€โ”€ config/
    โ””โ”€โ”€ project-scratch-def.json

A custom hook owns the data lifecycle:

const { opportunities, loading, error } = usePipelineData({ extended: isExtended });

Authentication is handled entirely by createDataSDK() โ€” no tokens, no session juggling in your app code.


Bonus: Two GraphQL Relationship Routes

Beyond the main dashboard, the POC ships two additional routes that explore GraphQL relationship traversal โ€” one in each direction. These are the cleanest way to feel how GraphQL replaces classic SOQL parent/child patterns.

/opportunities โ€” Child-to-Parent Lookup

Fetches Opportunities and reaches up into each parent Account in a single query. No second round trip, no manual join, no separate @wire for the Account record.

query {
  uiapi {
    query {
      Opportunity {
        edges {
          node {
            Id
            Name { value }
            Amount { value }
            Account {
              Name { value }
              Industry { value }
            }
          }
        }
      }
    }
  }
}

SOQL equivalent:

SELECT Name, Amount, Account.Name, Account.Industry FROM Opportunity

/accounts-with-opps โ€” Parent-to-Child Sub-Query

Inverts the relationship. Queries Accounts and uses the Opportunities child relationship name to pull each account's opportunities as a nested collection.

query {
  uiapi {
    query {
      Account {
        edges {
          node {
            Id
            Name { value }
            Opportunities {
              edges {
                node {
                  Name { value }
                  StageName { value }
                  Amount { value }
                }
              }
            }
          }
        }
      }
    }
  }
}

SOQL equivalent:

SELECT Name, (SELECT Name, StageName, Amount FROM Opportunities) FROM Account

๐Ÿ’ก In LWC, the parent-to-child case typically forces a custom Apex method or a SOQL sub-select wrapped in @AuraEnabled. With @salesforce/sdk-data, it's just GraphQL โ€” same SDK call, different shape.

Together, these two routes demonstrate GraphQL traversal in both directions of the same relationship, in a single round trip each.


Try It Yourself: Spin Up React on Salesforce

You don't need our repo to get started. Salesforce ships an official React template that scaffolds the exact stack โ€” TypeScript, Vite, React 19, Tailwind, shadcn/ui, and @salesforce/sdk-data preconfigured.

Prerequisites

  • Salesforce CLI (latest version)

  • Node.js v18+ (v22+ recommended)

  • A scratch org or sandbox with English as the default language

  • VS Code with Salesforce Extension Pack + Agentforce Vibes (recommended)

โš ๏ธ Multi-Framework beta is not available in production orgs, Developer Edition orgs, or Trailhead Playgrounds.


Step 1: Enable the Beta in Your Org

Multi-Framework is opt-in. Enable it first:

Setup โ†’ Quick Find: Salesforce Multi-Framework โ†’ React Development with Salesforce Multi-Framework (Beta) โ†’ Enable Beta


Step 2: Authorize Your Org

# Authorize an existing sandbox or scratch org
sf org login web --alias myorg --instance-url https://test.salesforce.com

# OR create a fresh scratch org (Dev Hub required)
sf org create scratch -f config/project-scratch-def.json -a myorg -d -y 7

Step 3: Scaffold the React App

Three paths โ€” pick what fits your workflow:

Option A โ€” Agentforce Vibes (recommended) Open VS Code โ†’ Vibes Welcome Screen โ†’ React App tile โ†’ Internal App โ†’ Vibes scaffolds everything in one shot.

Option B โ€” SFDX CLI

sf template generate ui-bundle

Option C โ€” VS Code Command PaletteCtrl+Shift+P / Cmd+Shift+P โ†’ SFDX: Create Project โ†’ React Internal App


Step 4: Install and Run Locally

cd force-app/main/default/uiBundles/<YourBundleName>

npm install      # React, Vite, sdk-data, shadcn/ui, Tailwind
npm run dev      # http://localhost:5173

Step 5: Build and Deploy

# From the UI Bundle directory
npm run build

# From the repo root
sf project deploy start --source-dir force-app --target-org myorg

Step 6: Launch in Salesforce

App Launcher โ†’ search your bundle's masterLabel โ†’ click to open.

The React app loads natively inside Salesforce.


Optional: Run the Full POC

Skip scaffolding and see the Sales Pipeline Dashboard exactly as built:

git clone https://github.com/hegdesumanth/sf-multiframework-react-graphql
cd sf-multiframework-react-graphql

# One-shot bootstrap: install + deploy + schema + codegen + build + dev
npm run setup -- --target-org myorg

Once deployed, search Pipeline Dashboard in the App Launcher. Flip the Extended toggle in DevTools and watch the GraphQL query string change at runtime.


Key Learnings

GraphQL relationships eliminate manual joins. A single round trip returns Opportunity + Account + Owner data. In LWC, that's three @wire adapters or custom Apex.

@optional is non-negotiable. Treat it as the default on every field. One inaccessible field without it will blow up your entire query in real orgs.

Code readability wins. Someone with no Salesforce background can follow the GraphQL approach from inline comments alone. That's a meaningful signal for team velocity.

TypeScript codegen is a productivity multiplier. Generated operation types from the org schema catch field-name typos before runtime โ€” not at 11pm during a demo.


Limitations & Trade-offs (The Honest Section)

The beta is real, and so are its sharp edges:

Limitation Details
Scratch orgs + sandboxes only Production deployment is unsupported during beta
English orgs only Multi-language orgs are not supported yet
No App Builder integration Apps launch from App Launcher only โ€” no drag-and-drop on Lightning pages
No @wire caching You give up Lightning Data Service's free cache invalidation
No Salesforce Base Components No lightning-record-form, no lightning-datatable โ€” you compose with shadcn/Radix
Micro-frontend embedding React components embedded in Lightning pages โ€” closed pilot, Spring 2027

The core trade-off is clear: React buys ecosystem velocity. LWC buys declarative platform integration. Pick based on what you're building and where it needs to run.


Results

Running this end-to-end surfaced a few clear conclusions:

Velocity is real. A React developer with no Salesforce background could ship a comparable dashboard with minimal platform-specific friction.

Security stays intact. FLS, sharing rules, and authentication still work. You don't trade governance for flexibility.

GraphQL does the heavy lifting. Single round trips for Opportunity + Account + Owner data eliminate the multi-@wire choreography LWC forces.

Code is portable. The same React components could run outside Salesforce โ€” a meaningful win for teams maintaining customer-facing and internal surfaces in parallel.


Conclusion

Multi-Framework is the most consequential frontend shift on the Salesforce platform in years. It doesn't replace LWC โ€” but it broadens the menu significantly. For data-heavy, design-forward, ecosystem-leveraging apps, React on Salesforce is now a genuine option, not a workaround.

Where to go from here:

The platform is opening up. See what your stack feels like inside Salesforce.


Sumanth Shyam Hegde ยท Software Engineer @ ABSYZsumanth.hegde@absyz.com ยท github.com/hegdesumanth


Suggested Hashnode Tags: salesforce react graphql javascript frontend webdev lwc salesforcedeveloper

Suggested Cover Image: A dark-themed banner with the Salesforce cloud logo + React atom icon side by side. Tools like Canva or Figma work great for this.

Salesforce Dev Deep Dives

Part 1 of 1

Hands-on technical walkthroughs of Salesforce platform capabilities โ€” from Multi-Framework React to GraphQL, Apex patterns, and integrations. Built by engineers, for engineers.