airbridge
v0.1.0
Published
Fast local-network file transfer between any two devices. No install, no account, no cloud.
Maintainers
Readme
AirBridge
Fast file transfer between any two devices on the same network. Phone to laptop, laptop to phone, Android to iPhone, iPhone to Windows — any direction.
No install on the receiving device, no account, no cloud upload. Nothing leaves your network.
npx airbridge --httpsScan the QR that appears in your terminal. That's the whole setup.
Measured throughput
size time throughput
─────────────────────────────────────────
100 MB 0.86 s 116.3 MB/s 975 Mbps
300 MB 1.98 s 151.3 MB/s 1269 Mbps
500 MB 2.43 s 205.6 MB/s 1725 Mbps
1024 MB 4.47 s 228.9 MB/s 1921 MbpsReproduce it yourself: npm run bench.
That is the transport ceiling measured on loopback, so it excludes the physical network. On real Wi-Fi your router is the limit — roughly 30–60 MB/s on Wi-Fi 5, 60–110 MB/s on Wi-Fi 6, ~112 MB/s on gigabit Ethernet. The point is that the software is not the bottleneck.
These numbers are only reachable on a local network. Sending 500 MB in 10 seconds needs 400 Mbps sustained; no home internet connection uploads that fast. AirBridge is fast because the bytes never leave the building.
Running it
Needs Node 18+ on one machine — usually the laptop. The other device needs nothing but a browser.
npx airbridge --https # recommendedThe terminal prints a scannable QR code and the URLs:
AirBridge server — HTTPS
─────────────────────────────────────────
Local: https://localhost:3000
Network: https://192.168.68.100:3000
Scan this with the phone:
█▀▀▀▀▀█ ▀▄█▄▀ █▀▀▀▀▀█
█ ███ █ ▀▄ ▄▀ █ ███ █
█▄▄▄▄▄█ █▄▀▄█ █▄▄▄▄▄█
https://192.168.68.100:3000/#r=TZ26SU- Scan the QR with the phone.
- Open the same link on the laptop.
- Each device warns once about the certificate — accept it. Chrome and Edge: Advanced → Proceed. iOS Safari: Show Details → visit this website. Your own machine issued it; nothing leaves your network.
- Drop a file, pick the other device, accept on that side.
Why --https
Plain HTTP works, but browsers do not treat it as a secure context, so
showSaveFilePicker is unavailable and the receiving device assembles the whole
file in memory instead of streaming it to disk. Fine for small files, a problem
at a gigabyte. HTTPS costs one certificate prompt per device, once.
To skip the prompt entirely, see Tailscale below.
Options
npx airbridge --https Serve over HTTPS (recommended)
npx airbridge --port 3005 Use a different port
npx airbridge --help
npm run doctor Check your setup and print what to fix
npm run bench Measure transport throughput
npm test Run all four test suitesAway from the same Wi-Fi
Install Tailscale on both devices and sign in with the same account. AirBridge detects it automatically and offers a "Tailnet · works anywhere" entry in the QR picker.
Tailscale is a WireGuard mesh, so devices connect directly. On the same Wi-Fi it routes over the LAN and you keep full local speed. Elsewhere it is still peer to peer, bounded by your upload rather than by a middleman.
For a certificate browsers trust silently — no prompt, and large files stream to disk:
tailscale cert <your-machine>.<your-tailnet>.ts.netDrop the resulting .crt and .key into certs/ and AirBridge prefers them.
Do not use a tunnel — ngrok, Cloudflare Tunnel, or similar. They route every byte through a datacenter and back, which is two internet round trips for data that could cross the room. A tunnel destroys the exact property that makes this fast, and Cloudflare's free tier additionally caps request bodies at 100 MB.
How it works
Discover ──▶ Consent ──▶ Connect ──▶ Transfer ──▶ Verify ──▶ Save
QR + room explicit SDP/ICE bytes SHA-256 to disk
accept
├──────── control messages ────────┤├───── file bytes ───────┤Two transports, chosen automatically:
On a local network the bytes stream through this server over plain TCP. Nothing is buffered, nothing touches disk on the way through, and the sender is paced by the receiver's own backpressure. The "server" is your own machine — one of the two devices in the transfer — so no third party ever holds the file.
This exists because a WebRTC data channel is slower on a LAN: SCTP-over-DTLS is congestion-window bound and settles well below link speed, while plain TCP to a box on the same switch reaches wire speed.
Everywhere else the file goes peer to peer over WebRTC, striped across several data channels so their congestion windows fill in parallel. Each stripe owns a byte range and is written at its absolute offset, so nothing needs reordering on arrival.
Either way:
- Integrity — SHA-256 computed on both sides over the original bytes, per stripe, in a Web Worker. A mismatch discards the file rather than saving a corrupt one.
- Consent — nothing transfers without an explicit accept. Verified: a request left unanswered moves zero bytes.
- Memory — bounded regardless of file size. The sender never holds more than one block; the receiver streams to disk.
- Compression — measured per file by sampling its middle, never guessed from the extension. Used only when it genuinely helps, so video and archives are sent raw instead of wasting CPU on them.
- Rooms — you only see devices that scanned the same code.
Limits worth knowing
Some of these are browser limits with no workaround. They are stated plainly because discovering them mid-transfer is worse.
- 5 GB per file.
- AirDrop, Quick Share and Nearby Share cannot be reached. They are closed protocols over Bluetooth LE and AWDL with vendor-signed certificates. No browser API and no extension permission opens them. Turning AirDrop on does not make a device visible here.
- No Wi-Fi Direct, raw UDP, mDNS or kernel zero-copy (
sendfile,splice,mmap) — none are exposed to browsers. - No peer-to-peer QUIC. WebTransport is QUIC but client-to-server only.
- Safari has no File System Access API, so a receiving Safari device assembles files in memory. Warned above 256 MB, refused above 2 GB rather than crashing the tab at 80%.
Development
git clone https://github.com/aniketkrs/airbridge
cd airbridge
npm install
npm run devbin/ npx entry point
server/ Express + ws signalling, HTTP relay, TLS
public/ Client — no build step
js/relay.js LAN fast path
js/transfer.js WebRTC striped path
js/hasher.js streaming SHA-256 in a worker
scripts/ Test suites and the benchmarkTests:
npm test # SHA-256 · address classification · relay · signallingscripts/smoke-signaling.mjs also asserts the core guarantee: with
AIRBRIDGE_AUDIT=1 the server logs every relayed message type, and the test
fails if anything other than a control message appears on the signalling path.
License
MIT
