Prerequisites
Before installing whatsapp-rust, ensure you have:- Rust nightly (default) — required for Rust edition 2024 and SIMD-optimized binary protocol. The project pins
nightly-2026-04-05viarust-toolchain.toml. See Using stable Rust if you need stable toolchain support. - Cargo package manager
SQLite is bundled by default with the
whatsapp-rust-sqlite-storage crate, so you don’t need to install it separately. If you prefer to link against a system-installed SQLite, disable the default bundled-sqlite feature.Add to your project
whatsapp-rust re-exports the entire stack (wacore, wacore_binary, waproto, and all bundled implementations), so one dependency line is enough for most projects:
Cargo.toml
whatsapp_rust::waproto::whatsapp(aliased aswainprelude)whatsapp_rust::wacore,whatsapp_rust::wacore_binarywhatsapp_rust::store::SqliteStore,whatsapp_rust::http::UreqHttpClient,whatsapp_rust::transport::TokioWebSocketTransportFactory
whatsapp-rust also re-exports every third-party crate whose types appear in its public API, so you never need to add or version-pin any of these yourself:
whatsapp_rust::buffa— sub-message fields onwa::Message(MessageField; also re-exported directly fromprelude) — see waprotowhatsapp_rust::anyhow— the error type on the store/transport/InboundDurabilityHooktraitswhatsapp_rust::async_trait— the macro required to implement those traitswhatsapp_rust::bytes—Transport::sendpayloadswhatsapp_rust::chrono— timestamps returned bywacore::timeand message metadatawhatsapp_rust::futures— theoneshot::Receiverreturned by response-waiting accessorswhatsapp_rust::serde,whatsapp_rust::serde_json,whatsapp_rust::async_channel
This is purely additive — you can still add any of these crates directly (for example to pin your own version, or to use APIs beyond what whatsapp-rust re-exports).
Cargo.toml
Feature flags
whatsapp-rust supports several optional features:
The
wacore crate has an additional feature for WASM browser targets:
To use whatsapp-rust in a WASM browser environment, enable the
js feature on wacore:
Cargo.toml
waproto crate has its own feature flags:
build.rs always runs and generates whatsapp.rs into OUT_DIR — you do not need any feature flag for normal builds. All protobuf types derive Serialize by default. Enable serde-deserialize when you need to parse protobuf types from JSON (e.g., in a WASM bridge). Enable serde-snake-case when your JSON source uses snake_case for enum variants (buffa generates SCREAMING_SNAKE_CASE by default).
Cargo.toml
whatsapp-rust-sqlite-storage crate has its own feature flags:
To use a system-installed SQLite instead of the bundled version:
Cargo.toml
whatsapp-rust-chat-store crate — an event-sourced SQLite chat/message history store, not re-exported through whatsapp-rust — has its own feature flag:
Cargo.toml
search feature:
Cargo.toml
The default features provide everything needed for most use cases. Only customize features if you have specific requirements.
Using stable Rust
By default, whatsapp-rust uses Rust edition 2024 and enables thesimd feature, which uses Rust’s portable_simd API for optimized binary protocol encoding/decoding. Both of these require a nightly Rust toolchain. The project pins nightly-2026-04-05 via rust-toolchain.toml.
To compile on stable Rust, disable the simd feature by setting default-features = false. You must do this on both whatsapp-rust and wacore — otherwise Cargo’s feature unification will re-enable SIMD through the wacore dependency:
Cargo.toml
32-bit target support
whatsapp-rust usesportable-atomic instead of std::sync::atomic for 64-bit atomic operations. This means the library works on 32-bit targets (ARM32, MIPS, RISC-V 32, etc.) where AtomicU64 is not natively available — portable-atomic provides a software fallback automatically.
No extra configuration is needed. The portable-atomic dependency is included with the fallback feature enabled by default across all crates (whatsapp-rust, wacore, and whatsapp-rust-sqlite-storage).
Custom features example
If you want to use only specific features:Cargo.toml
Verify installation
Create a simple test file to verify the installation:src/main.rs
Docker deployment
whatsapp-rust ships a pre-built multi-arch image to GHCR and includes a Dockerfile for building your own. The runtime image is built fromscratch (only the static binary) and runs unprivileged as uid 65532.
Pre-built image
Pull from GitHub Container Registry — a single manifest resolves tolinux/amd64 or linux/arm64 automatically based on the host:
ghcr.io/oxidezap/whatsapp-rust:0.6.0). The image is published on every push to main, on v* tags, and can be triggered manually via the Actions tab.
Build from source
- Uses
rust:alpinewith cargo-chef (pinned to a fixed release with--locked) for efficient, reproducible dependency caching - Detects the host target triple at build time —
docker buildx build --platform linux/arm64produces native binaries without Dockerfile changes - Enables
-Zshare-generics=y(−5.6%.text) and recompilesstdwith the release profile (-Zbuild-std, −~300 KiB more) so it participates in fat LTO — together these two flags reduce.textby roughly 8%; the full optimization series (#842–#845) achieved 15% total - Caches dependency compilation via
cargo chef cook --targetin a separate layer for fast rebuilds - Produces a final image from
scratchcontaining only the binary
Run the container
Use a named volume for/data. The container runs as uid 65532 and a named volume inherits that ownership automatically, so the SQLite database stays writable without extra setup:
--phone flag:
Host bind mounts (e.g.
-v ./data:/data) require the host directory to be owned by uid 65532, otherwise the container cannot write the database. Named volumes don’t have this requirement.Upgrading from an older image
Images before this release ran as root. If an existing named volume has root-owned files, chown it once before restarting:Graceful shutdown
The container supports graceful shutdown out of the box. When thesignal feature is enabled (it is by default), the bot listens for SIGTERM and Ctrl+C, disconnects cleanly from WhatsApp, and exits. Docker sends SIGTERM on docker stop, so the bot will shut down gracefully without losing session state.
Since the image is built from scratch, PID 1 is the binary itself. It handles signals directly — no init system like tini is needed. This matters more than usual for PID 1: the kernel silently drops any signal a PID-1 process has no handler installed for, so an unhandled SIGTERM doesn’t just fall back to the default disposition — it’s dropped entirely, and the process only stops once docker stop’s grace period expires and it’s SIGKILLed.
The bundled demo and voip-cli binaries get this via whatsapp_rust::shutdown_signal() — an exported async fn (gated on the signal feature) that resolves on the first of SIGINT or SIGTERM on Unix, or Ctrl+C elsewhere. Both handlers are armed before the future first suspends, so a signal arriving right after the first poll is still delivered. Use it in your own main() in place of a bare tokio::signal::ctrl_c() if you also deploy under Docker/Kubernetes/systemd:
The Dockerfile detects the host target triple at build time via
rustc -vV, so docker buildx build --platform linux/arm64 (or any other supported platform) works natively without modifying the Dockerfile. The nightly-only build flags (-Zshare-generics, -Zbuild-std) apply only inside this image — stable consumers and local cargo build invocations are unaffected.Next steps
Quickstart
Build your first WhatsApp bot in minutes