Skip to main content

JSON-RPC Migration Guide

JSON-RPC is deprecated. Migrate to either gRPC or GraphQL RPC by July 2026. For a method mapping, decision criteria, and common migration gotchas, see the JSON-RPC Migration Guide.

Refer to the list of RPC or data providers that have enabled gRPC on their full nodes or offer GraphQL RPC. Contact a provider directly to request access. If your RPC or data provider doesn’t yet support these data access methods, ask them to enable support or contact the Sui Foundation team on Discord, Telegram, or Slack for help.

JSON-RPC is deprecated and is planned for deactivation in July 2026. The two replacements are gRPC for full node access and transaction execution, and GraphQL RPC for indexed, filterable reads.

Choose your replacement

You can use one API or both. Most exchanges and indexers end up using both: gRPC for the live data path and transaction submission, GraphQL for ad hoc queries, support tools, and joined reads.

Use gRPC for:

  • Backend services, indexers, and exchange pipelines.

  • Streaming finalized checkpoints with SubscriptionService.SubscribeCheckpoints. Combined with client-side event filtering, this can serve as a replacement for JSON-RPC WebSocket subscriptions.

  • Low-latency point lookups against the current state and recent history of a full node, through LedgerService and StateService.

  • Generated, typed clients in TypeScript, Go, Rust, Python, and other languages.

  • Workloads where protocol overhead, message size, and tail latency matter.

Use GraphQL RPC for:

  • Frontends, developer tools, scripts, and dynamic-language clients.

  • Filterable queries over historical transactions, and events.

  • Paginated queries over object and package history.

  • Filtering over live objects by type.

  • Queries that join multiple resources in a single request, such as an address with its owned objects, balances, and recent transactions.

  • Consistent results pinned to the chain state at a specific checkpoint for queries that span multiple different types, or multiple pages.

If you only need to read live state from a single full node, gRPC is usually enough. If you need cross-resource filtering, deep pagination, or want one request to return data assembled from several sources, GraphQL is usually a better fit. For deeper detail on when each API applies, see What is gRPC and GraphQL RPC.

Method mapping

The following table maps common JSON-RPC method families to their gRPC service and GraphQL equivalents. Method names on the gRPC side use the protobuf service in the Sui Full Node gRPC reference. GraphQL equivalents reference the GraphQL field or field path on the schema. Use this table to plan the migration, then consult the linked references for the exact request and response shapes.

JSON-RPC methodgRPC service and operationGraphQL field
sui_getCheckpoint, sui_getLatestCheckpointSequenceNumberLedgerService.GetCheckpointQuery.checkpoint
sui_getCheckpointsNo paginated gRPC list. Use LedgerService.GetCheckpoint for point lookups, or SubscriptionService.SubscribeCheckpoints for an ordered stream, depending on your use case.Query.checkpoints
sui_getTransactionBlockLedgerService.GetTransactionQuery.transaction
sui_multiGetTransactionBlocksLedgerService.BatchGetTransactionsQuery.multiGetTransactions
sui_getTotalTransactionBlocksLedgerService.GetCheckpoint on the latest or target checkpoint, then read summary.total_network_transactionsCheckpoint.networkTotalTransactions
sui_getObject, sui_tryGetPastObjectLedgerService.GetObject (current state and recent history)Query.object
sui_multiGetObjectsLedgerService.BatchGetObjectsQuery.multiGetObjects
suix_getBalance, suix_getAllBalancesStateService.GetBalance, StateService.ListBalancesAddress.balance, Address.balances
suix_getCoins, suix_getAllCoinsStateService.ListOwnedObjects with a type filter: 0x2::coin::Coin<T> for one coin type, or the bare 0x2::coin::Coin for all coin typesAddress.objects with filter: { type: "0x2::coin::Coin<T>" } for one coin type, or filter: { type: "0x2::coin::Coin" } for all coin types
suix_getCoinMetadataStateService.GetCoinInfoQuery.coinMetadata
suix_getOwnedObjectsStateService.ListOwnedObjectsAddress.objects
suix_getDynamicFieldsStateService.ListDynamicFieldsObject.dynamicFields
suix_getDynamicFieldObjectDerive the dynamic field's object ID locally from the parent object ID and the field name, then call LedgerService.GetObject. ListDynamicFields is not needed when you already know the field name.Object.dynamicObjectField
suix_queryTransactionBlocksNo direct filtered query. Enumerate finalized transactions through SubscriptionService.SubscribeCheckpoints, or fetch known transactions through LedgerService.GetTransaction.Query.transactions with a TransactionFilter
suix_queryEventsRead events from transaction data returned by LedgerService.GetTransaction or streamed by SubscriptionService.SubscribeCheckpointsQuery.events with an EventFilter
sui_subscribeEvent, sui_subscribeTransaction (WebSocket)SubscriptionService.SubscribeCheckpoints, then read events and transactions from each checkpointNo streaming subscription. Poll Query.events with an EventFilter, or Query.transactions with a TransactionFilter.
suix_getReferenceGasPriceLedgerService.GetEpoch (read reference_gas_price from the response)Epoch.referenceGasPrice
suix_getStakes, suix_getStakesByIdsNo direct gRPC method. Read owned StakedSui objects through StateService.ListOwnedObjects filtered by type, then fetch full contents through LedgerService.GetObject.Address.objects with filter: { type: "0x3::staking_pool::StakedSui" }
suix_getValidatorsApyNo direct gRPC method and no APY field. Read validator-set data and compute APY client-side. See issue #23832 for the recommended computation.No direct APY field. Read validator-set data through Epoch.validatorSet and compute APY client-side. See issue #23832 for the recommended computation.
sui_executeTransactionBlockTransactionExecutionService.ExecuteTransactionMutation.executeTransaction
sui_dryRunTransactionBlock, sui_devInspectTransactionBlockTransactionExecutionService.SimulateTransactionQuery.simulateTransaction
unsafe_paySui, unsafe_pay, unsafe_payAllSui, unsafe_transferSui, unsafe_transferObject, unsafe_moveCall, unsafe_splitCoin, unsafe_mergeCoins, unsafe_batchTransactionBuild a programmable transaction block with the SDK, then execute it through TransactionExecutionService.ExecuteTransactionBuild a PTB with the SDK, then submit through Mutation.executeTransaction
sui_getNormalizedMoveModule, sui_getNormalizedMoveFunction, sui_getNormalizedMoveStructMovePackageServiceQuery.package, then MovePackage.module, MoveModule.function, and MoveModule.struct

The JSON-RPC unsafe_* builder methods do not have a one-to-one replacement on either side. Build transactions with PTBs using the TypeScript SDK or the Rust SDK, then submit the resulting bytes through TransactionExecutionService.ExecuteTransaction.

Migration gotchas

No implicit archival fallback in full node gRPC

JSON-RPC sometimes resolved requests for older data through fallback paths that were transparent to the caller. Full node gRPC does not do this. A full node serves only the data within its retention window, and LedgerService returns "not found" for anything older.

The three interfaces differ in how they reach pruned history:

  • Full node gRPC serves the complete RPC surface (transaction execution, point lookups, checkpoint subscriptions), but only within the full node's retention window.

  • The Archival Service is a separate gRPC service that serves unpruned point lookups for checkpoints, transactions, and objects. It is scoped to those point lookups, so it does not serve the rest of the full node RPC surface, such as transaction execution or live state queries. Reuse the same LedgerService methods, but point the client at an Archival Service endpoint such as archive.mainnet.sui.io:443 or your provider's archival URL. See Archival Store.

  • GraphQL is a unified interface that serves both recent data and, when the operator configures archival access, unpruned point lookups, with no client-side fallback.

Typed requests replace positional JSON-RPC params

JSON-RPC accepts a positional array of arguments. gRPC uses typed protobuf messages, and GraphQL uses named, typed arguments and selection sets. When you port a call, do not translate positional indices directly. Read the schema and pass each value by name, including the response shape selector. For gRPC, use a FieldMask to fetch only the fields you need rather than the entire response. See field masks for the rules.

WebSocket subscriptions are replaced by gRPC streaming

JSON-RPC offered WebSocket subscriptions for events and transactions. Sui does not carry those forward. Use SubscriptionService.SubscribeCheckpoints over gRPC server streaming to receive finalized checkpoints in order, and read each checkpoint's transactions, effects, and events from the streamed payload. If your stream disconnects, resume from the last processed checkpoint sequence number. Backfill any missed range using LedgerService before you resubscribe. See Subscriptions for streaming data.

Public load balancer URLs are not production endpoints

The public URLs at https://fullnode.<network>.sui.io and https://graphql.<network>.sui.io/graphql are rate-limited and intended for development and public-good access. Do not point a production exchange, indexer, or wallet backend at them. Run your own Sui full node or contract with a provider for a dedicated gRPC or GraphQL endpoint.

Object and coin queries behave differently

GraphQL and gRPC expose richer typing for objects and coins than JSON-RPC. A few practical points:

  • Coin selection. Replace suix_getCoins with an owned-objects query filtered by coin type: Address.objects with filter: { type: "0x2::coin::Coin<...>" } in GraphQL, or StateService.ListOwnedObjects with the same type filter on gRPC. To list coins of every type (the suix_getAllCoins case), filter by the bare 0x2::coin::Coin type without a type parameter. For transaction building, prefer gas smashing or address-balance gas payments rather than constructing coin lists by hand.

  • Balances cover both representations. Read Balance.totalBalance to get the sum across coin objects and the address-balance accumulator. Read Balance.coinBalance and Balance.addressBalance separately to reconcile against your own ledger.

  • Object and package versions. GraphQL can scrub through the version history of an object or package, which has no JSON-RPC analog. Use Query.objectVersions, or IObject.objectVersionsAfter and IObject.objectVersionsBefore from an object, to page through an object's versions. Use Query.packageVersions for the published versions of a package.

  • Checkpoint-scoped consistency. GraphQL can pin a query to the chain state at a specific checkpoint through Checkpoint.query, so a read that spans multiple types or multiple pages sees one consistent snapshot. JSON-RPC has no equivalent.

Pagination uses typed cursors

JSON-RPC cursors are opaque strings. GraphQL passes cursors through the after (or before) field on a connection, with the page size in first (or last). gRPC paging uses fields on the typed request and response messages. Do not try to reuse a JSON-RPC nextCursor value in a GraphQL or gRPC request. Fetch a fresh cursor from the new API and persist it as the resume point.

Retention windows

A full node retains a configurable window of recent data and prunes older history. Your application sees this as "not found" responses. For long-running queries, replays, or audits, plan to fall back to the Archival Service for data outside the full node's retention.

Examples for high-traffic paths

Each pattern below links to the canonical worked example and includes an inline snippet you can expand. The canonical docs remain the source of truth for the full request and response shapes.

Transaction lookup

Click to open
gRPC and GraphQL examples

Look up a transaction over gRPC with grpcurl:

$ grpcurl -d '{ "digest": "J4NvV5iQZQFm1xKPYv9ffDCCPW6cZ4yFKsCqFUiDX5L4" }' <full node URL:port> sui.rpc.v2.LedgerService/GetTransaction

The equivalent GraphQL query:

query {
transaction(digest: "Hay2tj3GcDYcE3AMHrej5WDsHGPVAYsegcubixLUvXUF") {
gasInput {
gasSponsor {
address
}
gasPrice
gasBudget
}
effects {
status
timestamp
checkpoint {
sequenceNumber
}
}
}
}

Balances

  • GraphQL: Query Address.balance for a single coin type or Address.balances for all balances, both reached from Query.address. Read Balance.totalBalance, Balance.coinBalance, and Balance.addressBalance together to reconcile. See Using Address Balances for a verified example.

  • gRPC: Use StateService.GetBalance or StateService.ListBalances. See the GetBalance request reference and the worked example in Using Address Balances.

Click to open
gRPC and GraphQL examples

Read a balance over gRPC with the Buf CLI:

$ buf curl --protocol grpc https://<full node URL>/sui.rpc.v2.StateService/GetBalance -d '{ "owner": "<ADDRESS>", "coin_type": "0x2::sui::SUI" }'

The equivalent GraphQL query:

query {
address(address: "0xe4ee9c157b5eb185c2df885bd7dcb4be493630a913f4b0e0c7e8ecf77930a878") {
balance(coinType: "0x2::sui::SUI") {
coinType {
repr
}
addressBalance
coinBalance
totalBalance
}
}
}

Coins

  • GraphQL: Example 3 in Migrating to GraphQL from JSON-RPC maps suix_getCoins to Address.objects with filter: { type: "0x2::coin::Coin<0x2::sui::SUI>" }, including how cursor pagination changes.

  • gRPC: Read coin objects through StateService.ListOwnedObjects with a Coin<T> type filter.

Click to open
gRPC and GraphQL examples

List owned objects over gRPC with grpcurl:

$ grpcurl -d '{ "owner": "0x94096a6a54129234237759c66e6ef1037224fb3102a0ae29d33b490281c8e4d5" }' <full node URL:port> sui.rpc.v2.StateService/ListOwnedObjects

Filter for a coin type in GraphQL. Pass the page size in first and the pagination cursor in after:

query {
address(address: "0x5094652429957619e6efa79a404a6714d1126e63f551f4b6c7fb76440f8118c9") {
objects(
first: 3,
after: "vBIzCwAAAADMAQBQlGUkKZV2Gebvp5pASmcU0RJuY/VR9LbH+3ZED4EYyQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAARjb2luAAAAAAAAAARDb2luAAAAAAAAAAEAAAAHAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAAAAAAAA3N1aQAAAAAAAAADU1VJAAAAAAAAAAAB/////XBZUf9feyhb9cW+AOBraL10O9t0D9JAr+tIq2wXDJdl5/zP5w==",
filter: { type: "0x2::coin::Coin<0x2::sui::SUI>" }
) {
nodes {
address
}
}
}
}

Omit after to fetch the first page. The cursor is opaque, so use one returned by a previous query rather than constructing it by hand.

Events

  • GraphQL: See Querying events with GraphQL for the events(filter:) field and the filtering reference.

  • gRPC: Events arrive as part of transaction data in LedgerService.GetTransaction responses, and live updates arrive in each checkpoint streamed by SubscriptionService.SubscribeCheckpoints. See Querying events with RPC.

Click to open
GraphQL example

Query events with a type filter:

query {
events(
filter: { type: "0x3164fcf73eb6b41ff3d2129346141bd68469964c2d95a5b1533e8d16e6ea6e13::Market::ChangePriceEvent<0x2::sui::SUI>" }
) {
nodes {
sender {
address
}
timestamp
contents {
type {
repr
}
json
}
}
}
}

Checkpoints

  • gRPC: Subscribe with SubscriptionService.SubscribeCheckpoints for an ordered, gapless stream of finalized checkpoints. Use LedgerService.GetCheckpoint for point lookups. See Subscriptions for streaming data.

  • GraphQL: Query Query.checkpoint for a specific checkpoint, or paginate Query.checkpoints for a range. Use Checkpoint.query to scope a multi-resource read to a specific checkpoint.

Click to open
gRPC and GraphQL examples

Look up a checkpoint over gRPC with grpcurl:

$ grpcurl -d '{ "sequence_number": "164329987", "read_mask": { "paths": ["transactions"]} }' <full node URL:port> sui.rpc.v2.LedgerService/GetCheckpoint

Subscribe to the checkpoint stream over gRPC with the Buf CLI:

$ buf curl --protocol grpc https://<full node URL>/sui.rpc.v2.SubscriptionService/SubscribeCheckpoints -d '{ "readMask": "sequenceNumber,digest,summary.timestamp" }' --timeout 1m

Look up a checkpoint in GraphQL:

query {
checkpoint(sequenceNumber: 164329987) {
digest
networkTotalTransactions
timestamp
}
}

Submit a transaction

Build the transaction with a PTB through the SDK, sign it, and execute it through TransactionExecutionService.ExecuteTransaction (gRPC) or the Mutation.executeTransaction mutation (GraphQL). See Building Programmable Transaction Blocks for the construction steps and Signing and Sending Transactions for the signature requirements.