SuiGrpcClient
Connect to Sui through gRPC with the recommended SuiGrpcClient
The SuiGrpcClient provides access to the Full Node gRPC API. It is the recommended default client
for application code and SDK integrations.
For more complete details on what is available through this API see the gRPC API docs.
Creating a gRPC client
To get started, create a SuiGrpcClient instance by specifying a network and base URL:
import { SuiGrpcClient } from '@mysten/sui/grpc';
const grpcClient = new SuiGrpcClient({
network: 'testnet',
baseUrl: 'https://fullnode.testnet.sui.io:443',
});For local development:
const grpcClient = new SuiGrpcClient({
network: 'localnet',
baseUrl: 'http://127.0.0.1:9000',
});Using top-level methods
Use top-level methods for most application code. These methods match the shared
Core API option and response shapes, so the same calls can also be written as
grpcClient.core.<method>() when SDK code needs the transport-agnostic ClientWithCoreApi
contract.
import { SuiGrpcClient } from '@mysten/sui/grpc';
const grpcClient = new SuiGrpcClient({
network: 'testnet',
baseUrl: 'https://fullnode.testnet.sui.io:443',
});
const { balance } = await grpcClient.getBalance({
owner: '<OWNER_ADDRESS>',
});
const { object } = await grpcClient.getObject({
objectId: '<OBJECT_ID>',
include: { content: true, display: true },
});
const coins = await grpcClient.listCoins({
owner: '<OWNER_ADDRESS>',
coinType: '0x2::sui::SUI',
});Common top-level methods:
| Category | Methods |
|---|---|
| Objects | getObject, getObjects, listOwnedObjects, listDynamicFields, getDynamicField |
| Coins | listCoins, getBalance, listBalances, getCoinMetadata |
| Transactions | getTransaction, executeTransaction, signAndExecuteTransaction, waitForTransaction |
| Simulation | simulateTransaction |
| Queries | listTransactions, listEvents |
| Move and names | getMoveFunction, resolveNameServiceAddress, defaultNameServiceName, mvr.resolvePackage, mvr.resolveType |
| Verification | verifyZkLoginSignature |
gRPC-specific top-level data
Top-level gRPC methods are a superset of the shared Core API where the transport can expose useful gRPC data directly:
const result = await grpcClient.getTransaction({
digest: '<TRANSACTION_DIGEST>',
include: {
effects: true,
protoJson: true,
},
});
const tx = result.Transaction ?? result.FailedTransaction;
console.log(tx.digest, result.protoJson);gRPC-specific options include:
| Option | Methods |
|---|---|
include.protoJson | getTransaction, executeTransaction, signAndExecuteTransaction, waitForTransaction |
include.protoJson | simulateTransaction |
doGasSelection | simulateTransaction |
include: { value: true } | listDynamicFields |
Transport options
By default, SuiGrpcClient uses GrpcWebFetchTransport from
protobuf-ts, which works in browsers and Node.js through
the Fetch API. You can also provide a custom transport for advanced use cases.
The GrpcWebFetchTransport class, GrpcWebOptions type, and RpcTransport type are all
re-exported from @mysten/sui/grpc for convenience.
gRPC-web transport (default)
The default transport uses the gRPC-web protocol over HTTP/1.1 or HTTP/2. You can customize it by
passing GrpcWebFetchTransport options directly:
import { SuiGrpcClient, GrpcWebFetchTransport } from '@mysten/sui/grpc';
const transport = new GrpcWebFetchTransport({
baseUrl: 'https://your-custom-grpc-endpoint.com',
format: 'binary', // default is 'text' (base64-encoded)
// Additional transport options like fetchInit
});
const grpcClient = new SuiGrpcClient({
network: 'testnet',
transport,
});Native gRPC transport
For server-side applications (Node.js, Bun, and others), you can use the native gRPC transport with
@protobuf-ts/grpc-transport and @grpc/grpc-js. This uses HTTP/2 with the native gRPC protocol
rather than the gRPC-web translation layer.
Install the required packages:
npm install @protobuf-ts/grpc-transport @grpc/grpc-jsThen create the client with a GrpcTransport:
import { SuiGrpcClient } from '@mysten/sui/grpc';
import { GrpcTransport } from '@protobuf-ts/grpc-transport';
import { ChannelCredentials } from '@grpc/grpc-js';
const transport = new GrpcTransport({
host: 'fullnode.testnet.sui.io:443',
channelCredentials: ChannelCredentials.createSsl(),
});
const grpcClient = new SuiGrpcClient({
network: 'testnet',
transport,
});For local development without TLS:
import { GrpcTransport } from '@protobuf-ts/grpc-transport';
import { ChannelCredentials } from '@grpc/grpc-js';
const transport = new GrpcTransport({
host: '127.0.0.1:9000',
channelCredentials: ChannelCredentials.createInsecure(),
});
const grpcClient = new SuiGrpcClient({
network: 'localnet',
transport,
});Using service clients
The SuiGrpcClient exposes several service clients for lower-level access to the gRPC API. These
service clients are generated using protobuf-ts, which
provides type-safe gRPC clients for TypeScript. For more details on how to use gRPC with Sui, see
the gRPC overview.
Prefer top-level methods first
For common operations, call the top-level method before reaching for raw service clients:
import { SuiGrpcClient } from '@mysten/sui/grpc';
const grpcClient = new SuiGrpcClient({
network: 'testnet',
baseUrl: 'https://fullnode.testnet.sui.io:443',
});
await grpcClient.listCoins({
owner: '<OWNER_ADDRESS>',
});Use the generated service clients directly when you need gRPC methods, read masks, streaming behavior, or filters that are not exposed by the top-level API.
Transaction execution service
const { response } = await grpcClient.transactionExecutionService.executeTransaction({
transaction: {
bcs: {
value: transactionBytes,
},
},
signatures: signatures.map((sig) => ({
bcs: { value: fromBase64(sig) },
signature: { oneofKind: undefined },
})),
});
// IMPORTANT: Always check the transaction status
if (!response.finality?.effects?.status?.success) {
const error = response.finality?.effects?.status?.error;
throw new Error(`Transaction failed: ${error || 'Unknown error'}`);
}Ledger service
// Get transaction by digest
const { response } = await grpcClient.ledgerService.getTransaction({
digest: '0x123...',
});
// Get current epoch information
const { response: epochInfo } = await grpcClient.ledgerService.getEpoch({});The ledger service also provides streaming listCheckpoints, listTransactions, and listEvents
RPCs. For most use cases, prefer the corresponding
core API query methods (listTransactions and listEvents),
which handle pagination and filter construction for you. The raw RPCs additionally support DNF
filters (combined, negated, and additional predicates like affected_address and package_write)
and checkpoint range bounds that the core API does not expose:
// Transactions that affected an address but were not sent by it:
const stream = grpcClient.ledgerService.listTransactions({
filter: {
terms: [
{
literals: [
{
negated: false,
predicate: {
oneofKind: 'affectedAddress',
affectedAddress: { address: '0xabc...' },
},
},
{
negated: true,
predicate: { oneofKind: 'sender', sender: { address: '0xabc...' } },
},
],
},
],
},
readMask: { paths: ['digest'] },
});
for await (const frame of stream.responses) {
if (frame.transaction) {
console.log(frame.transaction.digest);
}
}Subscription service
Subscribe to filtered, real-time streams of checkpoints, transactions, or events. Streams begin at the current tip of the chain:
const stream = grpcClient.subscriptionService.subscribeTransactions({
filter: {
terms: [
{
literals: [
{
negated: false,
predicate: { oneofKind: 'sender', sender: { address: '0xabc...' } },
},
],
},
],
},
readMask: { paths: ['digest', 'effects.status'] },
});
for await (const frame of stream.responses) {
if (frame.transaction) {
console.log(frame.transaction.digest);
}
}State service
// List owned objects
const { response } = await grpcClient.stateService.listOwnedObjects({
owner: '0xabc...',
objectType: '0x2::coin::Coin<0x2::sui::SUI>',
});
// Get dynamic fields
const { response: fields } = await grpcClient.stateService.listDynamicFields({
parent: '0x123...',
});Move package service
// Get function information
const { response } = await grpcClient.movePackageService.getFunction({
packageId: '0x2',
moduleName: 'coin',
name: 'value',
});Name service
const { address } = await grpcClient.resolveNameServiceAddress({
name: 'example.sui',
});Use the raw name service when you need the complete gRPC NameRecord instead of only its target
address:
const { response } = await grpcClient.nameService.lookupName({
name: 'example.sui',
});
const { response: reverseResponse } = await grpcClient.nameService.reverseLookupName({
address: '0xabc...',
});Signature verification service
// Verify a signature
const { response } = await grpcClient.signatureVerificationService.verifySignature({
message: {
name: 'TransactionData',
value: messageBytes,
},
signature: {
bcs: { value: signatureBytes },
signature: { oneofKind: undefined },
},
jwks: [],
});