A single binary is a self-contained executable file that includes everything needed to run the program: the application code, all libraries, and any required assets. Users download one file, make it executable, and run it. There are no package managers, dependency installations, or configuration files to manage.
This distribution model stands in contrast to traditional software installation where you run an installer, wait for dependencies to download, resolve version conflicts, and potentially restart your system. With a single binary, the entire process is: download, run, done.
Single binary vs traditional installation
| Aspect | Single binary | Traditional installation |
|---|---|---|
| Dependencies | Bundled inside the binary | Installed separately via package manager |
| Setup time | Immediate | May require minutes of downloading and configuring |
| Version conflicts | Impossible by design | Common when shared libraries differ |
| Portability | One file to copy or move | Multiple files and directories scattered across the system |
| Uninstall | Delete one file | Run uninstaller or track down scattered files |
| Size | Larger per binary (includes deps) | Smaller initial download, but deps add up |
| Offline use | Works immediately | May need to download deps on first run |
| Permissions | No admin rights needed | Often requires sudo or administrator access |
Why single binaries matter for developer tools
Developer and command-line tools benefit from single-binary distribution because:
- Fast onboarding - New users can start immediately without reading install guides or troubleshooting dependency issues
- CI/CD friendly - Easy to download and cache in build pipelines. A single URL gives you a deterministic artifact.
- Cross-platform - The same workflow works on macOS, Linux, and Windows. Download the right binary for your architecture and go.
- No privilege escalation - Users can install to any directory without
sudoor UAC prompts. This is especially important in restricted environments. - Version switching - Keep multiple versions side by side as separate files. Name them
crawler-v0.8.0andcrawler-v0.9.0and use whichever you need. - Reproducible environments - A specific binary version behaves identically everywhere. No “works on my machine” surprises caused by different system libraries.
- Air-gapped deployment - Copy the binary to a USB drive and install on machines with no internet access.
How single binaries are built
Languages like Go and Rust compile to native machine code and can statically link dependencies, producing true single binaries. The compiler pulls in all required libraries and bakes them into the executable. Other ecosystems use different techniques:
- Static linking - Bundling libraries at compile time rather than relying on dynamic linking at runtime. Rust’s
musltarget creates fully static Linux binaries. - Embedding assets - Including templates, images, fonts, or config files directly in the binary as byte arrays. Accessed at runtime as if they were files.
- UPX compression - Reducing binary size with executable packers. The binary self-extracts in memory when run.
- App bundling - Wrapping a runtime and application code into a single package. Electron and Tauri use this approach for desktop apps, though the result is larger than a pure native binary.
Static linking is the key technique. A dynamically linked binary depends on system libraries like libc being present and compatible. A statically linked binary has no external dependencies at all. It can run on a minimal container or a fresh operating system install.
Single binary examples in the wild
- Docker - Distributed as a single binary for Linux, though it typically runs as a daemon
- Terraform - A single binary that provides infrastructure-as-code across all platforms
- ** ripgrep** - A fast search tool distributed as a single static binary
- hugo - A static site generator that runs from one file
- crawler.sh - A web crawler and SEO analyzer in a single file
Limitations of single binaries
- Size - Bundling all dependencies increases file size. A Rust CLI might be 5-15MB versus a Python script of a few kilobytes. However, the Python script requires a 100MB+ runtime.
- Updates - No built-in package manager update mechanism. Tools must implement their own update checks or rely on external scripts.
- Plugin systems - Harder to support dynamic plugins since everything is baked in. Some tools work around this by loading plugins from external files at runtime.
- Platform specificity - You need a separate binary for each operating system and architecture combination (macOS ARM64, macOS x64, Linux ARM64, Linux x64, Windows).
How crawler.sh is distributed
crawler.sh is distributed as a single static binary for macOS and Linux. The install script detects the operating system and architecture, downloads the correct binary to ~/.crawler/bin/, and adds it to the shell PATH. There is no package manager, no dependency resolution, and no runtime to install.
The install process takes approximately five seconds on a typical connection:
curl -fsSL https://install.crawler.sh | shThe binary includes the crawling engine, JavaScript rendering engine, output writers, SEO analysis logic, and all command-line interfaces. It can run entirely offline after download. The desktop app is similarly self-contained, distributed as a signed DMG on macOS and a .deb package on Linux.