Introducing SteelMC
After nine months of development, SteelMC has block-for-block terrain parity, a multithreaded foundation, and a server you can try today.
SteelMC is a “new” Minecraft server written in Rust. Do not bother updating Days Since the Last Rust Minecraft Server. We have been on there since October 16, 2025.
I have never liked announcing a project the moment its repository is created. The replies are usually some version of “cool, let us know when it can actually do something.” By the time it can, the project has either died or everyone has forgotten about it.
So I waited.
Steel first achieved block-for-block terrain parity on May 20, 2026. The current parity suite covers 7,500 randomly selected chunks: 2,500 in each dimension.
Steel is still pre-alpha, but you can already connect to it, explore persistent generated worlds, interact with blocks and inventories, and begin building on what is already there.
Most of those nine months have gone into systems that are almost invisible when you join the server. As they mature, new gameplay features require less supporting infrastructure, and more of the work should begin showing up in the game.
In brief: what Steel can do today
Steel aims to track the latest Minecraft Java Edition release and currently targets 26.2. Clients can join, load generated worlds, move and interact, use inventories and commands, and return later to a saved world. These systems work together in a persistent multiplayer server, not just in isolated protocol or world-generation demos.
Survival gameplay is still incomplete, meaningful behavior is implemented for only a few entity types, and Steel does not yet provide full vanilla or protocol parity. Plugins do not exist yet, and extensions written for Paper, Bukkit, Fabric, Forge, or NeoForge will not work. I am not going to pretend that you should replace your production Paper server with it tomorrow.
Why I started Steel
Before Steel, I was a regular contributor to PumpkinMC. Pumpkin is the reason I began writing Minecraft server code in Rust, and I do not intend any of what follows as criticism of its contributors. This account is based on Pumpkin’s codebase as it existed around October 2025; it may have changed substantially since then.
One of the things I love about Rust is that its restrictions make more sense as you learn the language. A frustrating compiler error often turns out to protect you from an edge case you had not considered. The feeling that someone had already thought the problem through began to shape what I wanted from the systems I worked on.
I implemented redstone there and rewrote its inventory system. While contributing, I began to notice a difference in how I wanted to approach foundational systems. I wanted to step back, study the cases that would come later, and make sure a foundation could support more than its first use case.
That difference became clear when Pumpkin began adding trees to its world generator. Chunks were generated in isolation, which works until a tree near a border needs to place leaves in its neighbor. I spent about a month researching the problem and came to see it as a question of coordinating generation across an entire region, not merely placing a tree. The project ultimately merged another solution that addressed the immediate problem. Neither priority was wrong, but it became clear that I wanted to build around a different one.
So I started Steel, initially without many expectations. The first thing I implemented was the block registry and property system I had wanted while working on Pumpkin. For the first time, I could research how vanilla handled a problem, decide which guarantees mattered, and design around making the correct path the easy one.
The point of Steel is not simply to rewrite Minecraft in Rust and call it faster. I want it to be pleasant to work with, and I want its foundations to survive the second complicated use case instead of being replaced by it.
That does not mean inventing abstractions for problems we may never have. It means understanding a problem before choosing the simplest solution that is actually correct.
World generation is where that philosophy first became concrete.
Building the world through a chunk pyramid
Minecraft does not generate a chunk in one pass. It moves chunks through a series of stages. Structures are located, biomes are chosen, terrain is shaped, the surface is painted, caves are carved, features such as ores and trees are placed, and light is propagated. Each stage needs chunks around the target chunk to have reached particular earlier stages.
I used to picture those dependencies as a tree. Request a fully generated chunk at one coordinate, let it request its neighbors, let those neighbors request their neighbors, and continue until everything it needs exists. Trying to express that directly quickly becomes recursive: chunk X waits for chunk Y, which eventually asks for chunk X again.
Vanilla calls its solution a chunk pyramid. The name confused me until I understood what it described.
A chunk reaching the Full stage depends on a 23-by-23 area having reached the Structure Starts stage. Later stages need smaller areas: 7 by 7, then 5 by 5, then 3 by 3. At the final stages, only the center chunk remains. Stacked together, those minimum requirements form a pyramid.
Each tier shows the minimum area required at that stage. The dimensions and radii are exact, although the tier widths are compressed visually.
Once I saw it that way, the dependency problem stopped looking recursive. Steel advances through the stages in order, processing all required chunks for each stage in parallel before moving on. In practice, nearby requests overlap, so many chunks are already further ahead than the minimum shown by the pyramid. At first every stage was a no-op, but watching the scheduler coordinate the whole system correctly was still beautiful.
Chasing parity
From the start, the target was block-for-block vanilla parity: given the same seed, version, and coordinates, Steel should produce the same blocks as vanilla.
We began with biomes and then the noise stage, which first fills a chunk with terrain. That immediately exposed a dependency hidden by the neat stage diagram: terrain shaping needs information about structures. While the structure pipeline was incomplete, we disabled structures in the vanilla reference worlds produced by our extractor. That let us test the terrain we had actually implemented without weakening the final goal.
The surface stage replaces the raw stone from noise generation with the blocks players recognize: grass, dirt, sand, snow, and so on. When our implementation was nearly finished, almost every one of the 2,500 test chunks matched. Almost.
One chunk would differ. We traced the mismatch all the way down to a tied biome lookup. Vanilla caches biome searches in thread-local state, so the result of that tie can depend on what the worker thread happened to generate beforehand. The same seed and coordinates are not always enough to determine the same output.
That was the point where our goal became slightly more precise. Steel should reproduce vanilla where vanilla is deterministic, preserve behavior players rely on, and fix accidental nondeterminism where we can do so without changing the game.
Steel now uses a chunk-local biome cache, making the result independent of which worker thread receives the chunk. For parity tests, we modified the vanilla extractor to reset its cache for each chunk and reproduce Steel’s deterministic behavior.
The features stage introduced another source of nondeterminism. Features such as trees and ores can cross chunk borders, so changing the order in which neighboring chunks generate can change the final result. To make parity comparisons meaningful, our extractor generates reference chunks one at a time in a fixed order.
Even then, a few blocks still differed. The trail led to hash-based collections in vanilla’s feature code. Their iteration order is not stable, but in world generation that order can decide which block is placed first and what may be placed next. We gave those operations an explicit order and modified the extractor to use the same one.
With that final source of nondeterminism removed, all tested chunks matched block for block.
The entity-spawning stage remains disabled because Steel does not yet implement the behavior of most entities it would place in the world. Enabling the stage now or silently discarding those entities would give a misleading impression of completeness. Entity spawning therefore remains outside the parity claim.
Steel
Vanilla
Lighting without a global queue
Lighting has long been one of the most noticeable missing pieces in experimental Minecraft servers. It is easy to see why: light crosses chunk boundaries, and two adjacent chunks cannot safely propagate overlapping updates without coordination. Vanilla moves lighting off the main thread but runs it through a single engine, making lighting a bottleneck during parallel world generation.
The modding community had already explored this problem through Starlight. When Starlight was no longer maintained as a mod, ScalableLux continued its work as a fork and added an experimental parallel mode. Steel’s engine is inspired by that work, but designed around Rust’s ownership and concurrency tools from the beginning. Chunks can process lighting in parallel while the scheduler keeps overlapping work from interfering.
Measuring the result
Together, the chunk scheduler and parallel lighting engine now have measurable results. On a Ryzen 9 9950X, Steel generated a fresh 10,201-chunk Overworld area in a median of 3.95 seconds. A Fabric server using Chunky took 74.42 seconds. Across three cold runs, Steel averaged 2,582 chunks per second. That is 18.8 times the throughput of Fabric.
Those headline numbers need context. Steel used an average of 30.2 logical CPU cores during the measured interval, compared with 4.4 for Fabric. The test therefore measures parallel scaling as well as per-core efficiency. After adjusting for CPU use, Steel still generated 2.75 times as many chunks per CPU-second as Fabric.
This is a focused world-generation benchmark on one machine, not a claim that Steel is 18.8 times faster at every server workload. Steel also leaves out entity spawning while Fabric performs that stage. The full benchmark includes the methodology, individual runs, memory results, raw data, reproduction instructions, and further limitations. These performance measurements are separate from the block-by-block parity tests described above.
An unedited in-game test of Steel generating and sending chunks while moving through the world, using a 32-chunk render distance and a 10-chunk simulation distance. This is a visual demonstration, not the controlled benchmark described above.
Keeping the game tick moving
Vanilla is famous for its main thread. The design provides a valuable guarantee: while a game tick is running, the world does not change underneath it. The cost is that unrelated work can hold up the entire server.
Steel preserves a synchronous game tick for gameplay logic, but moves packet processing, chunk scheduling, and chunk sending out of it. Dedicated workers handle gameplay packets between ticks instead of collecting every packet for one large batch at the start of the next tick, as vanilla does. At the tick boundary, Steel stops accepting new gameplay packets and processes those it has already accepted. It can then advance chunks and entities against a stable world before packet processing resumes.
In parallel, chunk scheduling propagates tickets and starts generation work, while the sending loop prepares and transmits completed chunks to clients. Disk and network I/O do not need to consume time from the gameplay budget.
Steel's runtime architecture
Continuous work, one safe boundary
Normal cadence
Packets keep flowing while background work overlaps Packet workers use the whole inter-tick window instead of building one large queue for the next game tick. At the boundary, admission closes briefly while ready scheduler state and gameplay are applied safely.The rule behind that design is simple: the game tick never blocks while waiting for asynchronous work.
Consider respawning a player. The destination chunks must be ready before the player can safely appear, but waiting for them would stall every other player and entity. Steel instead creates a job that is checked each tick. Once its asynchronous preparation is complete, the move happens synchronously at a defined safe point.
This preserves the useful part of a synchronous world model: gameplay changes happen at defined safe points. A slow disk read or chunk dependency does not become a server-wide pause.
Preserving redstone’s useful bugs
Redstone presents almost the opposite problem. Some vanilla behavior is technically accidental, but has been studied, documented, and turned into machinery by the redstone community over many years. “Fixing” it would break real builds.
One example is locationality: a contraption can behave differently depending on where or how it is oriented in the world. Some of that behavior originated in the iteration order of a hash set used while processing updates. It may look like an implementation detail, but to technical players it is part of the game.
Steel’s redstone implementation therefore aims to preserve not only the intended rules, but also the quirks that players depend on. Vanilla parity does not mean cleaning up every strange behavior. It means knowing which strangeness has become a feature.
Designing for plugins before plugins exist
Plugins are one of the features I have wanted to build for the longest, but they are also something I refuse to rush. A plugin API exposes almost every part of a server, so publishing one too early can freeze the wrong abstractions for years. Steel needs to become a solid Minecraft server before I can honestly decide what that API should promise.
I have explored WebAssembly, scripting languages, and native Rust plugins. The current direction is a native Rust API, giving extensions the same power as ordinary server code. Native plugins could still provide sandboxed or higher-level environments by embedding WebAssembly or language runtimes such as JavaScript and Lua. Native plugins would be trusted code, so the API boundary will need careful design.
Years of Bukkit and Paper plugins have shown which problems server extensions commonly solve. Steel draws inspiration from those use cases, including how servers and plugins use permissions, without copying the public APIs of Bukkit or Paper. But Steel does not have plugins yet, and we will not publish an API until the server beneath it is mature enough to make that promise responsibly.
Why announce Steel now
Steel is still pre-alpha, and there is a lot left to do. We do not have plugins yet. Many vanilla systems are still missing. There will be bugs, incomplete mechanics, and architectural decisions we revisit as we learn more.
But Steel is no longer a prototype that might become a server one day. It is a server you can connect to, with nine months of work behind it, tested terrain-generation parity, working gameplay systems, and a growing group of contributors.
I recently added three trial maintainers: Junky, Evald, and purdze. I hope they will help drive the project forward and make it less dependent on one person. That matters particularly now because I will soon begin military service and expect to have less time to contribute for roughly a year. I still expect to be around most weekends to review work, answer questions, and keep building where I can.
That is part of why I am announcing Steel now. The project needs to become more than something I quietly work on by myself.
A note on AI contributions
Steel allows AI to be used as a tool, but not as a substitute for a contributor’s thinking. Whether you use it to look up an API, understand a compiler error, or explore possible approaches, you must understand every line you submit and be able to explain the design behind it.
Fully autonomous pull requests are not welcome, and contributors must write and understand their own pull request descriptions. Our contributor guide covers the expectations and how to get started.
Join us
If Steel sounds interesting, take a look at the repository, read through the documentation, follow the implementation tracker, or join our Discord. If you want to try it yourself, the installation guide has builds and setup instructions.
Feedback, criticism, and contributions are welcome.
Support Steel
If you would like to support the project, consider starring the repository. It helps more people discover Steel and follow its progress.
Our Steel Foundation sponsor page is still awaiting approval. In the meantime, you can sponsor 4lve; donations made there will go toward the costs of running the project.