MoonBit is a programming language designed from the ground up for WebAssembly. It combines Rust-level performance with a developer experience closer to Go or TypeScript.
Why MoonBit Matters
Compiling to WebAssembly is an afterthought for most languages. MoonBit was designed for Wasm from day one — its type system, runtime, and compiler all optimize for the Wasm execution model, producing binaries 10x smaller than Rust's.
What you get for free:
- WebAssembly-first design (10x smaller than Rust Wasm output)
- Fast compilation (much faster than Rust)
- Pattern matching and algebraic data types
- Structural typing with traits
- Built-in package manager (moon)
- IDE support with Language Server Protocol
- No garbage collector needed for Wasm GC targets
Quick Start
# Install
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash
# Create project
moon new my-project
cd my-project
# Run
moon run
# Build Wasm
moon build --target wasm
# Test
moon test
The Basics
fn main {
let name = "MoonBit"
println("Hello from \{name}!")
let numbers = [1, 2, 3, 4, 5]
let doubled = numbers.map(fn(n) { n * 2 })
println(doubled.to_string())
let result = divide(10, 3)
match result {
Ok(value) => println("Result: \{value}")
Err(msg) => println("Error: \{msg}")
}
}
fn divide(a : Int, b : Int) -> Result[Int, String] {
if b == 0 {
Err("division by zero")
} else {
Ok(a / b)
}
}
Enums and Pattern Matching
enum Shape {
Circle(Double)
Rectangle(Double, Double)
Triangle(Double, Double, Double)
}
fn area(shape : Shape) -> Double {
match shape {
Circle(r) => 3.14159 * r * r
Rectangle(w, h) => w * h
Triangle(a, b, c) => {
let s = (a + b + c) / 2.0
@math.sqrt(s * (s - a) * (s - b) * (s - c))
}
}
}
fn main {
let shapes : Array[Shape] = [Circle(5.0), Rectangle(3.0, 4.0)]
for shape in shapes {
println("Area: \{area(shape)}")
}
}
Structs and Methods
struct User {
name : String
age : Int
email : String
}
fn User::new(name : String, age : Int, email : String) -> User {
{ name, age, email }
}
fn greet(self : User) -> String {
"Hello, \{self.name}! You are \{self.age} years old."
}
fn main {
let user = User::new("Alice", 30, "alice@example.com")
println(user.greet())
}
Traits
trait Printable {
to_display(Self) -> String
}
fn to_display(self : User) -> String {
"User(\{self.name}, \{self.age})"
}
fn print_all[T : Printable](items : Array[T]) -> Unit {
for item in items {
println(item.to_display())
}
}
Error Handling
type! ParseError {
InvalidFormat(String)
OutOfRange(Int)
}
fn parse_age(input : String) -> Int!ParseError {
let n = try {
@strconv.parse_int!(input)
} catch {
_ => raise InvalidFormat("not a number: \{input}")
}
if n < 0 || n > 150 {
raise OutOfRange(n)
}
n
}
fn main {
try {
let age = parse_age!("25")
println("Age: \{age}")
} catch {
InvalidFormat(msg) => println("Format error: \{msg}")
OutOfRange(n) => println("Out of range: \{n}")
}
}
Wasm Size Comparison
| Language | Hello World Wasm | Performance |
|---|---|---|
| MoonBit | ~5KB | Excellent |
| Rust | ~50KB | Excellent |
| Go | ~2MB | Good |
| AssemblyScript | ~15KB | Good |
Useful Links
Building WebAssembly applications? Check out my developer tools on Apify for ready-made web scrapers, or email spinov001@gmail.com for custom solutions.
Top comments (0)