A blockchain node grows, and that growth is not a bug. Every block adds data, every state change adds trie entries, and a node that validates the chain must keep the recent state available to check the next block. The problem is only that disks are finite, and a node that fills its disk stops syncing, stops serving, and can corrupt data if it dies mid-write. Pruning is the controlled answer: it removes old state and history that a full node no longer needs to validate the current chain tip, while keeping the recent state, the block headers, and the data your apps actually query.
Pruning is not deleting the node and starting again, and it is not the same as wiping the data directory. Those are different operations with different costs, and confusing them is how operators lose a day of sync time, or an archival dataset they cannot rebuild. This post draws the line between the three, then gives a safe sequence that works across clients, with the Geth commands as the concrete example, because Geth documents its pruning path clearly.
What pruning removes, and what it keeps
A full node keeps two kinds of data that grow differently. Recent state is the current balances, contract storage, and trie nodes needed to validate new blocks. Historical state is the state at old blocks, which a full node does not need once it has moved past them, unless an app asks for a historical query. State pruning removes old state entries that are no longer reachable from recent blocks, while keeping recent state intact. History pruning, under the EIP-4444 approach now supported by major execution clients, removes old block history beyond a retention window, while keeping headers and current state so the node can still validate the chain head.
What pruning keeps is just as important. A pruned full node still validates new blocks, still serves current state, and still follows the chain tip. What it loses is the ability to answer historical queries for the pruned range. If your app, indexer, or explorer needs a balance at a block from last year, a pruned node cannot answer it, and no setting will bring that data back without a resync or an archival source. That is the first decision in any pruning plan: list the oldest historical query your system must answer, and do not prune past it. If you cannot list it, assume you need archival data somewhere, and prune only a node that is not the archival source.
The safe sequence, before you touch anything
Start with backups that are separate from the data you are about to prune. Back up the keystore and validator keys, if the host holds any, to an offline or encrypted store, and verify the backup can be read, because a pruning accident that also takes keys is a different incident. Back up the node configuration, the client version, the data directory path, and any custom flags, so a rebuild reproduces the same node instead of a guessed one. Then confirm the node is fully synced and healthy, with peers connected and no sync warnings, because pruning a node that is already behind or unhealthy mixes two problems and makes both harder to diagnose.
Next, free the easy space first and measure the result. Check disk use by directory, not just by total, so you know whether the growth is chain data, logs, or something else entirely, such as an unbounded log file that pruning will never fix. Rotate and cap logs, remove old client binaries and test data, and confirm the disk trend after the cleanup. Set a disk alert well before the disk fills - alerting at 80 percent full is a common starting point, with a second alert for fast growth - so pruning becomes a planned job, not a midnight emergency. A node that is pruned only when it is already full is a node that will be pruned again soon, under worse conditions.
Geth pruning: the concrete example
For Geth, the documented state-pruning path uses the snapshot prune command against a fully synced node that has a state snapshot available. In outline, the operator stops the node cleanly, runs the prune command against the data directory, and waits for it to finish, through its stages of iterating the snapshot, pruning state data, and compacting the database. Pruning can take hours, commonly several hours on slower disks, and the compacting stage can look hung for a long stretch. Do not interrupt or restart it in that stage: interrupting a database compaction is how a planned prune becomes a resync.
# Stop the node cleanly first, then prune (check the Geth docs for your version):
geth --datadir /var/lib/geth snapshot prune-state
# For a fresh start instead of a prune, removedb wipes chain data.
# It is not a prune: use it only when a resync is the plan.
geth --datadir /var/lib/geth removedb
Treat removedb as a different tool, not a stronger prune. It wipes the chain data directories, and while it leaves the keystore alone, it still means a full resync afterwards, which can take days depending on the chain, the client, and the hardware. Use removedb when the data is corrupt, the client version changed in a way that requires a fresh sync, or you have deliberately decided to rebuild. Never use it as a disk-space fix on a production node, and never delete chain data by hand with a recursive remove unless you have already decided the node is disposable and rebuildable, because hand deletion skips every safety check the client provides.
After pruning: verify, then change the plan
After pruning finishes, restart the node and verify before you call the job done. Confirm the node syncs to the chain tip, serves the queries your app needs, and shows healthy peers, logs, and disk use. Run the same sync check from the earlier node health post: chain tip lag, peer count, and a real query your app makes, not just a process-is-running check. If the node serves an app, test that app end to end, because a node that syncs but cannot answer a historical query your app makes has traded one failure for another, and you need to know that in the maintenance window, not in production traffic.
Finally, change the plan so pruning is not a recurring emergency. Set a retention policy per node type: pruned full nodes for validation and current-state RPC, archival nodes for history, with separate disks and separate alerts. Where the client supports it, set history retention explicitly at setup, so old history is pruned automatically within a window you chose, instead of growing until someone notices. And keep one node, or one provider, that can answer historical queries, even if your main nodes are pruned, because the first historical query after a prune is always urgent. If disk growth, pruning, and archival planning are eating operator time, node operations and cloud cost optimization cover storage planning and monitoring, starting with a free infra audit. Bring your disk trend, your client and version, and your oldest required historical query: those three facts set the pruning policy.
Disclaimer: This post is educational only, not financial advice. Figures are listing or project data as of 2026-11-02 and may change - always confirm version numbers, requirements, and dates in the official docs before acting on them.
