Release Builds & Cross-Compilation
The Node.js deployment problem
Section titled “The Node.js deployment problem”When you ship a Node.js application you must also ship Node itself — the runtime, node_modules, and all transitive dependencies. The result is typically hundreds of megabytes. Deployment usually means bundling with esbuild/webpack, writing a Dockerfile that installs Node, or using a PaaS that knows how to run Node.
Rust compiles to a single self-contained binary. There is no runtime to ship, no node_modules, and no interpreter. The binary runs directly on the OS.
# TypeScript / Node.js deployment# You must ship the runtime + all packagesdist/ index.js # your bundled appnode_modules/ # 300+ MB of dependencies# ... plus you need Node installed on the server
# Or use Docker:FROM node:20-alpineCOPY package*.json ./RUN npm ci --only=productionCOPY dist/ ./dist/CMD ["node", "dist/index.js"]# Rust deployment# Build once, ship the binarycargo build --release# → target/release/my-app (single static binary, ~5 MB)
# Copy the binary to the server — that's it.# No runtime, no package manager, no node_modules.scp target/release/my-app user@server:/usr/local/bin/Debug vs release builds
Section titled “Debug vs release builds”cargo build # debug build: fast compile, unoptimised, includes debug infocargo build --release # release build: slow compile, fully optimised (LLVM -O3)cargo run --release # compile in release mode and runThe debug build is what you use during development — it compiles in seconds. The release build can take minutes on large projects but produces a binary that is often 10–100× faster at runtime.
Cross-compilation
Section titled “Cross-compilation”Rust supports cross-compilation out of the box. A target triple identifies the OS + architecture + ABI combination.
# Add a cross-compilation targetrustup target add x86_64-unknown-linux-musl # Linux, statically linked (musl libc)rustup target add aarch64-unknown-linux-gnu # Linux, ARM64 (Raspberry Pi, AWS Graviton)rustup target add x86_64-pc-windows-gnu # Windows from macOS/Linux
# Compile for a different targetcargo build --release --target x86_64-unknown-linux-musl# → target/x86_64-unknown-linux-musl/release/my-appStatic binaries with musl
Section titled “Static binaries with musl”The x86_64-unknown-linux-musl target links against musl libc instead of glibc, producing a fully static binary that runs on any Linux distribution — including Alpine Linux containers — without any shared library dependencies.
# One-time setuprustup target add x86_64-unknown-linux-musl
# On macOS you need a cross-linker; easiest via cargo-zigbuild:cargo install cargo-zigbuildcargo zigbuild --release --target x86_64-unknown-linux-musl
# Verify: the binary has no dynamic dependenciesldd target/x86_64-unknown-linux-musl/release/my-app# → not a dynamic executableOptimisation profile in Cargo.toml
Section titled “Optimisation profile in Cargo.toml”[profile.release]opt-level = 3 # maximum LLVM optimisation (default)lto = true # link-time optimisation: smaller + faster binarycodegen-units = 1 # single codegen unit: slower compile, better optimisationstrip = true # strip debug symbols from the binarypanic = "abort" # abort on panic instead of unwinding (smaller binary)These are all
bash/tomlconfigurations. There is no browser Playground for cross-compilation — run these commands in your terminal after installing Rust via rustup.rs.