@salesforce/graphiti
v10.19.1
Published
Progressive GraphQL query builder CLI for Salesforce orgs
Maintainers
Keywords
Readme
graphiti
Progressive GraphQL query builder CLI for Salesforce orgs. Treats a query as a projection of the schema — navigate the schema like a filesystem, select leaf fields, set arguments, and compose queries without ever writing raw GraphQL.
Install
npm install
npm run buildRun via node dist/cli.js (built) or npx tsx src/cli.ts (dev).
Prerequisites
- Salesforce CLI installed and authenticated (
sf org login web --alias myorg)
Quick Start
# 1. Connect to an org (downloads GraphQL schema once)
graphiti connect myorg
# 2. Start a new query session
graphiti query new myorg
# → prints Session: s_xxxx and root fields
# 3. Navigate the schema like a directory
graphiti query s_xxxx ls # list available fields
graphiti query s_xxxx ls -l # long listing (type, args, selections)
graphiti query s_xxxx ls --search Account # filter by name
graphiti query s_xxxx cd accounts # enter a field directory
graphiti query s_xxxx cd accounts/edges/node # multi-level nav
graphiti query s_xxxx pwd # print current path
graphiti query s_xxxx cd .. # go up one level
graphiti query s_xxxx cd / # go back to root
# 4. Select leaf fields (parent path added automatically)
graphiti query s_xxxx select Id
graphiti query s_xxxx select Name --as accountName
# 5. Remove a selection
graphiti query s_xxxx rm Id
# 6. Navigate union/interface fragment directories
graphiti query s_xxxx cd search # field of union type
graphiti query s_xxxx cd [Account] # inline fragment directory
graphiti query s_xxxx select name
# 7. Set field arguments
graphiti query s_xxxx cd accounts
graphiti query s_xxxx args set first 10
graphiti query s_xxxx args set where '{"Status":{"eq":"Open"}}'
graphiti query s_xxxx args ls
graphiti query s_xxxx args rm first
# 8. Bind arguments to query variables
graphiti query s_xxxx vars set \$whereInput AccountWhere
graphiti query s_xxxx bind set where \$whereInput
# 9. Set directory-scoped default argument values
graphiti query s_xxxx defaults set first 20
# 10. Preview and execute
graphiti query s_xxxx show
graphiti query s_xxxx validate
graphiti query s_xxxx executeInteractive Mode
Start an interactive REPL session for faster iteration — same commands, no need to repeat the session ID each time. Bare commands like select, cd, and args set show guided pick-lists.
graphiti query s_xxxx interactiveREPL prompt: graphiti [s_xxxx] /accounts >
Inside the REPL:
- Type any subcommand (
ls,cd edges,select Id, etc.) without thegraphiti query s_xxxxprefix. selectwith no argument → guided pick-list of available leaf fields.cdwith no argument → guided pick-list of navigable directories.args setwith no argument → guided pick-list of available field arguments.vars setwith justset→ guided prompts for name, type, and default value.exitorCtrl-Cto quit.
Commands Reference
Setup
| Command | Description |
| ------------------------------------------- | ---------------------------------------------------------------------- |
| graphiti connect <org> | Connect to a Salesforce org and download its GraphQL schema |
| graphiti connect <org> --refresh | Re-download the schema and clear all caches (after deploying metadata) |
| graphiti type <org> <TypeName> | Inspect a named GraphQL type |
| graphiti validate <org> <TypeName> <json> | Validate a JSON value against an input type |
Session lifecycle
| Command | Description |
| ----------------------------------------------------- | -------------------------------------------------- |
| graphiti query new <org> [--mutation] [--aggregate] | Create a new query, mutation, or aggregate session |
| graphiti query help [topic] | Show command help, optionally scoped to a topic |
Navigation
| Command | Description |
| --------------------------------------------- | ----------------------------------------------------------- |
| graphiti query <sid> pwd | Print current schema navigation path |
| graphiti query <sid> ls [-l] [--search pat] | List schema entries at current path |
| graphiti query <sid> cd <path> | Navigate to a schema path (supports .., /, multi-level) |
Projection
| Command | Description |
| ------------------------------------------------- | ---------------------------------------- |
| graphiti query <sid> select <leaf> [--as alias] | Select a leaf field (parents auto-added) |
| graphiti query <sid> rm <field-or-alias> | Remove a leaf selection |
Multiple instances & aliases
| Command | Description |
| ---------------------------------------------- | ---------------------------------------------- |
| graphiti query <sid> alias ls | List all projection instances at current path |
| graphiti query <sid> alias set <name> | Set alias on the focused instance |
| graphiti query <sid> alias new <name> | Create a new projection instance with an alias |
| graphiti query <sid> alias use <alias-or-id> | Switch focus to a different instance |
| graphiti query <sid> alias clear | Remove alias from the focused instance |
Use alias new to select the same field multiple times with different arguments (e.g., two aliased versions of accounts with different where clauses).
Arguments
| Command | Description |
| ---------------------------------------------- | -------------------------------------------- |
| graphiti query <sid> args ls | List args on the focused projection instance |
| graphiti query <sid> args set <name> <value> | Set an argument value |
| graphiti query <sid> args rm <name> | Remove an argument |
Variable bindings
| Command | Description |
| -------------------------------------------- | ---------------------------------------------- |
| graphiti query <sid> bind ls | List variable bindings on the focused instance |
| graphiti query <sid> bind set <arg> <$var> | Bind an argument to a query variable |
| graphiti query <sid> bind rm <arg> | Remove a binding |
Directory-scoped defaults
Default argument values applied to all projection instances under the current path unless an instance overrides them.
| Command | Description |
| -------------------------------------------------- | ----------------------------- |
| graphiti query <sid> defaults ls | List defaults at current path |
| graphiti query <sid> defaults set <name> <value> | Set a default |
| graphiti query <sid> defaults rm <name> | Remove a default |
Variables
| Command | Description |
| -------------------------------------------------------- | ------------------------ |
| graphiti query <sid> vars ls | List all query variables |
| graphiti query <sid> vars set <$name> <type> [default] | Define a variable |
| graphiti query <sid> vars value <$name> <value> | Set the runtime value |
| graphiti query <sid> vars rm <$name> | Remove a variable |
Query output
| Command | Description |
| ------------------------------- | -------------------------------------------- |
| graphiti query <sid> show | Print the current GraphQL query string |
| graphiti query <sid> validate | Validate the query against the schema |
| graphiti query <sid> execute | Execute the query against the Salesforce org |
Interactive
| Command | Description |
| ---------------------------------- | --------------------------------- |
| graphiti query <sid> interactive | Start an interactive REPL session |
Performance
Schema and auth data are cached aggressively to minimize cold-start overhead:
- Auth memoization —
sf org displayis called at most once per process; the result is cached for the lifetime of the command or interactive session. - Session-stored instanceUrl — The Salesforce instance URL is resolved once at
query newtime and persisted in the session file. Subsequent commands use this URL to locate the cached schema file directly, completely bypassingsf org display. - SDL schema cache — After a schema is first built from the introspection JSON, it is serialized to a compact SDL file (
~/.graphiti/schemas/<cacheKey>.graphql) next to the introspection JSON. Subsequent cold starts load the SDL file instead, which is faster than re-processing the raw introspection format. - In-process schema cache — Within a single interactive session, the parsed
GraphQLSchemais kept in memory so every command after the first is near-instant.
Schema storage
Schemas are stored in ~/.graphiti/schemas/ keyed by a hash of the normalized Salesforce instance URL. This means:
- Reusing an org alias for a different org will always pick up the correct schema.
- The companion SDL file (
<cacheKey>.graphql) is regenerated automatically whenever the introspection JSON is updated.
Refreshing after a deploy
graphiti caches three things per org: the on-disk introspection JSON, the in-memory parsed schema, and an ObjectInfo cache (picklists, filterable/sortable flags, required-on-create; 1-hour TTL on disk). When you deploy new metadata (fields, picklist values, objects), run a refresh to invalidate all three coherently:
graphiti connect <org> --refreshre-downloads the schema and clears all three caches.- In the MCP server, call the
sf_gql_connecttool withforceRefresh: true— the long-lived server cannot otherwise pick up new metadata, since its in-memory caches outlive a single request. - Concurrent refreshes (a CLI
--refreshand an MCPsf_gql_connectfiring at once) coalesce into a single introspection via the on-disk schema lock, so you normally never pay for the (large, multi-second) introspection twice. Coalescing is best-effort: it keys off the cache file's modification time, so on filesystems with coarse mtime resolution two refreshes landing in the same tick may each download — never incorrect, just occasionally redundant. - If a refresh fails (network/5xx) it is retried once; on terminal failure the previously cached schema is kept and a staleness-aware message is surfaced — the cache stays usable.
ObjectInfo is keyed by org alias, not instance URL. Refreshing alias
Adoes not invalidate ObjectInfo cached under a different aliasBthat points at the same org; refresh each alias you actively use, or let ObjectInfo's 1-hour TTL heal it.
Development
npm run build # compile TypeScript
npm test # build + run tests