Sui Clients
Choose between SuiGrpcClient and SuiGraphQLClient and understand their shared API
A client is how your code reads from and writes to the Sui network. There are two to choose from, and they implement the same API (the same method names, options, and response shapes), so the choice is about which transport suits your application, not about which features you get.
| Client | Choose it for |
|---|---|
SuiGrpcClient | The default. Reads from a full node, and the only client with real-time subscriptions |
SuiGraphQLClient | Reads from the indexer, and custom queries written against the GraphQL schema |
Both are fully supported primary choices. Pick SuiGrpcClient if you have no particular reason to
prefer one, and SuiGraphQLClient when your application wants to query the GraphQL schema directly.
Because they share an API, moving between them is mostly a matter of changing the constructor.
JSON-RPC is deprecated. See the migration guide if you maintain existing JSON-RPC code.
Quick start
import { SuiGrpcClient } from '@mysten/sui/grpc';
const client = new SuiGrpcClient({
network: 'mainnet',
baseUrl: 'https://fullnode.mainnet.sui.io:443',
});
const { balance } = await client.getBalance({ owner: '0x...' });
const { object } = await client.getObject({
objectId: '0x...',
include: { content: true },
});The same code against GraphQL differs only in how the client is created:
import { SuiGraphQLClient } from '@mysten/sui/graphql';
const client = new SuiGraphQLClient({
network: 'mainnet',
url: 'https://graphql.mainnet.sui.io/graphql',
});Three ways to call a client
Each client exposes the same functionality through three surfaces, aimed at different callers.
Top-level methods
The main API for application code. Read data, execute transactions, and query history by calling methods directly on the client:
const { objects } = await client.listOwnedObjects({
owner: '0x...',
include: { display: true },
});
const result = await client.signAndExecuteTransaction({
transaction,
signer,
include: { effects: true, balanceChanges: true },
});These are documented in Querying data and
Signing and execution. Where a transport can return more
than the shared shape carries, it adds options here, such as include: { protoJson: true } on gRPC.
client.core
The transport-agnostic contract, for libraries that must work with whichever client their caller supplies:
import type { ClientWithCoreApi } from '@mysten/sui/client';
export async function fetchResource(client: ClientWithCoreApi, objectId: string) {
return client.core.getObject({
objectId,
include: { content: true },
});
}See the Core API for the contract and the cross-transport differences to account for. Application code does not need this. Call the top-level methods instead.
Native APIs
Each client also exposes its transport in full, for the cases the shared API does not cover:
// gRPC: generated service clients, read masks, and streams
const { response } = await grpcClient.ledgerService.getServiceInfo({});
// GraphQL: type-safe custom queries
const result = await graphqlClient.query({
query: graphql(`
query {
chainIdentifier
}
`),
});gRPC adds raw list RPCs and subscriptions; GraphQL adds custom queries against the schema.
Client extensions
Both clients support extensions through $extend, which lets SDKs such as
@mysten/walrus add functionality to a client your
application already configured:
import { walrus } from '@mysten/walrus';
const client = new SuiGrpcClient({ network: 'mainnet', baseUrl: '...' }).$extend(walrus());
const { blobId } = await client.walrus.writeBlob({
blob: file,
deletable: false,
epochs: 3,
signer: keypair,
});See Building SDKs for creating your own.