The Problem
LocalSend solves device-to-device file sharing without internet connectivity or third-party servers. AirDrop locks this capability to Apple's ecosystem; most cross-platform alternatives require a cloud relay, which introduces latency and privacy concerns. LocalSend uses a local REST API with HTTPS encryption, so devices on the same network can exchange files directly.
What This Does
This repository is a fork of the popular localsend/localsend project (89,995 stars upstream). It contains four self-contained projects: the app/ directory holds the Flutter client (576 files, including Android, iOS, Windows, Linux, and web targets), cli/ is a Rust-based command-line client (21 files), server/ is a Rust-based headless server (16 files), and packages/ contains shared Dart and Rust libraries (216 files). The app/lib/main.dart is the primary Flutter entry point; cli/src/main.rs starts the Rust CLI.
The architecture is a portfolio rather than a monolith—each project is independently buildable. The Flutter app handles the UI and device discovery; the Rust components handle the protocol and isolated computation. The packages/localsend_isolates/ directory bridges Dart and Rust via Flutter's FFI, which is where the bulk of the non-UI logic lives.
How It Is Wired
The call graph shows a single internal module with zero import edges, meaning the repository's static analysis found no internal module dependencies—the projects are genuinely isolated. The most-connected module is packages/core/assets/web/main with zero inbound and outbound edges; this is a web asset, not a code hub.
For the Flutter app, execution starts at app/lib/main.dart, which initializes the UI and routes to screens like home_page.dart (device discovery and file selection) and progress_page.dart (transfer status). The apk_picker_page.dart handles Android package selection. The Rust CLI starts at cli/src/main.rs and uses packages/core/Cargo.toml for shared types. The server's server/Dockerfile packages the headless daemon.
The wiring between Dart and Rust flows through packages/localsend_isolates/lib/rust/frb_generated.dart (4,987 lines), which is the generated FFI bridge. This file is the widest blast radius—any change to the Rust API regenerates this file and ripples into every caller.
How To Use It
# Clone the repository
git clone https://github.com/moses-y/localsend
cd localsend
# Build the Flutter app (requires Flutter SDK)
cd app
flutter pub get
flutter run
# Build the CLI (requires Rust toolchain)
cd ../cli
cargo build --release
./target/release/localsend-cli
# Build the server container
cd ../server
docker build -t localsend-server .
Configuration is minimal—no environment variables are required. The Flutter app uses app/pubspec.yaml for dependencies; the Rust projects use Cargo.toml. The server exposes a REST API on the local network; clients discover it via mDNS.
Real-World Use
A typical deployment is an office where employees need to transfer large files (e.g., design assets, video renders) without saturating the internet uplink. Run the server container on a NAS or workstation, have employees use the Flutter app or CLI on their laptops and phones. Transfers happen over LAN at full switch speed, with HTTPS encryption and no cloud dependency.
Code Health & Issues
Static analysis found 139 findings (29 high, 110 medium). The high-severity issues are:
- High - Deep nesting (56 instances):
app/lib/pages/apk_picker_page.dart,home_page.dart, andprogress_page.dartreach indentation depth 11, making control flow hard to follow. Fix with early returns and extracted guard clauses. - High - Duplicated code (1,561 repeated 6-line blocks across 171 files): concentrated in
app/lib/gen/strings_*.g.dart(generated localization files). Extract shared helpers rather than repeating. - High - Oversized files (3 instances): the
frb_generated.dartandfrb_generated.rsfiles are ~5,000 lines each—generated FFI bridges that are hard to review but should not be hand-edited.
The SDLC audit found two high-priority items: GitHub Actions use mutable @vN tags (e.g., flutter-actions/setup-flutter@v4), which is a supply-chain risk—pin to commit SHAs. CI workflows exist but none invoke the 25 test files present, so the green check is not verifying anything.
The Bottom Line
This is a well-structured fork of a proven project. The isolation of app, CLI, and server is clean, and the Rust/Dart split is sensible. The main risks are supply-chain (unpinned CI actions) and the fact that CI does not run tests. Use it if you need a local-only file transfer tool and want to customize the client or server; the generated FFI files and deep nesting are maintenance hazards but not blockers.