Skip to main content

Running the Archival Store and Service

The Archival Store and Service are part of the Sui data access infrastructure. The stack provides long-term storage and low-latency point lookups of historical on-chain data through a gRPC service backed by Google Cloud Bigtable. This stack is optimized for operators and data providers who need to serve historical transactions, checkpoints, objects, and epoch data beyond the retention horizon of full nodes or indexer databases.

The Archival Service exposes the same gRPC LedgerService API as a Sui full node, so existing gRPC clients can query it by changing the endpoint. The service is powered by an indexer (sui-kvstore-alt) that reads checkpoints from the remote checkpoint store and writes processed data to Bigtable, and a gRPC server (sui-kv-rpc) that reads from Bigtable to serve client requests.

See Archival Store and Service for more information on the stack.

Architecture overview

The archival stack consists of three components:

  1. Google Cloud Bigtable: The backing store that holds all historical chain data across 11 tables.
  2. sui-kvstore-alt (Indexer): Reads checkpoints from the remote checkpoint store and writes processed data to Bigtable.
  3. sui-kv-rpc (Archival Service): A gRPC server that reads from Bigtable and exposes the LedgerService API to clients.
  • A Google Cloud Platform (GCP) project with the Bigtable API enabled.
  • Two GCP service accounts:
    • Read/write account for the indexer; requires roles/bigtable.user (the indexer both writes pipeline data and reads its own watermarks).
    • Read-only account for the gRPC service; requires roles/bigtable.reader.
  • Access to the Sui checkpoint buckets for your target network:
    • Mainnet: GCS bucket mysten-mainnet-checkpoints or https://checkpoints.mainnet.sui.io
    • Testnet: GCS bucket mysten-testnet-checkpoints or https://checkpoints.testnet.sui.io
  • A Sui full node with gRPC enabled. After the initial backfill, you can stream checkpoints from a full node instead of polling the bucket for lower latency. See Steady-state operation.

Authentication

Both the indexer and gRPC service authenticate to GCP using Application Default Credentials (ADC). The same credentials are used for Bigtable access and Google Cloud Storage (GCS) checkpoint bucket reads.

On Google Kubernetes Engine (GKE): Use Workload Identity to bind your pod's Kubernetes service account to a GCP service account. No keys or environment variables needed — the SDKs automatically fetch tokens from the metadata server.

Outside GKE: Set the GOOGLE_APPLICATION_CREDENTIALS environment variable to the path of a service account JSON key file:

export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json

The checkpoint buckets are publicly readable, but authenticated requests receive higher GCS rate limits than anonymous ones. Using --remote-store-gcs with valid credentials avoids throttling during backfill.

Bigtable setup

Create a Bigtable instance

Create a Bigtable instance in your GCP project. Refer to the Bigtable documentation for instructions.

Key decisions:

SettingRecommendation
Storage typeSSD is required. HDD has not been tested and is not recommended.
Node countMysten Labs currently runs 5 nodes for mainnet and 2 for testnet as a starting point. Scale up to 15 nodes for backfill. Your steady-state node count will depend on your read traffic — enable autoscaling or monitor CPU utilization and scale manually.

Replication: A single-cluster instance is the recommended default. If you need to serve read traffic in multiple regions, you can add clusters in other zones — Bigtable automatically replicates data across clusters, so you get low-latency reads in additional regions without running a separate indexing stack in each one. The tradeoff is that storage costs scale with the number of clusters (the data is stored in full in each cluster). Use single-cluster routing in your app profile for single-cluster instances, or multi-cluster routing to let Bigtable route requests to the nearest cluster.

Create tables

Create the following 11 tables, each with a single column family named sui and a GC policy that keeps only the latest cell version:

TableDescription
checkpointsCheckpoint summaries, signatures, and contents
checkpoints_by_digestCheckpoint lookup by digest
transactionsTransaction data, effects, events, and balance changes
objectsObject data keyed by object ID and version
epochsEpoch start and end data including system state
watermark_altInternal indexer watermark tracking
protocol_configsProtocol configuration per epoch
packagesPackage metadata keyed by original ID and version
packages_by_idPackage lookup by ID
packages_by_checkpointPackage lookup by checkpoint
system_packagesSystem package data

Using the cbt CLI:

for table in checkpoints checkpoints_by_digest transactions objects epochs \
watermark_alt protocol_configs packages packages_by_id \
packages_by_checkpoint system_packages; do
cbt -project <GCP_PROJECT> -instance <INSTANCE_ID> createtable "$table"
cbt -project <GCP_PROJECT> -instance <INSTANCE_ID> createfamily "$table" sui
cbt -project <GCP_PROJECT> -instance <INSTANCE_ID> setgcpolicy "$table" sui maxversions=1
done

Storage requirements

The storage footprint estimations below are based on the network as of early March 2026. These numbers are directional and will grow with network activity.

Mainnet (full history from genesis):

TableSize
transactions8.1 TB
objects4.4 TB
checkpoints832 GB
checkpoints_by_digest15 GB
watermark_alt1.5 GB
epochs83 MB
packagesTBD (not yet backfilled)
packages_by_idTBD (not yet backfilled)
packages_by_checkpointTBD (not yet backfilled)
protocol_configsTBD (not yet backfilled)
system_packagesTBD (not yet backfilled)
Total~13.3 TB

Testnet (full history from genesis):

TableSize
transactions2.5 TB
objects1.2 TB
checkpoints514 GB
checkpoints_by_digest18 GB
watermark_alt12 MB
epochs97 MB
packagesTBD (not yet backfilled)
packages_by_idTBD (not yet backfilled)
packages_by_checkpointTBD (not yet backfilled)
protocol_configsTBD (not yet backfilled)
system_packagesTBD (not yet backfilled)
Total~4.3 TB

The transactions and objects tables dominate storage. The packages, packages_by_id, packages_by_checkpoint, protocol_configs, and system_packages pipelines are new and have not yet been backfilled — their storage contribution will increase once backfill is completed. Growth rate scales with network transaction volume.

Scaling

Bigtable supports both manual and automatic node scaling. Mysten Labs uses manual scaling with CPU monitoring for better operational control, but autoscaling is a reasonable option if you prefer hands-off management.

Key thresholds to monitor:

  • CPU utilization: Scale up if sustained above 60% (mixed read/write) or 90% (write-only).
  • Storage utilization: Each SSD node supports up to 5 TB, but Google recommends staying under 70% (3.5 TB per node) to accommodate spikes. Ensure your cluster has enough nodes for both compute and storage needs.

Backup policy

Configure automated backups for disaster recovery. A daily backup with 7-day retention is a reasonable default. See the Bigtable backup documentation for setup instructions.

Indexer setup

The indexer (sui-kvstore-alt) reads checkpoints from the remote checkpoint store and writes data to Bigtable through 12 parallel pipelines.

Hardware requirements

Steady-state (at network tip):

  • CPU: 1 core per instance (conservative — observed usage is ~0.1-0.2 cores)
  • Memory: 1 GB per instance (conservative — observed usage is ~50 MB)

Backfill:

  • CPU: 16 cores
  • Memory: 32 GB

Run sui-kvstore-alt

sui-kvstore-alt \
--config <CONFIG_FILE> \
--chain <CHAIN> \
<INSTANCE_ID> \
--remote-store-gcs <REMOTE_STORE_GCS_BUCKET>
CLI parameterRequiredDescription
--configNoPath to TOML configuration file. If omitted, framework defaults are used. See Indexer configuration.
<INSTANCE_ID>YesBigtable instance ID.
--chainYesChain identifier: mainnet, testnet, or unknown.
--remote-store-gcsOne source requiredGCS bucket name to fetch checkpoints from (recommended for backfill). Mutually exclusive with other source flags.
--remote-store-urlOne source requiredHTTPS URL of the remote checkpoint store (alternative to --remote-store-gcs). Mutually exclusive with other source flags.
--rpc-api-urlOne source requiredFullnode gRPC URL to fetch checkpoints from (for steady-state). Mutually exclusive with other source flags.
--streaming-urlNoFullnode gRPC URL for streaming live checkpoints. Used alongside --rpc-api-url for lowest latency at the network tip.
--bigtable-projectNoGCP project ID. Defaults to the project associated with the service account credentials.
--app-profile-idNoBigtable app profile ID for routing.
--write-legacy-dataNoDo not set this. Enable writing deprecated data formats.
--first-checkpointNoCheckpoint to start indexing from. Defaults to 0 (genesis).
--last-checkpointNoCheckpoint to stop indexing at. Useful for bounded backfill jobs.
--metrics-addressNoPrometheus metrics bind address. Default: 0.0.0.0:9184.

Example (backfill from GCS bucket)

sui-kvstore-alt \
--config kvstore.toml \
--chain mainnet \
my-bigtable-instance \
--remote-store-gcs mysten-mainnet-checkpoints

Example (steady-state from fullnode)

sui-kvstore-alt \
--chain mainnet \
my-bigtable-instance \
--rpc-api-url http://my-fullnode:9000 \
--streaming-url http://my-fullnode:9000

Indexer configuration

The indexer accepts an optional TOML configuration file via --config. For tip-of-chain indexing, the framework defaults are a good starting point and you can omit the flag entirely. Configuration tuning is primarily needed during backfill.

Top-level options

OptionDefaultDescription
total-max-rows-per-secondunlimitedGlobal rate limit shared across all pipelines (rows/sec). Set this during backfill to avoid overwhelming Bigtable.
max-rows-per-secondunlimitedDefault per-pipeline rate limit (rows/sec). Both this and total-max-rows-per-second are enforced, so you can use per-pipeline limits to prevent one pipeline from starving others. In practice this is not been needed and you can omit it.
bigtable-connection-pool-size10Number of gRPC channels in the Bigtable connection pool. Rule of thumb: 2x your Bigtable node count.
bigtable-channel-timeout-ms60000Channel-level timeout for Bigtable gRPC calls (ms).

Committer settings ([committer])

These control how each pipeline flushes data to Bigtable. Set at the top level to apply to all pipelines, or per-pipeline to override (see below).

OptionDefaultDescription
write-concurrency5Number of concurrent write tasks per pipeline. Increase for high-throughput pipelines during backfill.
collect-interval-ms500How often to flush buffered rows (ms).
watermark-interval-ms500How often to update the pipeline watermark (ms).

Per-pipeline overrides ([pipeline.<name>])

Each of the 12 pipelines can override the global settings. Use [pipeline.<name>] for pipeline-level options and [pipeline.<name>.committer] for committer overrides:

[pipeline.objects]
max-rows-per-second = 50000

[pipeline.objects.committer]
write-concurrency = 40
OptionDescription
max-rowsMaximum rows per Bigtable batch for this pipeline.
max-rows-per-secondPer-pipeline rate limit, overriding the global max-rows-per-second.
committer.*Any committer field (write-concurrency, collect-interval-ms, watermark-interval-ms) can be set per pipeline.

For recommended backfill configuration for a 15-node cluster, see Backfill rate limit sizing.

Additional advanced options (channel sizes, fanout concurrency, backpressure thresholds, ingestion settings) are available but rarely need tuning. See Pipeline architecture — Performance tuning for the full reference.

Pipelines

The indexer runs 12 pipelines in parallel. All pipelines are required for full archival service functionality:

PipelineTarget tableDescription
kvstore_checkpointscheckpointsCheckpoint summaries, signatures, and contents.
kvstore_checkpoints_by_digestcheckpoints_by_digestCheckpoint digest-to-sequence-number mapping.
kvstore_transactionstransactionsTransactions with effects, events, and balance changes.
kvstore_objectsobjectsObject data for each output object at each version.
kvstore_epochs_startepochsEpoch start data including system state and gas price.
kvstore_epochs_endepochsEpoch end data.
kvstore_protocol_configsprotocol_configsProtocol configuration snapshots per epoch.
kvstore_epoch_legacyepochsLegacy epoch data format (requires --write-legacy-data).
kvstore_packagespackagesPackage metadata keyed by original package ID and version.
kvstore_packages_by_idpackages_by_idPackage lookup by package ID.
kvstore_packages_by_checkpointpackages_by_checkpointPackages published in each checkpoint.
kvstore_system_packagessystem_packagesSystem package data.

Backfill

To index from genesis, start the indexer without --first-checkpoint. A full mainnet backfill takes approximately 2–3 days with a 15-node SSD cluster and a 16 CPU indexer.

For backfill, use a single indexer instance — one instance can generate enough load to fully saturate a 15-node cluster. The 16 CPU / 15-node configuration is the largest scale Mysten Labs has tested. Larger instance types and cluster sizes may work but could hit software bottlenecks that have not been identified yet.

  1. Scale up the Bigtable cluster to 15 nodes before starting the backfill.
  2. Run one indexer instance on a larger machine (16 CPU / 32 GB RAM) with aggressive rate limits (~150,000 rows/sec), using the checkpoint bucket as the data source.
  3. Once the backfill catches up to the network tip, switch to steady-state (see Steady-state operation below).
  4. Scale down the Bigtable cluster to 5 nodes.

From there, monitor cluster CPU utilization and scale nodes as needed — either with Bigtable autoscaling or by monitoring and scaling manually.

Backfill rate limit sizing

The rate limit you set in the TOML configuration should be based on your Bigtable cluster size. Each Bigtable SSD node can sustain approximately 111 rows/sec per 1% CPU utilization. Google recommends targeting:

  • 90% CPU for write-only backfill (no concurrent read traffic)
  • 60% CPU if the cluster is also serving reads during backfill
ScenarioTarget CPURows/sec per node5 nodes10 nodes15 nodes
Write-only backfill90%~10,000~50,000~100,000~150,000
Backfill while serving reads60%~6,700~33,500~67,000~100,000

These numbers are a guideline. For new write-only clusters being backfilled, you can set the rate limit to the table values above. For clusters that are already serving read traffic, start lower, monitor CPU utilization, and increase the rate limit gradually.

Set total-max-rows-per-second in your TOML config accordingly. Save the following as your backfill config file (e.g. backfill.toml) and pass it via --config backfill.toml. This example targets a 15-node write-only backfill:

# Assumes a 15-node cluster targeting 90% CPU utilization (write-only).
# Scale linearly for smaller clusters, e.g. 50000 for 5 nodes, 100000 for 10.
total-max-rows-per-second = 150000
bigtable-connection-pool-size = 30

[pipeline.objects.committer]
write-concurrency = 40

[pipeline.transactions.committer]
write-concurrency = 20

[pipeline.checkpoints.committer]
write-concurrency = 10

[pipeline.checkpoints_by_digest.committer]
write-concurrency = 10

The default write-concurrency is 5, which is sufficient for the smaller pipelines. Only the high-throughput pipelines (objects, transactions, checkpoints, checkpoints_by_digest) need higher concurrency during backfill.

Checkpoint-range sharding

You can parallelize backfill across multiple indexer instances by splitting the checkpoint range using --first-checkpoint and --last-checkpoint. Each instance processes a different range independently.

Steady-state operation

Once the backfill is complete and the indexer has caught up to the network tip, switch from the checkpoint bucket to streaming from a fullnode for the best latency. Replace --remote-store-url with --rpc-api-url and --streaming-url pointing to your fullnode's gRPC endpoint:

sui-kvstore-alt \
--chain mainnet \
my-bigtable-instance \
--rpc-api-url http://my-fullnode:9000 \
--streaming-url http://my-fullnode:9000

No --config is needed. The framework defaults are sufficient for steady-state indexing. The full node only needs gRPC enabled. JSON-RPC is not required. Mysten Labs runs full nodes with a 2-week retention period and only uses the checkpoint bucket for backfills.

If you want to set a rate limit at steady state, there is a tradeoff to consider. Write throughput is naturally bounded by the chain, but if the indexer crashes and needs to catch up, it will ingest as fast as possible from the full node. Without a rate limit it catches up faster but may briefly impact read latency while writing older data. With a rate limit, read latency stays stable but recovery takes longer.

info

Mysten Labs plans to enable requester-pays on the public checkpoint buckets in the future. Streaming from your own full node avoids these costs.

Running multiple instances

Bigtable writes are idempotent, so multiple indexer instances can safely process the same data. Mysten Labs runs 3 indexer instances at steady state to enable rolling deployments without ever delaying updates from the chain.

During backfill, a single instance is sufficient. One instance can saturate a 15-node cluster.

Archival Service setup

The archival service (sui-kv-rpc) is a gRPC server that reads from Bigtable and exposes the LedgerService API.

Resource requirements depend on your read traffic. Monitor CPU and memory utilization and scale accordingly.

Run sui-kv-rpc

sui-kv-rpc \
<INSTANCE_ID> \
<ADDRESS>
CLI parameterRequiredDescription
<INSTANCE_ID>YesBigtable instance ID.
<ADDRESS>NogRPC listen address. Default: [::1]:8000.
--credentialsNoPath to GCP service account JSON key file. If not provided, uses Application Default Credentials.
--tls-certNoPath to TLS certificate PEM file.
--tls-keyNoPath to TLS private key PEM file.
--bigtable-projectNoGCP project ID. Defaults to the project associated with the service account credentials.
--app-profile-idNoBigtable app profile ID.
--checkpoint-bucketNoGCS bucket for full checkpoint data (enables richer checkpoint responses).
--bigtable-channel-timeout-msNoChannel-level timeout for Bigtable gRPC calls in milliseconds. Default: 60000.

Example

sui-kv-rpc \
my-bigtable-instance \
"[::]:8000" \
--credentials /etc/sui-kv-rpc/bigtable-ro-sa.json \
--tls-cert /secrets/cert.pem \
--tls-key /secrets/key.pem

gRPC API

The archival service implements the LedgerService gRPC API, which is the same API exposed by Sui full nodes. Existing gRPC clients can query the archival service by changing the endpoint URL.

MethodDescriptionBatch limit
GetServiceInfoReturns chain ID, current epoch, latest checkpoint, and server version.
GetObjectLook up an object by ID, optionally at a specific version.
BatchGetObjectsBatch object lookup. Requires exact versions.1000
GetTransactionLook up a transaction by digest.
BatchGetTransactionsBatch transaction lookup.200
GetCheckpointLook up a checkpoint by sequence number or digest.
GetEpochLook up epoch data by epoch number.

All methods support field masking via the read_mask parameter to reduce response size.

gRPC server reflection is enabled (both v1 and v1alpha), allowing tools like grpcurl and Postman to discover the API schema.

Health check

The service exposes an HTTP health check endpoint at GET /health on port 8081.

TLS

For production deployments, enable TLS by providing --tls-cert and --tls-key. The service expects PEM-encoded certificate and private key files.

Monitoring

Both the indexer and archival service export Prometheus metrics on port 9184 at /metrics.

The indexer uses the same indexer framework metrics as the general-purpose Postgres indexer (ingestion, pipeline, watermark, and commit metrics), with a kvstore_alt_ prefix and pipeline-specific labels. If you already operate the Postgres indexer stack, the same dashboards and alerts apply.

Prometheus scrape configuration

scrape_configs:
- job_name: sui-kvstore
static_configs:
- targets: ['<INDEXER_HOST>:9184']
- job_name: sui-kv-rpc
static_configs:
- targets: ['<RPC_HOST>:9184']

Archival service metrics

The archival service exports the following metrics:

MetricTypeDescription
rpc_request_latencyhistogramEnd-to-end request latency.
rpc_requestscounterRequest count, labeled by status.
rpc_inflight_requestsgaugeConcurrent requests in flight, labeled by path.
kv_get_latency_mshistogramBigtable read latency per batch request, labeled by table.
kv_get_latency_ms_per_keyhistogramBigtable read latency divided by batch size, labeled by table.
kv_scan_latency_mshistogramBigtable scan latency, labeled by table.
kv_bt_chunk_latency_mshistogramBigtable internal processing time per response chunk, labeled by table.
kv_get_successcounterSuccessful Bigtable reads, labeled by table.
kv_scan_successcounterSuccessful Bigtable scans, labeled by table.
thread_stall_duration_sechistogramTokio thread stall duration.
EnvironmentRUST_LOG
Productioninfo
Debugginginfo,sui_kvstore=debug,sui_indexer_alt_framework=debug