Plan disk for an xOne node in three steps. Pick the sync mode and read its measured datadir size. Size the filesystem so that free space stays above the 15% alert line. Then learn what the node does at its own lines: stop import at 2% free, resume at 3%, exit at 1%.
No xOne repository publishes a disk recommendation. The hardware and disk post lists the limits. The storage layout post explains the files. The xOneTS, xOnePy and xOneC repositories are private.
Which two disk lines does an xOne node have?
The node has its own watermark, and Prometheus has a separate alert. The alert fires first, at less than 15% free. The node stops import at 2% or 2 GiB free.
| Line | Free space | Effect |
|---|---|---|
Alert XoneDiskAlmostFull |
below 15% for 10 minutes | Warning. You act. |
Alert XoneDiskCapacityUnknown |
no datadir filesystem series for 10 minutes | Warning. node_exporter is down or the regex matches nothing. |
| Resume | above 3% or 3 GiB | Import runs again (disk_ok). |
| Stop | below 2% or 2 GiB | Import stops at a block boundary (disk_low). |
| Exit | below 1% or 1 GiB, two samples in a row | Clean stop, exit code 4 (disk_full). |
Each node line is the larger of its percent and its byte floor. The node samples the datadir filesystem every 5 seconds with df -P -k. The first sample runs before any writer starts. The defaults are in config.rs and diskguard.rs. The alerts are in alerts.yml.
ADR-007 is still proposed. It proposes higher lines than the code uses. For alert setup, see node monitoring.
How much free space does the filesystem need?
Size the filesystem so that the datadir plus planned growth fills at most 85% of it. Then free space stays above the 15% alert line. The alert line sits well above the node lines.
This is arithmetic on the lines above, not a recommendation:
| Filesystem | Stop | Resume | Exit | Alert (15%) |
|---|---|---|---|---|
| 1 TiB | 20.48 GiB | 30.72 GiB | 10.24 GiB | 153.6 GiB |
On a filesystem below 100 GiB the byte floors win. Above it the percents win. Minimum filesystem size = (datadir + growth) / 0.85.
Example. The net2040 archive datadir was 22.78 GB at the sample below. Growth was about 410 MB per 100,000 blocks over a range of mostly empty blocks, so 4.1 GB for 1,000,000 blocks. Then (22.78 + 4.1) / 0.85 = 31.6 GB. Dense blocks cost more: measure your own rate.
How big is the datadir in each sync mode?
Snap and minimal datadirs were 0.09 to 0.15 GB on net2040. Full and archive datadirs were 17.99 to 22.78 GB. On Apothem the xOne snap datadirs were 31.12 to 75.11 GB.
Source: xOne team measurement, 2026-11-14 19:20 UTC, one sample. The method was du -sx --block-size=1 on the datadir, shown here in decimal GB. The reference head was 841,381 on net2040 and 85,385,427 on Apothem.
| Network | Client and mode | Datadir |
|---|---|---|
| net2040 | xOneRS full | 20.64 GB |
| net2040 | xOneRS archive | 22.78 GB |
| net2040 | xOneRS fast, minimal | 0.15 GB each |
| net2040 | xOneTS full | 19.56 GB |
| net2040 | xOneC full, archive | 17.99 GB, 22.22 GB |
| net2040 | xOneC snap, minimal | 0.14 GB each |
| net2040 | xOnePy snap, minimal | 0.09 GB each |
| Apothem | xOneRS snap | 75.11 GB |
| Apothem | xOnePy snap | 31.12 GB |
| Apothem | xOneC snap | 51.05 GB |
The two xOneRS Apothem nodes are different nodes and builds. Do not average them. Until you have your own number, plan Apothem at the largest value. For the modes, see archive mode.
How fast does an xOne datadir grow?
Main has one growth record: the net2040 archive run in docs/ops/archive.md. It has no Apothem growth rate and no per-day figure.
| Range (sampled every 5 minutes, 2026-11-14) | chain.mdbx |
Whole datadir |
|---|---|---|
| 0 to 215k (blocks of 20,000+ transactions up to ~50k) | 4.56 GB | 20.3 GB |
| 215k to 793k (mostly empty blocks) | +0.47 GB, about 81 MB per 100k blocks | +2.38 GB, about 410 MB per 100k blocks |
| at 832,598 | 5.03 GB | 22.8 GB |
ADR-007 still asks for the daily growth before its disk values are final (question 3). To get yours, read the datadir size and the head block twice, hours apart:
du -sx --block-size=1 <datadir>
curl -s -H 'content-type: application/json' \
--data '{"jsonrpc":"2.0","id":1,"method":"eth_blockNumber","params":[]}' <rpc-url>
The size change divided by the block change gives bytes per block. Repeat it in a quiet range and a busy range.
What do segment files and the MDBX map limit?
Segment files hold headers, bodies and receipts, one file per 100,000 blocks. --datadir.ancient <path> moves them to another disk. --db.max-size (default 1TB) caps the MDBX map, and --db.growth-step (default 64MB) sets its growth step.
- Segments: the directories are
static/headers,static/bodiesandstatic/receipts. The path is recorded in the datadir. A wrong or missing path refuses to start (flags.md). - Second disk: the disk guard receives the datadir path only, so it does not sample a separate segment disk. Extend the mountpoint regex in
prometheus.ymlso it labels both filesystemsdatadir="true". - MDBX: the bounds are
16MBto8TB. Startup refuses an existingmdbx.datlarger than--db.max-size. A full map fails the write with an error that names the flag. Committed data stays intact. Restart with a larger value (db-geometry.md).
What do I do at each line?
Act at the alert, before the stop line. At disk_low, free space and the node resumes alone. At disk_full, free space and restart.
XoneDiskAlmostFull: grow the filesystem or free space on it.xone doctorwarns below the resume line and fails below the stop line.XoneDiskCapacityUnknown: check thenodejob and its mountpoint regex inprometheus.yml.disk_low: import has stopped and the producer refuses to seal ("disk low: block production paused"). RPC reads, serving and consensus timers continue. A validator cannot vote on blocks it lacks, so treat it as a "not producing" alarm. The log showsdisk_okabove the resume line.disk_full: the node stopped with exit code 4. Free space, runxone doctor, start again.
To move the lines, set the six limits.disk_{stop,resume,exit}_{pct,min_bytes} keys. Keep exit < stop < resume. A misordered set refuses to start. Example values only:
[limits]
disk_exit_pct = 3
disk_stop_pct = 5
disk_resume_pct = 7
How do other clients handle disk limits?
Geth also moves history files to another disk. Nethermind documents a low-disk shutdown threshold. The table compares features, not sizes.
| Client | What its documentation says | xOne |
|---|---|---|
| geth | The freezer moves with --datadir.ancient, as stated in Geth databases. |
--datadir.ancient moves static/. |
| nethermind | A low-disk shutdown threshold (LowStorageSpaceShutdownThreshold), as stated in the health check docs, no date listed. |
Exit at 1% or 1 GiB free, code 4. |
Correction
On 2026-11-15 we removed an Apothem row that was labelled "xOneRS snap (second node)". That node reports the version xOne/v1.1.0/linux-amd64/go1.25.0: it runs xOneGo, the earlier Go line, not xOneRS. The other rows are unchanged.
Frequently asked questions
How much disk does an xOne node need?
No xOne repository publishes a figure. One sample measured 20.64 GB for an xOneRS full node on net2040 and 0.15 GB in fast or minimal mode. Size the filesystem so that datadir plus growth fills at most 85%.
When does an xOne node stop importing blocks?
It stops below 2% or 2 GiB free, whichever is larger. It exits with code 4 below 1% or 1 GiB.
Can I put xOne segment files on another disk?
Yes. Use --datadir.ancient <path>. The node's own watermark does not sample that disk, so alert on it too.
Sources
- xOneRS: config.rs, diskguard.rs, ADR-007, ADR-005, alerts.yml, monitoring.md, archive.md, db-geometry.md, flags.md
- Datadir sizes: xOne team measurement, 2026-11-14 19:20 UTC, one sample.
This article describes the source and evidence at its review date. Check the linked repository for current implementation and qualification status.
Explore the engineering evidenceEdit this page on GitHub opens the Markdown source (content/blog/disk-planning-xone/index.md). GitHub may ask you to sign in. Report a correction opens a prefilled GitHub issue for this page.