GraphQL Migration Cookbook
Each recipe pairs a JSON-RPC call with its GraphQL replacement and explains the key differences. For the full method mapping and decision criteria, see the JSON-RPC Migration Guide. For GraphQL concepts, pagination, and scope, see GraphQL for Sui RPC.
JSON-RPC is disabled on Sui Foundation Mainnet full nodes. The shutoff took effect the week of July 27, 2026. Sui Foundation plans full decommission, including code removal, for mid-October 2026. If your application still calls JSON-RPC, migrate to gRPC or GraphQL RPC now. For a method mapping, decision criteria, and the remaining timeline, see the JSON-RPC Migration Guide.
See RPC and Data Providers for providers that serve gRPC and GraphQL RPC endpoints. Contact a provider directly to request access. If your provider does not yet support these interfaces, ask them to enable support, or reach the Sui Foundation team on Discord, Telegram, or Slack for help.
Before you start
GraphQL queries run against the online IDE or any GraphQL endpoint. Access the service at:
- Mainnet: https://graphql.mainnet.sui.io/graphql
- Testnet: https://graphql.testnet.sui.io/graphql
- Devnet: https://graphql.devnet.sui.io/graphql
For curl examples, replace <GRAPHQL_ENDPOINT> with your provider's GraphQL URL. See GraphQL for Sui RPC for headers, variables, fragments, and pagination details.
curl -X POST <GRAPHQL_ENDPOINT> \
-H "Content-Type: application/json" \
-d '{ "query": "{ epoch { referenceGasPrice } }" }'
Get a single object
Replace sui_getObject with Query.object. Select only the fields you need instead of toggling showContent, showOwner booleans.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getObject",
"params": [
"0xOBJECT_ID",
{ "showContent": true, "showOwner": true }
]
}'
query {
object(address: "0xOBJECT_ID") {
address
owner {
... on AddressOwner {
address { address }
}
... on Shared {
initialSharedVersion
}
}
asMoveObject {
contents {
type { repr }
json
}
}
}
}
Key differences:
- JSON-RPC uses
showContent,showOwnerbooleans. GraphQL uses field selection: request only the fields you need. - GraphQL returns typed owner information. Use inline fragments (
... on AddressOwner,... on Shared) to access owner details. - To fetch an object at a specific version, pass
versionas an argument:object(address: "0x...", version: 42).
Multi-get objects
Replace sui_multiGetObjects with Query.multiGetObjects.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_multiGetObjects",
"params": [
["0xOBJECT_A", "0xOBJECT_B", "0xOBJECT_C"],
{ "showContent": true }
]
}'
query {
multiGetObjects(keys: [
{ objectId: "0xOBJECT_A" },
{ objectId: "0xOBJECT_B" },
{ objectId: "0xOBJECT_C" }
]) {
address
asMoveObject {
contents {
type { repr }
json
}
}
}
}
Key differences:
- GraphQL applies the same field selection to all objects in the batch.
- Each key can optionally include a
versionto fetch a specific version of that object.
Get a transaction
Replace sui_getTransactionBlock with Query.transaction.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getTransactionBlock",
"params": [
"Hay2tj3GcDYcE3AMHrej5WDsHGPVAYsegcubixLUvXUF",
{ "showEffects": true, "showEvents": true }
]
}'
query {
transaction(digest: "Hay2tj3GcDYcE3AMHrej5WDsHGPVAYsegcubixLUvXUF") {
gasInput {
gasSponsor { address }
gasPrice
gasBudget
}
effects {
status
timestamp
checkpoint { sequenceNumber }
}
}
}
Key differences:
- JSON-RPC uses
showEffects,showEventsbooleans. GraphQL uses field selection: requesteffects,events,gasInput, or any combination. - GraphQL returns structured, typed data. For example,
effects.checkpointgives you the checkpoint directly without needing a separate lookup.
Multi-get transactions
Replace sui_multiGetTransactionBlocks with Query.multiGetTransactions.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_multiGetTransactionBlocks",
"params": [
["DIGEST_A", "DIGEST_B"],
{ "showEffects": true, "showEvents": true }
]
}'
query {
multiGetTransactions(keys: ["DIGEST_A", "DIGEST_B"]) {
digest
effects {
status
timestamp
}
}
}
Get total transactions
Replace sui_getTotalTransactionBlocks with Checkpoint.networkTotalTransactions.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getTotalTransactionBlocks",
"params": []
}'
query {
checkpoint {
networkTotalTransactions
}
}
Key differences:
- Without an argument,
checkpointreturns the latest checkpoint. ReadnetworkTotalTransactionsfrom it for the current total.
Query filtered transactions
Replace suix_queryTransactionBlocks with Query.transactions and a TransactionFilter.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_queryTransactionBlocks",
"params": [
{ "filter": { "FromAddress": "0xADDRESS" } },
null, 10, false
]
}'
query {
transactions(
first: 10,
filter: { sentAddress: "0xADDRESS" }
) {
pageInfo {
hasNextPage
endCursor
}
nodes {
digest
sender { address }
effects {
status
timestamp
}
}
}
}
Key differences:
- GraphQL supports rich filters:
sentAddress,affectedAddress,affectedObject,function,kind, and more. - Pagination uses
first/after(forward) orlast/before(backward) with cursors frompageInfo. - JSON-RPC's positional
[filter, cursor, limit, descending]array is replaced by named arguments.
Query events
Replace suix_queryEvents with Query.events and an EventFilter.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_queryEvents",
"params": [
{ "MoveEventType": "0xPACKAGE::module::MyEvent" },
null, 50, false
]
}'
query {
events(
first: 50,
filter: {
type: "0xPACKAGE::module::MyEvent"
}
) {
pageInfo {
hasNextPage
endCursor
}
nodes {
sender { address }
timestamp
contents {
type { repr }
json
}
}
}
}
Key differences:
- GraphQL supports server-side event filtering by
type,module,sender, and checkpoint bounds (afterCheckpoint,beforeCheckpoint,atCheckpoint). No client-side filtering needed. - JSON-RPC's
MoveEventTypefilter becomestypein the GraphQLEventFilter. - For events from a known transaction, query the transaction directly and select
events.
Events from a known transaction
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_queryEvents",
"params": [
{ "Transaction": "8NB8sXb4m9PJhCyLB7eVH4onqQWoFFzVUrqPoYUhcQe2" },
null, 50, false
]
}'
query {
transaction(digest: "8NB8sXb4m9PJhCyLB7eVH4onqQWoFFzVUrqPoYUhcQe2") {
effects {
events {
nodes {
sender { address }
contents {
type { repr }
json
}
}
}
}
}
}
Look up a single checkpoint
Replace sui_getCheckpoint with Query.checkpoint.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getCheckpoint",
"params": ["164329987"]
}'
query {
checkpoint(sequenceNumber: 164329987) {
digest
networkTotalTransactions
timestamp
}
}
Key differences:
- Without a
sequenceNumberargument,checkpointreturns the latest. - GraphQL can also look up a checkpoint by
digest.
Paginate checkpoints
Replace sui_getCheckpoints polling with Query.checkpoints pagination.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_getCheckpoints",
"params": [null, 10, false]
}'
query ($after: String) {
checkpoints(first: 10, after: $after) {
pageInfo {
hasNextPage
endCursor
}
nodes {
sequenceNumber
digest
timestamp
}
}
}
Key differences:
- GraphQL uses cursor-based pagination. Pass
pageInfo.endCursoras the$aftervariable for the next page. - For reverse order, use
lastandbeforeinstead offirstandafter. - For real-time streaming, use gRPC
SubscribeEventsorSubscribeTransactionsinstead. GraphQL has subscription infrastructure but gRPC is the production streaming path today.
Get balances
Replace suix_getBalance and suix_getAllBalances with Address.balance and Address.balances.
- JSON-RPC (deprecated)
- GraphQL
# Single coin type
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_getBalance",
"params": ["0xADDRESS", "0x2::sui::SUI"]
}'
# All coin types
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_getAllBalances",
"params": ["0xADDRESS"]
}'
# Single coin type
query {
address(address: "0xADDRESS") {
balance(coinType: "0x2::sui::SUI") {
coinType { repr }
totalBalance
}
}
}
# All coin types
query {
address(address: "0xADDRESS") {
balances {
nodes {
coinType { repr }
totalBalance
}
}
}
}
Key differences:
balancereturns a single balance for a specific coin type.balancesreturns a paginated list of all coin type balances.- The GraphQL balance includes
addressBalance,coinBalance, andtotalBalancefields. ReadtotalBalancefor the combined amount.
List owned coins
Replace suix_getCoins and suix_getAllCoins with Address.objects filtered by coin type.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_getCoins",
"params": ["0xADDRESS", "0x2::sui::SUI", null, 50]
}'
query {
address(address: "0xADDRESS") {
objects(
first: 50,
filter: { type: "0x2::coin::Coin<0x2::sui::SUI>" }
) {
pageInfo {
hasNextPage
endCursor
}
nodes {
address
contents { json }
}
}
}
}
To list coins of every type, use filter: { type: "0x2::coin::Coin" } without a type parameter.
Key differences:
- There is no dedicated coin-listing query. Use
Address.objectswith aCoin<T>type filter. - Pagination uses cursor-based
first/afterinstead of positional[cursor, limit]parameters.
Get coin metadata
Replace suix_getCoinMetadata with Query.coinMetadata.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_getCoinMetadata",
"params": ["0x2::sui::SUI"]
}'
query {
coinMetadata(coinType: "0x2::sui::SUI") {
name
symbol
decimals
description
iconUrl
}
}
List owned objects
Replace suix_getOwnedObjects with Address.objects.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_getOwnedObjects",
"params": ["0xADDRESS", null, null, 50]
}'
query {
address(address: "0xADDRESS") {
objects(first: 50) {
pageInfo {
hasNextPage
endCursor
}
nodes {
address
digest
contents {
type { repr }
json
}
}
}
}
}
Key differences:
- GraphQL supports
filteronobjectsto narrow by type, such asfilter: { type: "0x2::coin::Coin" }. - Pagination is consistent: cursors encode the checkpoint at which the query was first executed, so later pages reflect the same state.
List dynamic fields
Replace suix_getDynamicFields with Object.dynamicFields.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_getDynamicFields",
"params": ["0xPARENT_OBJECT_ID", null, 50]
}'
query {
object(address: "0xPARENT_OBJECT_ID") {
dynamicFields(first: 50) {
pageInfo {
hasNextPage
endCursor
}
nodes {
name {
type { repr }
json
}
value {
__typename
... on MoveValue {
type { repr }
json
}
... on MoveObject {
contents {
type { repr }
json
}
}
}
}
}
}
}
Key differences:
- GraphQL returns both the name and value of each dynamic field in one query. JSON-RPC required a separate
suix_getDynamicFieldObjectcall for each value. - For a specific dynamic field by name, use
dynamicField(name: { type: "...", bcs: "..." })ordynamicObjectField(name: { type: "...", bcs: "..." })instead of paginating.
Get a specific dynamic field object
Replace suix_getDynamicFieldObject with Object.dynamicObjectField.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "suix_getDynamicFieldObject",
"params": [
"0xPARENT_OBJECT_ID",
{ "type": "0x1::string::String", "value": "my_key" }
]
}'
query {
object(address: "0xPARENT_OBJECT_ID") {
dynamicObjectField(
name: { type: "0x1::string::String", bcs: "..." }
) {
value {
... on MoveObject {
address
contents {
type { repr }
json
}
}
}
}
}
}
Execute a transaction
Replace sui_executeTransactionBlock with Mutation.executeTransaction.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_executeTransactionBlock",
"params": [
"<BASE64_TX_BYTES>",
["<BASE64_SIGNATURE>"],
{ "showEffects": true }
]
}'
mutation ($tx: Base64!, $sigs: [Base64!]!) {
executeTransaction(transactionDataBcs: $tx, signatures: $sigs) {
effects {
status
epoch {
startTimestamp
}
gasEffects {
gasSummary {
computationCost
}
}
}
}
}
Variables:
{
"tx": "<BASE64_TX_BYTES>",
"sigs": ["<BASE64_SIGNATURE>"]
}
Key differences:
- GraphQL uses a mutation, not a query.
- The
transactionDataBcsparameter takes the serialized unsigned transaction data. Use the Sui Client CLI--serialize-unsigned-transactionflag or the TypeScript SDK to generate it. - Select fields from
effectsin the same mutation to read execution results immediately without waiting for a separate indexed query. - The JSON-RPC
unsafe_*builder methods (unsafe_moveCall,unsafe_transferObject, and others) have no GraphQL equivalent. Build transactions with programmable transaction blocks (PTBs) using the SDK, then submit the bytes.
Simulate a transaction (dry run)
Replace sui_dryRunTransactionBlock and sui_devInspectTransactionBlock with Query.simulateTransaction.
- JSON-RPC (deprecated)
- GraphQL
curl -X POST https://fullnode.mainnet.sui.io:443 \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "sui_dryRunTransactionBlock",
"params": ["<BASE64_TX_BYTES>"]
}'
query ($tx: JSON!) {
simulateTransaction(
transaction: $tx,
checksEnabled: true,
doGasSelection: true
) {
effects {
status
gasEffects {
gasSummary {
computationCost
storageCost
}
}
}
outputs {
returnValues {
value { json }
}
}
}
}
Key differences:
simulateTransactionaccepts a JSON transaction matching the Sui gRPC transaction schema, or a BCS-encoded transaction with{"bcs": {"value": "<base64>"}}.- Set
doGasSelection: trueto have the service automatically select gas coins for the simulation.