Pruning
Sustainable disk usage requires IOTA full nodes to prune the information about historic object versions as well as historic transactions with the corresponding effects and events, including old checkpoint data.
Both transaction and object pruners run in the background. The logical deletion of entries from RocksDB ultimately triggers the physical compaction of data on disk, which is governed by RocksDB background jobs: the pruning effect on disk usage is not immediate and might take multiple days.
Testing indicates that aggressive pruning results in more efficient full node operation.
Types of Pruning
Object Pruning
IOTA adds new object versions to the database as part of transaction execution, which makes previous versions ready for garbage collection. Without pruning, this would result in database performance degradation and require large amounts of storage space. IOTA identifies the objects that are eligible for pruning in each checkpoint, and then performs the pruning in the background.
Transaction Pruning
Transaction pruning removes previous transactions and their effects from the database. IOTA periodically creates checkpoints, and each checkpoint contains the transactions that occurred during the checkpoint and their associated effects. IOTA performs transaction pruning in the background after checkpoints complete.
Index Pruning
Index pruning advances a watermark in the secondary index stores (JSON-RPC and gRPC) so older entries are no longer served by index-backed queries (for example iotax_getBalance(), dynamic-field lookups, and event queries). Without it, the index tables grow with every transaction. Index pruning is only relevant for nodes that have indexing enabled (enable-index-processing: true).
Pruning Parameters
Object pruning, transaction pruning, and index pruning are independent background tasks. Each task is gated by its own parameter, so you can enable or disable them individually:
| Pruning task | Controlling parameter | Enabled when |
|---|---|---|
| Object pruning | num-epochs-to-retain | value is not u64::MAX |
| Transaction pruning | num-epochs-to-retain-for-checkpoints | set to a value >= 2 |
| Index pruning | num-epochs-to-retain-for-indexes | set |
All pruning parameters are configured in fullnode.yaml. The following annotated block shows every parameter with its default value — copy it into your config and adjust as needed:
# Enable indexing of additional data (ownership, balances, events).
# Required for JSON-RPC and gRPC index queries. Default: true.
# Set to false for validators or nodes that do not serve RPC requests.
enable-index-processing: true
authority-store-pruning-config:
# Number of epochs to keep historic object versions. Controls object pruning.
# 0 — aggressive pruning (default). Prunes old versions as soon as
# possible. Lowest disk usage. Recommended for validators and full
# nodes that do not serve historic object queries.
# N (>= 1) — retains object versions from the last N epochs. Use this when
# the node must serve lookups by object ID + version.
# u64::MAX — disables object pruning entirely (18446744073709551615).
num-epochs-to-retain: 0
# Number of epochs to keep historic transactions, effects, events, and
# checkpoint data. Controls transaction pruning.
# unset / 0 / u64::MAX — transaction pruning disabled (default).
# N (>= 2) — prunes data older than current − N epochs. The
# minimum effective value is 2; IOTA always keeps
# the current and immediately prior epoch.
# num-epochs-to-retain-for-checkpoints: 2
# Number of epochs to retain entries in the secondary index tables (JSON-RPC
# and gRPC). Controls index pruning. Only relevant when indexing is enabled
# (enable-index-processing: true).
# unset — index pruning disabled (default).
# N (>= 7) — prunes index entries older than N epochs. Values below 7 are
# silently coerced to 7.
# num-epochs-to-retain-for-indexes: 7
# Number of recent per-epoch RocksDB databases to keep. Default: 3.
num-latest-epoch-dbs-to-retain: 3
# Trigger periodic compaction for SST files older than this many days.
# Reclaims disk space and avoids fragmentation. Default: 1 (when read from
# config). Set to "null" to disable periodic compaction entirely.
periodic-compaction-threshold-days: 1
# Maximum checkpoints processed in a single pruning batch (advanced). Default: 10.
max-checkpoints-in-batch: 10
# Maximum transactions processed in a single pruning batch (advanced). Default: 1000.
max-transactions-in-batch: 1000
# Spread pruning work evenly across the epoch to avoid I/O spikes. Default: true.
smooth: true
# Use the RocksDB compaction filter for object-table pruning. When disabled,
# a range-deletion approach is used. Do not toggle frequently — switching
# back to range deletion may leave some old versions unpruned. Default: false.
# enable-compaction-filter: false
# Delay (seconds) between consecutive pruner runs in aggressive mode
# (num-epochs-to-retain: 0). Optional. Default: unset.
# pruning-run-delay-seconds: null
Set an Archiving Watermark
If your full node is configured to upload committed information to an archive, you should ensure that pruning does not occur until after the corresponding data is uploaded. To do so, set use-for-pruning-watermark: true in the fullnode.yaml file as described in Archival fallback.
Configuration Examples
The following examples cover common operator use cases. Each example shows the key parameters for the scenario — parameters not listed use their defaults from the reference block above.
Validator or Minimal Full Node
This configuration keeps disk usage to a minimum. A node with this setup cannot answer queries that require indexing or historic data. It is the recommended setup for IOTA validators and for full nodes that do not serve RPC requests.
# Do not generate or maintain indexing of IOTA data on the node
enable-index-processing: false
authority-store-pruning-config:
# Aggressively prune historic object versions
num-epochs-to-retain: 0
# Prune historic transactions of past epochs
num-epochs-to-retain-for-checkpoints: 2
Full Node with Indexing but no History
This setup manages secondary indexing in addition to the latest state, but aggressively prunes historic data. A full node with this configuration:
- Answers RPC queries that require indexing, like
iotax_getBalance(). - Answers RPC queries that require historic transactions via a fallback to retrieve the data from a remote key-value store:
iota_getTransactionBlock(). - Cannot answer RPC queries that require historic object versions:
iota_tryGetPastObject().- The
showBalanceChangesfilter ofiota_getTransactionBlock()relies on historic object versions, so it cannot work with this configuration.
- The
authority-store-pruning-config:
# Aggressively prune historic object versions
num-epochs-to-retain: 0
# Prune historic transactions of past epochs
num-epochs-to-retain-for-checkpoints: 2
Full Node with Full Object History but Pruned Transaction History
This configuration manages the full object history while still pruning historic transactions. A full node with this configuration can answer all historic and indexing queries (using the transaction query fallback for transactional data), including the ones that require historic objects such as the showBalanceChanges filter of iota_getTransactionBlock().
The main caveat is that the current setup enables the transaction pruner to go ahead of the object pruner. The object pruner might not be able to properly clean up the objects modified by the transactions that have been already pruned. You should closely monitor the disk space growth on a full node with this configuration.
In addition to the regular (pruned) snapshots, the IOTA Foundation also maintains special RocksDB snapshots with the full history of object versions available for the operators using this configuration.
authority-store-pruning-config:
# No pruning of object versions (use u64::max for num of epochs)
num-epochs-to-retain: 18446744073709551615
# Prune historic transactions of the past epochs
num-epochs-to-retain-for-checkpoints: 2