Sui RPC gateways meter requests by estimated compute units per method, with rolling windows and cost headers. Heavy queries like queryTransactionBlocks and multiGetCoins dominate cost. This article explains the mechanism, provides runnable TypeScript SDK examples for pagination and cost-shaping, and discusses handling 429s with backoff, plus the evolving shift to GraphQL.
Direct Answer: What You Need to Know About Sui RPC Rate Limits
Sui RPC rate limits are not simply a fixed number of requests per second. The Sui gateway estimates a compute unit cost for each method, and your usage is metered against a rolling window. Heavy methods like queryTransactionBlocks and multiGetCoins consume far more units than lightweight calls like getObject. When you exceed your allotted units, you receive HTTP 429 responses. To manage cost and avoid 429s in production, you must shape your queries: use pagination, avoid deep vertical pagination, and prefer GraphQL as it becomes the recommended interface.
This article explains the compute-unit accounting mechanism, shows how to write cost-efficient queries with the Sui TypeScript SDK, and provides a backoff strategy for handling 429s. We also cover the documented public RPC rate-limit changes announced by the Sui Foundation and the ongoing transition from legacy JSON-RPC to GraphQL.
How Sui RPC Compute Units Work
The Sui gateway assigns an estimated compute unit cost to each RPC method. This estimate reflects the server-side work required to fulfill the request. For example, queryTransactionBlocks with a large page size can scan many transactions, while multiGetCoins fetches multiple coin objects in one call. The exact unit values are not publicly documented in a fixed table, but the Sui documentation on RPC best practices notes that certain methods are more expensive and recommends pagination to limit the load.
The gateway enforces rate limits using a rolling window. Instead of a simple per-second counter, you are allocated a budget of compute units over a sliding time window (e.g., per minute or per hour). Each request deducts its estimated cost from your current budget. When the budget is exhausted, the gateway returns a 429 with a Retry-After header or a similar indication. The response headers include x-sui-rpc-units (or similar) to show the cost of the request, allowing you to monitor your consumption.
It's important to note that these unit values are estimates, not exact measurements. The actual load may vary based on the state of the network and the size of the data returned. Therefore, treat the unit values as a guide for shaping your queries, not as a precise billing meter.
- Heavy methods:
queryTransactionBlocks,queryEvents,multiGetTransactionBlocks,multiGetCoins - Light methods:
getObject,getBalance,getChainIdentifier - Rolling window: budget of compute units over a sliding time period
- Headers:
x-sui-rpc-units(or similar) indicate cost per request
Pagination: Vertical vs Horizontal
Pagination is the primary tool for controlling compute unit consumption. Sui RPC methods like queryTransactionBlocks and queryEvents return a nextCursor that you can use to fetch the next page. There are two pagination strategies: vertical and horizontal.
Vertical pagination means fetching a large number of items in a single request by setting a high limit (e.g., 1000). This is efficient in terms of round trips but can be expensive in compute units because the gateway must process and serialize a large payload. Horizontal pagination means using a smaller limit (e.g., 50) and making multiple requests to page through the data. This spreads the load over multiple requests, each with a lower unit cost, and is generally recommended by the Sui documentation to avoid timeouts and rate limits.
The Sui documentation on RPC best practices explicitly advises using pagination and avoiding large page sizes. For example, when querying transaction blocks, use a limit of 50 or less, and always follow the nextCursor until it returns null. This approach reduces the peak compute unit consumption per request and makes your usage more predictable.
Runnable Example: Cost-Shaping Queries with the Sui TypeScript SDK
Below is a self-contained example using the Sui TypeScript SDK. It demonstrates how to query transaction blocks with horizontal pagination, how to fetch multiple coins with multiGetCoins, and how to handle 429s with exponential backoff. The example uses the public Sui Testnet endpoint, but you can replace it with your own RPC URL from OnFinality's Sui network page.
The code first creates a SuiClient with a custom fetch wrapper that intercepts 429 responses and retries with backoff. Then it defines a function to query transaction blocks in pages of 50, printing the digest and the compute units header if available. Finally, it demonstrates multiGetCoins with a list of coin object IDs.
import { SuiClient, getFullnodeUrl } from '@mysten/sui/client';
// Custom fetch wrapper to handle 429 with exponential backoff
async function fetchWithRetry(url: string, options: any, retries = 3): Promise<Response> {
let attempt = 0;
while (attempt <= retries) {
const response = await fetch(url, options);
if (response.status === 429 && attempt < retries) {
const retryAfter = response.headers.get('retry-after');
const delayMs = retryAfter ? parseInt(retryAfter) * 1000 : Math.pow(2, attempt) * 1000;
console.log(`429 received, retrying in ${delayMs}ms`);
await new Promise(resolve => setTimeout(resolve, delayMs));
attempt++;
continue;
}
return response;
}
throw new Error('Exhausted retries due to 429');
}
// Create a SuiClient with the custom fetch
const client = new SuiClient({
url: getFullnodeUrl('testnet'), // Replace with your own RPC URL
fetch: fetchWithRetry as any,
});
// Horizontal pagination for queryTransactionBlocks
async function queryAllTransactionBlocks() {
let cursor: string | null = null;
let hasNextPage = true;
while (hasNextPage) {
const page = await client.queryTransactionBlocks({
cursor,
limit: 50, // small page size to control compute units
order: 'descending',
});
console.log(`Fetched ${page.data.length} blocks, nextCursor: ${page.hasNextPage ? page.nextCursor : 'null'}`);
// Process each block digest
for (const block of page.data) {
console.log(block.digest);
}
// Check for next page
if (page.hasNextPage && page.nextCursor) {
cursor = page.nextCursor;
} else {
hasNextPage = false;
}
}
}
// Example of multiGetCoins (heavy method)
async function getMultipleCoins(coinIds: string[]) {
const coins = await client.multiGetCoins({ ids: coinIds });
console.log(`Fetched ${coins.data.length} coins`);
for (const coin of coins.data) {
console.log(coin.coinObjectId, coin.balance);
}
}
// Run the example
async function main() {
await queryAllTransactionBlocks();
// Replace with actual coin IDs
await getMultipleCoins(['0x...', '0x...']);
}
main().catch(console.error);Expected Results and How to Verify
When you run the example, you should see a series of log lines showing each page of transaction blocks. The queryTransactionBlocks call will return a nextCursor until all pages are exhausted. The multiGetCoins call will return the coin objects for the provided IDs.
To verify that your queries are cost-efficient, inspect the response headers. The Sui gateway includes a header like x-sui-rpc-units that indicates the compute units consumed by the request. You can log this header in your fetch wrapper to monitor your usage. For example, modify the fetchWithRetry function to print response.headers.get('x-sui-rpc-units') for each successful response.
Also, check the Retry-After header on 429 responses. The gateway may provide a suggested wait time. Our backoff logic uses that header if present, otherwise it falls back to exponential backoff (1s, 2s, 4s). This is a documented pattern for handling rate limits in HTTP APIs.
Common Failures and Fixes
One common failure is hitting 429s because you are using a large limit (e.g., 1000) in queryTransactionBlocks. The fix is to reduce the limit to 50 or less and use horizontal pagination. Another failure is not following the nextCursor correctly, leading to infinite loops or missing data. Always check hasNextPage and update the cursor only when it is not null.
Another issue is using multiGetCoins with a very large array of coin IDs. This method is heavy because it fetches multiple objects in one call. If you have many coins, consider batching the IDs into smaller groups (e.g., 50 per call) to reduce the compute unit cost per request.
Finally, if you are using the legacy JSON-RPC interface, you may encounter rate limits that are stricter than the GraphQL interface. The Sui Foundation has announced changes to public RPC rate limits, and the recommendation is to migrate to GraphQL for better efficiency and lower costs. See the Sui forum announcement for details (note: this is an announcement record, not a benchmark).
Tradeoffs and Limitations
Horizontal pagination reduces compute unit consumption per request but increases the number of requests, which can still add up to a higher total unit consumption if you are paging through a large dataset. There is a tradeoff between request count and per-request cost. You should test different page sizes to find the sweet spot for your workload.
The compute unit values are estimates and may change as the Sui network evolves. The Sui documentation is the authoritative source for current best practices, but it does not publish a fixed table of unit costs. Therefore, you should monitor your actual usage via the x-sui-rpc-units header and adjust your queries accordingly.
The transition from JSON-RPC to GraphQL is ongoing. While GraphQL is more flexible and often more efficient, it has a different query syntax and requires a learning curve. The Sui documentation provides a migration guide, but you should test your queries thoroughly before switching in production.
Next Steps and Further Reading
To get the most out of Sui RPC, start by reviewing the Sui RPC Best Practices official documentation. Then, explore the OnFinality Sui RPC guide for provider-specific tips. If you are managing multiple endpoints, consider using OnFinality's RPC monitoring and failover to ensure high availability.
For production workloads, you may want to use a dedicated RPC service like OnFinality's API service to get higher rate limits and dedicated resources. Check the pricing page for options. Also, stay updated on the latest Sui RPC changes by following the Sui Developer Forum.
Finally, as the ecosystem moves toward GraphQL, start experimenting with the Sui GraphQL interface. The Sui GraphQL documentation provides examples and migration guides. By adopting these practices, you can manage costs and avoid 429s effectively.