s3nd

Duration
4 weeks
Date
August – September 2026
Website
s3nd.sh
Documentation
doc.s3nd.sh
Live demo
drop.s3nd.sh
Source code
GitHub
The s3nd launch film
The s3nd.sh homepage: send anything with a code, the sync code on a split-flap board
The s3nd.sh homepage: send anything with a code, the sync code on a split-flap board
The drop box after sending: the eight-character code, the link and a QR code
The drop box after sending: the eight-character code, the link and a QR code
+13

Preface

$ s3nd put ./report.pdf
report.pdf · 284 kB · expires in 1 day
K7QP2M4X

# any other machine
$ s3nd get k7qp-2m4x
Wrote /home/you/report.pdf · 284 kB

s3nd sends anything with a code, through your own bucket. The bytes go from one machine to an S3 bucket you own, and from the bucket to the other machine. Nothing streams through anyone else's server, nobody signs up for anything, and there is nothing to deploy. Eight characters, forty bits, no I, L, O or U: read it over the phone, type it in the wrong case with a dash in the middle, it still resolves.

The same primitive works inside an app. A local-first app keeps everything in IndexedDB, then the user opens it on a new phone and it is empty. s3nd wraps that state in a self-describing, gzipped snapshot, stores it under a code, and the user types the code on the next device. Credentials stay on the server; the browser only ever talks to the app's own API.

The project started as bucketcode, a small library I extracted from TripBrain. It grew a CLI, React hooks, a wire protocol and a drop box, so it was renamed s3nd and moved to a monorepo with its full history. The old repository is archived and bucketcode is deprecated on npm in favour of the @s3nd/* packages; a snapshot written by it still reads back.

Stacks involved

  • TypeScript, Node.js 20+, ESM and CommonJS builds with bundled types
  • AWS SDK v3 for S3, compatible with AWS S3, Cloudflare R2, MinIO, Scaleway, Wasabi
  • React 19 hooks, Next.js 16 App Router, Tailwind 4
  • Fumadocs for the documentation site, shiki for build-time code samples
  • bun workspaces, Turborepo, tsup, Vitest
  • GitHub Actions, release-please, npm provenance, Vercel

Three ways in

  • From a terminal, @s3nd/cli: init, doctor, put, get, rm, straight to the bucket or through your own server with --remote
  • Inside your app, @s3nd/core on the server and @s3nd/react in the browser: one route file turns any bucket into a drop box
  • Anything that speaks HTTP, @s3nd/protocol: four routes, one error format, a typed client that bundles for a browser because it carries no storage client. curl works

Details

The architecture follows one constraint: a browser must never end up with a storage client in its dependency tree. @s3nd/protocol is the contract both halves share, which is why it exists as its own package rather than inside @s3nd/core. The React hooks depend on the protocol, never on S3.

@s3nd/protocol   nanoid                      the contract, shared by everything
@s3nd/core       + aws-sdk, protocol         the S3 primitive
@s3nd/react      + protocol, react (peer)    hooks, no path to S3
@s3nd/cli        + core                      the binary

Sync codes are the whole user experience of a transfer. Generation and normalisation come from the same configuration, so they can never disagree about the alphabet. Confusable characters are removed from the alphabet and repaired on input: k7qp-2m4x resolves to K7QP2M4X. The server picks the code and reserves it with a conditional write, so two senders can never claim the same one.

s3nd doctor is what makes the "first transfer in two minutes" promise hold. It performs every operation s3nd needs against the real bucket and reports what happened: credentials, reachability, a write, read and delete round trip, and whether a lifecycle rule will actually clean up expired transfers.

Every snapshot carries its own envelope version, distinct from the app's schema version, and maxVersion refuses a snapshot written by a newer schema. Compression is detected from the gzip magic bytes rather than assumed, which is how snapshots written by the old bucketcode still load.

Role

Solo project: product and API design, the four packages, the CLI, the website and its identity, the documentation, the drop box template, the examples and the release pipeline.

What I built

The packages

  • @s3nd/core: snapshots, files and a transfer handler on top of S3, with stable error codes and expiry enforced on read
  • @s3nd/cli: the s3nd binary with profiles, .env references instead of secrets in config, stdout for the code and stderr for the rest, so CODE=$(s3nd put ./report.pdf) composes
  • @s3nd/react: hooks to send a file or a snapshot, and a sync code input that repairs what the user typed
  • @s3nd/protocol: the wire contract, a fetch-based client and sync codes, with no storage client

The drop box

  • A small WeTransfer on your own bucket, live at drop.s3nd.sh and deployable as a one-click Vercel template
  • Preview before sending: image, video, audio, PDF, first lines of text
  • Per-transfer options: lifetime, password hashed with scrypt, burn after the first download, custom name, a message
  • Pickup page with a QR code, and the same four-route protocol so the CLI can talk to it

Website and documentation

  • s3nd.sh: a bilingual (EN / FR), fully static Next.js site with a split-flap departure-board identity, use cases, provider guides and comparison pages, plus llms.txt
  • doc.s3nd.sh: 22 documentation pages, from the quick start to the protocol, limits, testing and use cases such as encrypted sync
  • A 56-second launch film, the one at the top of this page, rendered entirely from code: every frame drawn on a canvas at 60 fps by headless Chromium, the soundtrack synthesised from sine waves and noise, both driven by the same cue sheet so each split-flap tile clicks on the frame it flips
  • Animated demos for the whole journey and for each package, recorded from the CLI's real output

Testing and releases

  • An offline test suite of more than 230 cases against an in-memory S3 double that honours conditional headers, run on Node 20, 22 and 24 in CI
  • release-please driven by conventional commits, four packages versioned independently, published to npm with provenance

Technical achievements

A library that became a product

bucketcode solved one narrow problem. s3nd keeps that core intact, snapshots written by bucketcode still read back, and builds the tools around it that make it usable by anyone: a terminal command, React hooks, a protocol, a drop box and a website.

Your bucket, nobody else's server

No relay, no account, no CORS policy to write, nothing to sign in the browser. The credentials stay where they belong and the code is the whole handshake.

In short

s3nd is an open-source way to move a file or an app's whole state from one device to another with an eight-character code, through a bucket you already own. Try it at drop.s3nd.sh, read the documentation, or npm install -g @s3nd/cli.

Similar projects

Homepage of onmangekoi
Homepage of onmangekoi on mobile
onmangekoi
onmangekoi
Duration
4 months
Date
April 2026
Homepage of tripbrain.fr with the live demo embedded in a phone mockup
The TripBrain roadbook on mobile
TripBrain
TripBrain
Duration
6 months
Date
March 2026
Homepage of Moenou
Homepage of Moenou mobile
Moenou
Moenou
Duration
6 months
Date
November 2024
Logo

© All rights reserved by Abderrahmane Mouzoune