llms.txt
@mysten/sui v2.0 and a new dApp Kit are here! Check out the migration guide
Mysten Labs SDKs
Clients

SuiGraphQLClient

Connect to Sui over GraphQL and write type-safe custom queries

SuiGraphQLClient talks to the Sui GraphQL API. It implements the same client API as SuiGrpcClient, so anything on Querying data and Signing and execution works here unchanged:

import { SuiGraphQLClient } from '@mysten/sui/graphql';

const client = new SuiGraphQLClient({
	url: 'https://graphql.mainnet.sui.io/graphql',
	network: 'mainnet',
});

const { object } = await client.getObject({
	objectId: '0x...',
	include: { content: true },
});

Beyond that shared surface, the client can run any query the schema supports, typed from the schema itself. The rest of this page covers writing those queries; see the GraphQL reference for the schema.

The constructor takes:

OptionDescription
urlGraphQL endpoint
networkNetwork the endpoint serves, used for caching and MVR defaults
headersExtra headers sent with every request, such as an API key
fetchCustom fetch implementation
queriesNamed documents callable through execute
mvrMove Registry overrides

Writing queries

Use query to run any GraphQL document against the endpoint:

import { graphql } from '@mysten/sui/graphql/schema';

const chainIdentifierQuery = graphql(`
	query {
		chainIdentifier
	}
`);

const result = await client.query({ query: chainIdentifierQuery });

console.log(result.data?.chainIdentifier);

Type safety

The graphql function is powered by gql.tada, which types results and variables from the schema itself, with no code generation step and no hand-written result types. Fields you did not select are not on the result type, and variables are checked against the query:

const getSuinsName = graphql(`
	query getSuiName($address: SuiAddress!) {
		address(address: $address) {
			defaultNameRecord {
				domain
			}
		}
	}
`);

async function getDefaultSuinsName(address: string) {
	const result = await client.query({
		query: getSuinsName,
		variables: { address },
	});

	return result.data?.address?.defaultNameRecord?.domain;
}

Using typed documents with other clients

The graphql function returns document nodes implementing the TypedDocumentNode standard, so the same typed documents work with most GraphQL clients:

import { useQuery } from '@apollo/client';
import { graphql } from '@mysten/sui/graphql/schema';

const chainIdentifierQuery = graphql(`
	query {
		chainIdentifier
	}
`);

function ChainIdentifier() {
	// Result types flow through the other client's own hooks and methods
	const { data } = useQuery(chainIdentifierQuery);

	return <span>{data?.chainIdentifier}</span>;
}

Handling errors

query returns { data, errors } rather than throwing on GraphQL errors, because a response can be partially successful, where some fields resolve and others fail. Check errors before trusting data:

const { data, errors } = await client.query({ query: chainIdentifierQuery });

if (errors?.length) {
	throw new AggregateError(errors.map((error) => new Error(error.message)));
}

A transport-level failure (a non-2xx response) throws SuiGraphQLRequestError instead.

Named queries

Pass a queries map when constructing the client and call them by name with execute. This keeps query documents in one place instead of threading them through your call sites:

const client = new SuiGraphQLClient({
	url: 'https://graphql.mainnet.sui.io/graphql',
	network: 'mainnet',
	queries: {
		getSuinsName,
		chainIdentifier: chainIdentifierQuery,
	},
});

const result = await client.execute('getSuinsName', {
	variables: { address: '0xabc...' },
});

Results and variables stay typed from the document the name resolves to.

Reading your own writes

GraphQL reads an index that trails execution slightly, so a transaction executeTransaction has already returned might not appear in a query for a moment. Use waitForTransaction before reading back a transaction's effects.

On this page