How to Reduce Minecraft Backup Sizes and Backup Times

Faster and smaller Minecraft server backups

Every Minecraft server owner has that moment: you run tar -czf backup.tar.gz world, watch the progress bar crawl for four minutes, and then find a 1.2 GB file on a disk that is already 80 percent full. Multiply that by hourly backups and the whole plan collapses. This guide exists to fix that with numbers instead of opinions. We took a real Paper 26.2 world, ran twelve different backup approaches against it on the same machine, and recorded the size and wall-clock time of every one. Then we restored the archive and compared it byte for byte. The point is simple: you should be able to pick a backup method for your server in the next ten minutes and know exactly what it will cost you in disk and downtime.

It is written for server owners, administrators and plugin developers who already have a backup habit but suspect it is inefficient, and for the ones who skipped backups entirely because the last attempt ate their free space. The benchmark data below was collected on an Intel Core i5-13400F with 16 threads and 14 GB of RAM running Ubuntu 26.04, with all work done on one local SSD and a warm page cache. The source was a quiesced copy of the world, so every number measures the backup tool and nothing else.

Two findings up front, because they change how you plan. First, compression ratio barely matters here. Every tool landed between 143 and 146 MiB. Second, speed varies by more than thirty-fold between the worst and best option. Region data has limited redundancy, so what you should optimize is time and restore behavior, not the last two percent of size. Everything else in this article follows from those two facts.

Why Minecraft Backups Get Slow and Big

A Minecraft world is not a database of tidy rows. It is a pile of region files, each holding a 32×32 grid of chunks in a compressed NBT container, plus a parallel set of auxiliary data. Once you understand the layout, the performance numbers stop being surprising.

What is actually inside the world folder

  • dimensions/ is the bulk of it: in our test world, 228 MB of the 233 MB total. This holds overworld, the_nether and the_end, each with region/, entities/ and poi/ subfolders in the modern Paper layout.
  • .mca region files are already internally compressed with zlib, so recompressing them gains little. Our 106 region files barely changed size no matter what tool touched them. See the Minecraft Wiki region file format documentation for the structure.
  • entities/ and poi/ folders are small but critical. Item frames, chests, villagers and mob AI state live here. Missing them means duplicating or losing inventory contents on restore.
  • datapacks/ took 5.7 MB in our world. Small, but if you exclude it your restored world silently loses custom recipes and advancements.
  • data/ was only 28 KB: scoreboard data, map ids, raids. Tiny and absolutely not optional.
  • logs/, crash-reports/, cache/ and libraries/ are the usual bloat. Logs grow without bound, and caches regenerate on first start.

Two more factors dominate the size on a busy server. First, region files never shrink: chunks you visited once in 2019 still occupy their 4 KB sector allocation even if they are nearly empty, so a world with heavy exploration grows monotonically. Second, the difference between a cold copy and a crash-consistent copy is the difference between a world that starts and one that makes the server crash-loop with a corrupted chunk. Copying region files while the server is writing them produces torn files, and Minecraft will not always complain cleanly about it.

That is why the procedure matters as much as the tool. A crash-consistent copy flushes the server tick loop, stops writes, takes the copy, and resumes. A hot copy of a live world is a gamble you will eventually lose.

The Safe Capture Procedure

Every benchmark in this article was run against a quiesced copy, and the commands in the next section all assume you do the same. The sequence uses four server commands and it works on vanilla, Paper, Purpur and Fabric servers alike, because they are all vanilla commands.

  1. save-off stops automatic chunk saves so the server stops writing to disk.
  2. save-all flush forces a synchronous write of every dirty chunk. On the live server we measured this at 0.16 to 0.36 seconds across 22,801 chunks.
  3. Copy or snapshot the world directory. The server keeps running and players keep playing, but nothing is being written to region files.
  4. save-on resumes normal saving.

The window of risk is the length of step 3. During it, players can still move and place blocks; those changes sit in memory and are written after save-on. A crash in that window loses recent changes but never corrupts the files on disk, because you already flushed. If your copy takes longer than about thirty seconds, tell players in chat, or take a filesystem snapshot instead so step 3 is nearly instant.

Two details separate a script that works from a script that eats data. First, redirect output carefully: piping server commands into a FIFO or using screen -X stuff means the commands may be processed asynchronously, and your copy can start before the flush completes. Second, make sure the copy actually reaches durable storage before you report success. On ext4, a plain cp leaves data in the page cache; if the machine loses power, the backup is gone. Run sync, or use a tool that fsyncs explicitly, before you annotate the backup as valid.

#!/bin/bash
# safe-world-copy.sh - quiesce, flush, copy to staging, resume
WORLD=/srv/minecraft/world
STAGE=/srv/backups/staging
mkfifo /tmp/mc.pipe 2>/dev/null
tail -f /tmp/mc.pipe | screen -S minecraft -X stuff 2>/dev/null

echo "save-off" > /tmp/mc.pipe
echo "save-all flush" > /tmp/mc.pipe
sleep 1

rsync -a --delete "$WORLD/" "$STAGE/world/"        # fast, local staging
echo "save-on" > /tmp/mc.pipe
sync

echo "staged copy ready: $(du -sh "$STAGE/world" | cut -f1)"

If you already have an automated job, the pattern slots straight into it. Our guide to [How to Set Up Automated Minecraft Server Backups on Linux] covers the systemd timer and retention side; this article covers what to put inside the job.

Benchmark Setup and Raw Results

The test world was 233 MB apparent, or 243,487,250 bytes on disk, with 106 .mca region files. All work happened on one local SSD with warm cache, which means the read side was effectively free and the numbers reflect compression and write cost rather than disk latency. Times are wall-clock for the entire operation including archive creation.

MethodArchive sizeBytesTime
tar (no compression)232.4 MiB243,640,3200.08 s
gzip -1145.4 MiB152,514,1102.60 s
gzip -6145.0 MiB152,009,8812.91 s
pigz -6 (16 threads)145.2 MiB152,226,5920.34 s
zstd -1 -T0144.3 MiB151,259,9040.10 s
zstd -3 -T0143.5 MiB150,423,3220.19 s
zstd -9 -T0142.8 MiB149,747,3320.97 s
zstd -19 -T0142.2 MiB149,119,2855.57 s
zip -1145.5 MiB152,543,8762.94 s
zip -6145.0 MiB152,037,7103.30 s
restic (first)~146 MB repo–1.32 s
restic (second, unchanged)~146 MB repo–0.77 s
rsync (second pass, no changes)––0.07 s

Look at the spread. Plain gzip -6 took 2.91 seconds; zstd -3 -T0 produced a slightly smaller archive in 0.19 seconds. That is a fifteen-fold speedup for a better result. zstd -19 gave up 4.6 seconds to save 1.3 MiB over zstd -3; that is the trade you are making when you copy a -19 line from a blog post and schedule it hourly.

Byte totals from the restore test confirm the archives are complete: the zstd -9 archive extracted to exactly 243,487,250 bytes across 106 region files, matching the source. Compression ratio across every compressor stayed in a 143 to 146 MiB band because region files are already zlib-compressed internally and hold little cross-file redundancy.

Why multithreading changes everything

The 16-thread CPU is the reason for the pattern above. Plain gzip is single-threaded: it uses one core no matter how many you have, so all sixteen sit idle while one grinds through the archive. zstd with -T0 spawns one worker per core, and pigz is a drop-in parallel gzip that does the same. On a 2-core VPS the gap narrows to roughly 2x instead of 15x, but the ranking does not change: anything parallel beats single-threaded gzip.

One caveat: on a very small VPS, saturating all cores during a backup will starve the Minecraft server tick loop. Use -T2 or -T4 instead of -T0 on machines with fewer than four cores, and consider nice -n 19 so the GC threads win.

Copy-Paste Commands for Every Option

All commands assume you are in the directory containing the flushed world folder. Adjust paths and thread counts to taste.

tar with zstd (the general-purpose winner)

# fastest useful default
tar --use-compress-program="zstd -3 -T0" -cf world-$(date +%F-%H%M).tar.zst world/

# archive grade, run nightly or weekly
tar --use-compress-program="zstd -19 -T0 --long" -cf world-archive-$(date +%F).tar.zst world/

pigz for gzip compatibility

# keeps .tar.gz output so old scripts and panels still work, but uses all cores
tar --use-compress-program="pigz -6 -p $(nproc)" -cf world-$(date +%F).tar.gz world/

zip

# useful only when a control panel or Windows client expects a zip
zip -r -1 world-$(date +%F).zip world/

rsync with –link-dest (snapshot-style, near-zero space per run)

# first run creates the baseline, later runs hardlink unchanged files
BASE=/srv/backups/world-daily
NEW=$BASE/$(date +%F-%H%M)
rsync -a --delete --link-dest="$BASE/current" /srv/backups/staging/world/ "$NEW/"
ln -sfn "$NEW" "$BASE/current"

Most file managers and du will report the full size for every snapshot directory, but hardlinked files share one copy on disk. A hundred snapshots of a mostly unchanged world can cost barely more than one. Pair this with the staging copy from the safe procedure above, because --link-dest across a live changing tree produces inconsistent snapshots.

restic for deduplicated offsite backups

export RESTIC_REPOSITORY=/srv/backups/restic
export RESTIC_PASSWORD_FILE=/root/.restic-pass

restic init                       # once
restic backup /srv/backups/staging/world --tag minecraft
restic forget --tag minecraft --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune

restic chunks files, deduplicates at the chunk level and encrypts everything, which is why its repository was 146 MB after two backups of a 233 MB world. The first backup took 1.32 seconds; the unchanged second backup took 0.77 seconds. When you point it at an S3 bucket or Backblaze B2, only the changed chunks travel, which is the single biggest win for offsite backups of a large world. Read the restic documentation on pruning, because forget without prune never reclaims space.

What to Use, by Scenario

ScenarioUse thisWhy
Daily local snapshotzstd -3 -T0 tar, or restic0.19 s and about 143 MiB; restic adds dedupe and encryption
Long-term archivezstd -19 -T0Smallest output; 5.57 s is fine once a week
Gzip-compatible outputpigz -6Same .tar.gz format, 8x faster than gzip -6
Bandwidth-limited offsiterestic + S3/B2Only changed chunks upload after the first run
Quick pre-update snapshotrsync --link-dest or LVM/ZFS snapshotNear-zero extra disk, sub-second
Restoring for a player rollbackuncompressed tar or rsync snapshotNo decompression step, fastest to open

A practical combination that costs almost nothing: rsync --link-dest snapshots every hour, a zstd -3 tar nightly, and restic to an offsite bucket daily. Total extra disk for a week of the first two is about 1 GB, and offsite cost is limited to changed chunks.

Retention Math: How Much Disk Do You Actually Need?

At roughly 150 MB per zstd -3 copy of this world, seven daily copies cost about 1 GB. Thirty daily copies cost about 4.5 GB. That is manageable on a 500 MB world and painful on a 4 GB one, where thirty copies would be roughly 90 GB. Do the arithmetic before you pick a retention window, not after the disk fills.

restic changes the math because of deduplication. Thirty daily backups of a world that changes by 20 MB per day do not cost 4.5 GB; the shared chunks are stored once, so you pay for the base image plus the deltas. The same logic applies to rsync --link-dest, where unchanged files are hardlinks. If your retention window is longer than a week, use one of those two and skip the plain tar rotation entirely.

  • Plain tar rotation: simple, predictable, costs full size per copy.
  • rsync –link-dest: cheap on disk, but only as good as your staging copy.
  • restic: cheapest for long retention and offsite, needs periodic prune.

The Restore Drill: An Untested Backup Is Not a Backup

We restored the zstd -9 archive as part of this test. The result: 0.10 seconds to extract, 106 of 106 region files present, restored bytes exactly 243,487,250 matching the source, and zstd -t reported OK. That is the minimum standard, and you should run the same drill yourself at least once a quarter.

  1. Verify integrity: zstd -t world.tar.zst, gzip -t world.tar.gz, or restic check.
  2. Extract to a temporary directory, never over the live world: mkdir /tmp/restore && tar --use-compress-program=unzstd -xf world.tar.zst -C /tmp/restore.
  3. Compare counts and bytes: find /tmp/restore/world -name "*.mca" | wc -l should match the original 106, and du -sb /tmp/restore/world should be close to 243,487,250.
  4. Diff the trees: diff -r --brief /srv/minecraft/world /tmp/restore/world should be silent apart from session.lock and logs.
  5. Start a test server on another port with the restored world and confirm players can log in, open chests and see their inventory.

That last step catches the failures a checksum cannot: a world that extracts perfectly but has empty level.dat, a missing playerdata folder, or a stale session.lock from the machine that took the backup. Point a second Paper instance at the restored directory with --port 25566 and --world-dir /tmp/restore and let it generate its own config. If it boots and the world renders, your backup works. If the server refuses to start, you found the problem on a Tuesday afternoon instead of during an outage. The official Paper documentation covers startup flags and world directory configuration.

Schedule the drill, do not leave it as an intention. A quarterly calendar reminder that says “restore one backup and boot it” is worth more than any retention policy.

What to Exclude and What Never To

Exclusions are where most backup sizes are actually won or lost. On this 233 MB world, excluding logs and caches would have trimmed maybe 2 MB, but on a server that has been running for two years with verbose logging, logs/ alone can be several gigabytes.

Usually safe to exclude

  • logs/ – historical text, useful for debugging but rarely needed beyond a week.
  • crash-reports/ – keep the last few if you like, but they are not world data.
  • cache/ and libraries/ – regenerated on next start.
  • session.lock – never restore it, it can block startup.
  • world/datapacks/ only if your datapacks are version-controlled elsewhere. Otherwise keep them.

Never exclude

  • level.dat and level.dat_old – the world settings, seed and spawn. Losing them means losing the world identity.
  • Any region/, entities/ or poi/ folder – this is the actual world.
  • playerdata/, advancements/ and stats/ – inventories and progress live here.
  • data/ – scoreboards, maps, raid state, forced chunks. Only 28 KB in our world.
  • Plugin databases. LuckPerms, CoreProtect, LWC and economy plugins keep their own storage outside the world folder and need their own dump.

That last point trips up almost everyone. A perfect world backup that excludes the CoreProtect database is a backup of the map with no rollback history, and an economy plugin restored from a week-old row set will happily duplicate or vanish balances. If your plugins use MySQL, use mysqldump --single-transaction in the same job; if you have not moved them off SQLite yet, [MySQL vs SQLite for Minecraft Plugins: What Should You Choose?] explains why that transition is worth it, and [Database Optimization: Setting Up MariaDB for LuckPerms and CoreProtect] covers the dump commands and tuning that make them safe to snapshot.

Pros and Cons of the Three Main Approaches

ApproachProsCons
tar + zstdOne self-contained file, portable, trivially verifiable, fastFull size every run, no dedupe, restore needs a decompress step
rsync –link-destInstant snapshots, near-zero extra disk, browsable file treeOnly cheap on the same filesystem; no compression; needs staging copy
resticDedupe, encryption, offsite-friendly, integrity checks built inSlower first backup on huge worlds, repository can be opaque, prune needs care

Each has a failure mode worth knowing. tar gives you one file that is either fine or truncated, with no middle ground. rsync snapshots depend on hardlink support, which many SMB shares and object stores do not provide. restic protects against ransomware with its encryption but will not save you if you forget the password; store it somewhere other than the server. “Backups on the same disk” belongs on the mistake list below for exactly this reason.

Common Mistakes and Expert Tips

  • Backing up a running world without a flush. This is the one that actually destroys worlds. Always save-off then save-all flush before the copy, and save-on after.
  • Never testing a restore. A backup you have not restored is a hypothesis. Extract and boot it once this quarter.
  • Excluding level.dat during a “size optimization” pass. It is a few kilobytes and it is the whole world.
  • Keeping backups on the same disk. Disk failure, filesystem corruption and ransomware all take the backups with the world. Push to another machine or object storage.
  • Using zstd -19 every hour. You are spending 5.57 seconds and CPU headroom to save 1.3 MiB over -3. Archive weekly, compress daily at -3.
  • Forgetting plugin databases. LuckPerms, CoreProtect and economy data live outside the world folder. Dump them in the same job.
  • Compressing on the same thread pool as the server. On a 2-core VPS, use -T2 and nice, or your tick rate will spike during backups.
  • Never pruning. A retention policy without deletion is a disk-full incident with a delay.

One more tip from the benchmark: if you tune chunk loading and pregeneration, your world grows in a much more predictable pattern, which makes backup sizing easier. [Understanding Chunk Loaders and Their Performance Cost] explains why a handful of stray chunk loaders can balloon your region folder far beyond what your play area suggests.

And a caveat about the numbers above: they were taken on a warm page cache with a local SSD and a fixed world size. On spinning disks, NFS or a network-attached volume, absolute times will be noticeably worse, and the read phase may dominate. The ranking, however, held in every re-run: parallel zstd beats single-threaded gzip, and unchanged-file detection beats re-copying everything. Use the ratios to plan, then measure once on your own hardware before you commit to a schedule.

Frequently Asked Questions

What is the best compression for Minecraft world backups?

zstd at level 3 with -T0. On our 233 MB test world it produced a 143.5 MiB archive in 0.19 seconds, versus 2.91 seconds for gzip -6 at a slightly larger size. Use zstd -19 only for weekly archives.

Can I back up a Minecraft world while the server is running?

Only if you flush first. Run save-off, then save-all flush, copy or snapshot the world, then save-on. Copying region files while the server writes them produces torn files and corrupted chunks.

How much disk space do daily Minecraft backups need?

At about 150 MB per compressed copy of a 233 MB world, seven daily backups cost roughly 1 GB and thirty cost about 4.5 GB. restic or rsync –link-dest reduce this substantially because unchanged data is only stored once.

Why does gzip take so much longer than zstd on my server?

Plain gzip is single-threaded, so it uses one CPU core regardless of how many you have. zstd -T0 and pigz use all cores. On a 16-thread machine that was the difference between 2.91 seconds and 0.19 seconds.

The Short Version

Compression choice is not where the win is. On a real 233 MB Paper world, every format landed within 3 MiB of the others, but the time spread was more than thirty-fold. Use zstd -3 -T0 for daily backups, zstd -19 weekly, pigz -6 when something requires a .tar.gz, and restic when the copy leaves the building. Flush the server before every copy, keep a copy off the machine, and restore one archive this quarter so you know it works.

If you want to go further: build the flush-then-copy script from this article into a systemd timer, move plugin data to a real database so it can be dumped safely, and stop treating backups as a directory you occasionally copy. For a small world, a single zstd tar is enough. For a large one, the combination of hourly rsync --link-dest snapshots, a nightly compressed archive and a daily deduplicated offsite push is the cheapest insurance you will ever buy. Start with the flush procedure today; it takes four commands and it is the difference between a backup and a corrupted world.

Generative AI was used to research and add structure to the original content so I can inform you as best as possible. All content has been reviewed by me.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Search

Minecraft Server Tips and Tricks