Build a WebAssembly Ready App in Rust (2025): Mini Project for Beginners🦀
Part of series: Rust Tutorial for Beginners: Learn the Rust Programming Language from Scratch and Build a WebAssembly Ready App (Article Series)
So far, you’ve picked up the basics of Rust — variables, functions, control flow, structs, enums, ownership. Now it’s time to bring all that together.
You can switch to video version of Rust Crash Course to the relevant chapter
In this article, we’ll walk through building a real-world Rust project from scratch: a reusable math library with a command-line interface (CLI) frontend. Along the way, you’ll learn how to structure your code with modules, separate logic cleanly, and even prepare for future WebAssembly (wasm) use..
Note we are NOT going to cover webassembly integration in this article. This series is about Rust programming language. You can refer to our Webassembly Rust Tutorial Video to learn how to do so.
You can switch to video version of Rust Crash Course to the relevant chapter
🔧 While we won’t compile it to Wasm in this part, the way we structure the app makes it portable for a follow-up where we’ll cover full WebAssembly deployment.
Let’s dive in.
🛠️ Step 1 — Create the Project
Let’s begin by creating a new binary Rust project:
cargo new rust_math_lib --bin
cd rust_math_lib
touch src/lib.rsUsing --bin creates an executable project with main.rs as the entry point — ideal for our CLI. We’ll also create a lib.rs, where the reusable logic will live.
🗂️ Step 2 — Create the Math Module
Inside src, let’s organize our math functionality into a dedicated folder:
mkdir src/math
touch src/math/mod.rs
touch src/math/operations.rsThen update src/lib.rs to declare the math module:
pub mod math;In src/math/mod.rs, wire in the operations submodule:
pub mod operations;Now, implement your math logic in src/math/operations.rs:
pub fn add(a: f64, b: f64) -> f64 {
a + b
}
pub fn subtract(a: f64, b: f64) -> f64 {
a - b
}
pub fn multiply(a: f64, b: f64) -> f64 {
a * b
}
pub fn divide(a: f64, b: f64) -> Option<f64> {
if b == 0.0 {
None
} else {
Some(a / b)
}
}These functions are intentionally simple — they focus on pure logic with no I/O, making them reusable and testable.
🧠
lib.rsis the gateway to your library code — it exposes modules likemath::operationsso other parts of the project (or external tools like WebAssembly) can use them.❓ Why use
Option<f64>instead ofResult<f64, String>?Since we’re targeting both CLI and WebAssembly, returning
Resultwith string errors would add unnecessary complexity in wasm contexts.Optionis simpler and works cleanly in both environments:Some(value)for success,Nonefor errors like division by zero.
💻 Step 3 — Build the CLI in main.rs
With the library in place, let’s write a CLI app in src/main.rs to use it:
use std::io;
use rust_math_lib::math::operations;
fn main() {
println!("Welcome to Rust Math CLI");
println!("Choose an operation: add, subtract, multiply, divide");
let mut operation = String::new();
io::stdin().read_line(&mut operation).unwrap();
let operation = operation.trim();
let mut input1 = String::new();
let mut input2 = String::new();
println!("Enter first number:");
io::stdin().read_line(&mut input1).unwrap();
println!("Enter second number:");
io::stdin().read_line(&mut input2).unwrap();
let a: f64 = input1.trim().parse().unwrap();
let b: f64 = input2.trim().parse().unwrap();
let result = match operation {
"add" => Some(operations::add(a, b)),
"subtract" => Some(operations::subtract(a, b)),
"multiply" => Some(operations::multiply(a, b)),
"divide" => operations::divide(a, b),
_ => {
println!("Unknown operation");
None
}
};
match result {
Some(r) => println!("Result: {}", r),
None => println!("Could not compute result (maybe division by zero?)"),
}
}This CLI uses basic input/output and pattern matching — no external dependencies needed.
✅ Step 4 — Test It Out
Build and run your CLI:
cargo runTry each operation — including dividing by zero — and you’ll see how your CLI handles it with clean, readable Rust code.
🌐 Step 5 — Why This Is WebAssembly-Ready
So far, we’ve been using this app in the terminal. But here’s the exciting part: this exact library can be compiled to WebAssembly and run in the browser.
🧠 WebAssembly (wasm) allows high-performance languages like Rust to run safely inside modern browsers — right alongside JavaScript.
Because our logic is separated into a lib.rs and math/operations.rs, and doesn't rely on stdin/stdout, it's already wasm-compatible.
Get Ali Aslam’s stories in your inbox
Join Medium for free to get updates from this writer.
You don’t need to rewrite anything. The same functions used by the CLI can be exposed to JavaScript with minimal setup.
💡 If you’ve seen our “Rust + WebAssembly: Hello World” video, you already know the basics of setting up wasm-pack, exporting functions with
#[wasm_bindgen], and calling Rust code from JS.
We’ll cover this exact library’s wasm conversion in a future tutorial — but if you’re curious, you’re already 90% there.
And again, our use of Option<f64> instead of Result<f64, String> avoids wasm’s string-handling complexities.
🧠 Summary
You just built a modular Rust app that:
- ✅ Organizes reusable logic in a clean folder structure
- ✅ Runs in the terminal as a simple CLI tool
- ✅ Is ready to be reused in WebAssembly — or published as a crate
🎯 “Mini projects like this are perfect to reinforce concepts. They give you confidence while preparing for real-world development.”
Next up: Crates, External Libraries, and Cargo Ecosystem ➡️







