- One world on several servers: Storia Cluster (Storia) Folia splits a world across the cores of one machine; Storia splits it across machines. Each Storia Worker runs the part of the world where its players are, Storia Relay stores the world and decides who runs what, and players move between workers through Storia Proxy without a loading screen, keeping their inventory, advancements and statistics. Players who come close are put on the same worker before they could see each other's chunks, and contraptions on a border always run on one worker. See Storia Cluster.
- Regionised multithreading (from Folia) Nearby chunks are grouped into independent "regions" that tick in parallel. This scales well on large servers where players spread out (SMP, skyblock, etc.).
- RAM world (Storia)
On startup the world is loaded into RAM (
/dev/shm) and the server reads and writes it there, so disk I/O stops being a bottleneck.- Only changed files are written back to disk in the background, at a fixed interval
- Files are written to a temp file and then atomically renamed, so the on-disk world is never half-written
stopwrites everything to disk- If the process is killed, the RAM copy survives as long as the machine stays up; it is detected and recovered to disk on the next start
- If there is not enough RAM, the server falls back to loading from disk as usual
- Fast chunk pregeneration (Storia)
/storia pregengenerates chunks ahead of time so players never wait for terrain. While it runs, the chunk worker pool is raised to all cores but one (Folia's default is only about a quarter of the cores), then restored. Progress survives restarts. - Tick guard (Storia)
A crowded spot such as spawn stays smooth for the people in it. When a region's tick time passes its target
(40 ms), mobs in crowded chunks (16+ mobs) re-plan only every 2nd, 4th or 8th tick; they still move, path,
collide, fall and ride water every tick. Blocks, redstone and hoppers are never touched, and mobs near a player,
fighting a player, pets and bosses always think every tick. On a test spawn with 1,400 mobs the region went from
50-55 ms to 32-35 ms per tick (TPS 20) and the players standing nearby were not limited at all.
/storia regionlists the crowded chunks so you can find the farm. - Per-player budget (Storia) Only players who add load themselves are limited: when their region is over budget, players moving faster than 12 blocks/s (elytra, ...) get a shorter view distance until they slow down. Players who stand, build or walk in a busy place are never limited. Simulation distance is not touched by default, so redstone and farms keep running. When the heap is nearly full after GC, view distance is lowered for everyone.
- Faster entity physics (Storia) Entity pushing (the cost of mobs crammed together) is about 3x faster with identical results: the same entities are pushed in the same order, and cramming damage and its random roll are unchanged. Redstone is not modified.
- Faster world generation (Storia) Noise sampling and block counting are optimized. Terrain is identical to vanilla for the same seed (the noise changes are verified bit-for-bit against the original code).
Requires Java 25 or newer.
java -Xmx8G -jar storia-26.2.jar noguiDownload from Releases:
| File | What it is |
|---|---|
storia-<version>.jar |
The Storia server |
storia-worker-<version>.zip |
Storia Worker: one server of a Storia Cluster |
storia-relay-<version>.zip |
Storia Relay: the cluster's coordinator (stores the world, decides who runs what) |
storia-proxy-<version>.jar |
Storia Proxy: Velocity fork with 50 built-in placeholders |
Versions follow Minecraft: 26.2 is the first Storia release for Minecraft 26.2, and later builds for the same
Minecraft version are 26.2-2, 26.2-3, and so on. Use the same version on the server, workers and relay.
Development builds are also available as the storia-jar artifact in Actions.
Created in the server folder on first start.
ram-world:
enabled: true
ram-directory: /dev/shm/storia
sync-interval-seconds: 300 # shorter is safer, longer is more efficient
min-free-mb: 512 # load from disk if RAM would drop below this
delete-on-shutdown: true # delete the RAM copy after a clean shutdown
pregen:
worker-threads: -1 # -1 = CPU cores - 1 while pregenerating
max-in-flight: -1 # -1 = worker-threads * 16 chunks queued at once
tick-guard:
enabled: true
target-mspt: 40.0 # keep each region below this (a tick has 50 ms)
crowd-threshold: 16 # mobs per chunk that count as a crowd
player-radius: 8.0 # mobs this close to a player always think every tick
max-level: 3 # thin out down to every 8th tick
player-budget:
enabled: true
check-interval-ticks: 100 # how often each player is checked
lower-simulation-distance: false # true = also lower simulation distance (machines far away stop)
max-region-mspt: 45.0 # a region ticking slower than this is over budget
pool-saturated-percent: 85 # tick threads this busy = saturated, so enforce fair shares
recover-below-percent: 70 # restore once the region is below 70% of its limits
min-simulation-distance: 4
min-view-distance: 6
memory-high-percent: 85 # heap after GC above this lowers everyone's view distance
memory-low-percent: 70
fast-mover-speed: 12.0 # only players faster than this (blocks/s) are limitedWarning
If the machine loses power or the OS crashes, changes made since the last sync are lost.
You need free RAM as large as the world folder, in addition to the JVM heap (check with df -h /dev/shm).
| Command | Description | Permission |
|---|---|---|
/storia status |
Show the RAM world status (paths, usage, last sync) | storia.command.storia (op) |
/storia sync |
Write the RAM world to disk now | storia.command.storia (op) |
/storia pregen start <radius> [world] [x z] |
Pregenerate a square of radius blocks around spawn (or x z) |
storia.command.storia (op) |
/storia budget |
Tick thread usage, heap, and each player's region load, speed and current distances | storia.command.storia (op) |
/storia region |
Busiest regions: thread usage, MSPT, TPS, players, chunks, tick guard state and crowded chunks | storia.command.storia (op) |
/storia cluster |
Cluster connection, cells this worker runs, players, shared time and scoreboard | storia.command.storia (op) |
/storia pregen stop / resume / status |
Stop (progress is saved), resume after a restart, show progress | storia.command.storia (op) |
Pregenerating 3,721 chunks (radius 480 blocks) on a 6-core machine:
| Time | Chunks/s | |
|---|---|---|
| Folia default (1 worker thread on 6 cores) | 3m 21s | 18.5 |
Storia /storia pregen (5 worker threads) |
40s | 94 |
2,000 chickens crammed into one block plus 2,000 spread out and 2,000 dropped items, one region:
| MSPT | |
|---|---|
| Folia | 750 |
| Storia | 252 |
Verified on live data: with -Dstoria.verifyPush=true every push is also computed the vanilla way and
compared (500,000 checks with cramming on and off, 0 differences).
For normal play (players exploring new terrain), you can raise chunk-system.worker-threads
in config/paper-global.yml if your CPU has headroom.
Storia Worker and Storia Relay are only for a cluster; a worker cannot be added to a single Storia server. To move an existing server into a cluster, see https://storiamc.com/en-us/docs/scaling/
players --> Storia Proxy --> Storia Worker A --\
\-> Storia Worker B ---> Storia Relay: the world, who runs what
\-> Storia Worker C --/
- Relay:
relay.propertieswith asecret(8+ characters); put your world incluster-world/. - Workers: in
storia.ymlA new worker needs no copy of the world: it fetches the world settings from the relay on first start. Workers are Velocity backends (cluster: enabled: true coordinator: "relay-host:25590" node-name: worker-1 # unique; the same name as in velocity.toml secret: some-long-random-string
online-mode=false,proxies.velocityinconfig/paper-global.yml). - Storia Proxy: list the workers in
velocity.tomlunder their node names and set[cluster]with the same coordinator and secret instoria-proxy.toml.
/storia cluster on a worker and status in the relay console show who runs what. Time, weather, game rules,
the scoreboard, maps, advancements and statistics are shared; /stop on a worker moves its players to the others
first. Seamless moves need Minecraft 26.1/26.2 clients. Full guide: https://storiamc.com/en-us/docs/cluster/ and
the design in CLUSTER.md.
Plugins: each worker runs its own copy of every plugin. Player data is shared by the cluster; for a plugin's
own data use Storia's plugin API (dev.storia.api.StoriaShared, storia-api-<version>.jar in the release): a
key-value store per plugin with compare-and-set, counters and change notifications, and messages to every worker.
It also works on a single server. Guide: https://storiamc.com/en-us/docs/plugin-api/
The earlier terrain-only offload (workers that computed terrain noise for one server) was replaced by the
cluster; its code is kept in the archive/terrain-offload branch.
Storia uses the same threading model as Folia, so only Folia-compatible plugins work
(those with folia-supported: true in plugin.yml).
ServerBuildInfo#isBrandCompatible(papermc:folia) also returns true, so plugins that check for Folia work too.
For details on the threading model and recommended settings, see the Folia README.
./gradlew applyAllPatches
./gradlew createPaperclipJar
# → folia-server/build/libs/folia-paperclip-*.jar- Storia's own classes:
folia-server/src/main/java/dev/storia/ - Minecraft changes: commit in
folia-server/src/minecraft/java→./gradlew rebuildMinecraftFeaturePatches - Paper changes: commit in
paper-server→./gradlew rebuildPaperServerFeaturePatches
Patches are licensed under PATCHES-LICENSE. Storia is a derivative of PaperMC/Folia (and Paper). Thanks to the upstream developers.
