A Rust library that provides the core logic for launching Minecraft Java Edition. It handles everything the official launcher does — downloading game files, assets, Java runtimes, mod loaders, and spawning the game process — exposing a clean async API with real-time progress events.
- Vanilla & modded — supports Forge, NeoForge, Fabric, LegacyFabric, and Quilt out of the box
- Automatic downloads — game JARs, libraries, assets, and Java runtimes fetched on demand
- Integrity checks — SHA-1 verification before every launch
- Instance isolation — each instance gets its own game directory
- Event-driven — progress, speed, logs, and exit codes delivered over a
tokiochannel - Async — built on
tokio; non-blocking from download to process management
Add to your Cargo.toml:
[dependencies]
minecraft-java-rs-core = { git = "https://github.com/fitzxel/minecraft-java-rs-core" }
tokio = { version = "1", features = ["full"] }use minecraft_java_rs_core::{
launcher::{
events::LaunchEvent,
options::{JavaOptions, LaunchOptions, LoaderConfig, MemoryConfig, ScreenConfig},
Launcher,
},
models::{loader::LoaderType, minecraft::Authenticator},
utils::auth::offline_uuid,
};
use tokio::sync::mpsc;
#[tokio::main]
async fn main() {
// 1. Configure the authenticator (offline mode)
let auth = Authenticator {
access_token: "offline".into(),
name: "Steve".into(),
uuid: offline_uuid("Steve"),
xbox_account: None,
user_properties: None,
client_id: None,
client_token: None,
};
// 2. Build launch options
let options = LaunchOptions {
path: "./minecraft".into(),
version: "1.21.1".into(),
authenticator: auth,
memory: MemoryConfig {
min: "2G".into(),
max: "4G".into(),
},
loader: LoaderConfig {
enable: false,
..Default::default()
},
timeout_secs: 30,
download_concurrency: 10,
java: JavaOptions::default(),
screen: ScreenConfig::default(),
verify: false,
game_args: vec![],
jvm_args: vec![],
instance: None,
url: None,
mcp: None,
intel_enabled_mac: false,
bypass_offline: true,
};
// 3. Create launcher and event channel
let launcher = Launcher::new(options);
let (tx, mut rx) = mpsc::channel::<LaunchEvent>(512);
// 4. Spawn event listener
tokio::spawn(async move {
while let Some(event) = rx.recv().await {
match event {
LaunchEvent::Progress { downloaded, total, kind } => {
println!("[{kind}] {downloaded}/{total}");
}
LaunchEvent::Data(line) => println!("[MC] {line}"),
LaunchEvent::Close(code) => println!("Exited with code {code}"),
_ => {}
}
}
});
// 5. Launch
let mut child = launcher.start(tx).await.expect("Failed to launch");
child.wait().await.ok();
}Set the loader field in LaunchOptions:
use minecraft_java_rs_core::models::loader::LoaderType;
use minecraft_java_rs_core::launcher::options::LoaderConfig;
// Fabric — latest build
let loader = LoaderConfig {
enable: true,
loader_type: Some(LoaderType::Fabric),
build: "latest".into(),
path: None,
config: None,
};
// NeoForge — specific build
let loader = LoaderConfig {
enable: true,
loader_type: Some(LoaderType::NeoForge),
build: "21.1.231".into(),
path: None,
config: None,
};
// Forge — recommended build
let loader = LoaderConfig {
enable: true,
loader_type: Some(LoaderType::Forge),
build: "recommended".into(),
path: None,
config: None,
};Available loader types: Forge, NeoForge, Fabric, LegacyFabric, Quilt.
Valid build values: "latest", "recommended", or an exact version string (e.g. "0.19.2").
Generates a deterministic offline UUID from a username. Useful when building
your own offline-mode Authenticator without a real Microsoft account.
use minecraft_java_rs_core::utils::auth::offline_uuid;
let uuid = offline_uuid("Steve");
// e.g. "2a6b3c4d-1e2f-3a4b-8c9d-0e1f2a3b4c5d"The same username always produces the same UUID, so the player's inventory and world progress are preserved across sessions.
Download and verify all game files without spawning the game process:
launcher.download_game(tx).await.expect("Download failed");All progress and game output is delivered as LaunchEvent variants over a tokio::sync::mpsc channel:
| Event | Description |
|---|---|
Progress { downloaded, total, kind } |
Download batch progress. kind is e.g. "libraries", "assets", "java" |
Speed(f64) |
Current download speed in bytes/sec |
Estimated(f64) |
Estimated seconds remaining |
Check { current, total, kind } |
File integrity check progress |
Extract(String) |
A file is being extracted from an archive |
Patch(String) |
A Forge processor step is running |
GameDownloadFinished |
All files downloaded and verified |
Data(String) |
A line of stdout/stderr from the Minecraft process |
Close(i32) |
Minecraft exited; carries the exit code |
Error(String) |
Non-fatal warning from the launcher |
while let Some(event) = rx.recv().await {
match event {
LaunchEvent::Progress { downloaded, total, kind } => {
let pct = downloaded * 100 / total.max(1);
println!("[{kind}] {pct}%");
}
LaunchEvent::Speed(bps) => {
println!("Speed: {:.1} MB/s", bps / 1_048_576.0);
}
LaunchEvent::GameDownloadFinished => {
println!("All files ready!");
}
LaunchEvent::Data(line) => {
println!("[MC] {line}");
}
LaunchEvent::Close(code) => {
println!("Game exited: {code}");
break;
}
_ => {}
}
}The repo ships an example launcher at examples/launch.rs:
# Vanilla 1.21.1
cargo run --example launch -- --version 1.21.1 --username Steve
# With Fabric (latest)
cargo run --example launch -- --version 1.21.1 --username Steve --loader-type fabric
# With NeoForge (specific build)
cargo run --example launch -- --version 1.21.1 --username Steve --loader-type neoforge --loader-build 21.1.231
# With Forge (recommended)
cargo run --example launch -- --version 1.21.1 --username Steve --loader-type forge --loader-build recommended
# With Quilt (latest)
cargo run --example launch -- --version 1.21.1 --username Steve --loader-type quilt
# Use a named instance (saves to ./minecraft/instances/myworld)
cargo run --example launch -- --version 1.21.1 --username Steve --instance myworld
# Download only (no game launch)
cargo run --example launch -- --version 1.21.1 --only-download
# Custom memory and auto-close after 60 seconds
cargo run --example launch -- --version 1.21.1 --username Steve --min-mem 2G --max-mem 6G --auto-close 60| Flag | Default | Description |
|---|---|---|
--version <VERSION> |
1.20.4 |
Minecraft version |
--username <NAME> |
Player |
Offline username |
--path <PATH> |
./minecraft |
Root game directory |
--instance <NAME> |
— | Instance name (<path>/instances/<name>) |
--min-mem <SIZE> |
2G |
JVM minimum heap |
--max-mem <SIZE> |
4G |
JVM maximum heap |
--loader-type <TYPE> |
— | forge | neoforge | fabric | legacyfabric | quilt |
--loader-build <BUILD> |
latest |
latest | recommended | exact version |
--only-download |
— | Download files without launching |
--auto-close <SECS> |
— | Kill Minecraft after N seconds |
My programming background is mainly web development. While I've been picking up Rust along the way, this project was born out of necessity rather than passion for the language or a desire to practice it. I needed a solid Minecraft Java launcher core in Rust and there are very few options that actually cover what this project aims to do.
Because of that, the code is — in principle — 100% AI-generated. If this ends up public it isn't a "look what I can build" statement. It's closer to "I built this, it's useful to me, and maybe it'll be useful to someone else too."
Bug reports, improvements, and pull requests are genuinely welcome.
MIT