CLI
s3nd from a terminal: move a file between machines, and check that a bucket is actually set up to hold transfers.
@s3nd/cli is its own package, built on s3nd as a primitive — so nothing a command
line needs ships to your server.
npx @s3nd/cli doctorOr globally, for the drop-box use:
npm install -g @s3nd/cli
s3nd put ./report.pdfIt has no dependencies of its own beyond s3nd: node:util's parseArgs is the whole
argument parser.
doctor
The command worth running first. S3 misconfiguration fails late and vaguely — a policy that looks
right, credentials that resolve to nothing, a region the endpoint disagrees with. doctor turns
all of that into a list:
$ s3nd doctor
✓ Configuration: bucket "transfers", region "eu-west-3"
✓ Credentials: resolved, key ends in 1234
✓ Bucket reachable: HeadBucket succeeded
✓ Write, read, delete: round-tripped a probe object
! Expiry cleanup: no enabled expiration rule
→ Add an S3 lifecycle rule that expires objects under this bucket after a day or
two. Without it, expired transfers stay stored and billed.
1 check(s) failed.It does not read your policy and reason about it; it performs the three operations s3nd needs and reports what actually happened. The probe object is deleted before it returns.
That last check is the one that earns the command. expiresIn stops a transfer being handed
over; only a lifecycle rule deletes the object. Nothing surfaces the gap until a bill does.
Pointed at a server, doctor checks the only thing that matters there — a real round trip:
$ s3nd doctor --remote https://drop.example.com/api/transfers --token "$TOKEN"
✓ Server: https://drop.example.com/api/transfers answered
✓ Create, read, delete: round-tripped code 8WTXQC8Rput, get, rm
$ s3nd put ./report.pdf
report.pdf, 284 kB, expires 14/09/2026 10:25
K7QP2M4XThe code goes to stdout and everything else to stderr, so it composes:
CODE=$(s3nd put ./report.pdf)On the other machine:
$ s3nd get K7QP2M4X
Wrote report.pdf (284 kB)
$ s3nd rm K7QP2M4X
Burned K7QP2M4Xget writes to the stored filename unless you pass -o; -o - sends the payload to stdout.
A code holding a snapshot rather than a file prints its JSON instead.
Against your own server
Every command takes --remote, which points it at a deployment of
the transfer protocol instead of at S3:
s3nd --remote https://drop.example.com/api/transfers put ./report.pdfThis is not a second implementation. The CLI has exactly one — the protocol client — wired either
to fetch or, without --remote, straight into the handler in the same process. The two modes
cannot drift apart, because there is only one of them.
The practical consequence: your laptop needs no S3 credentials. It holds a token for your own deployment, which holds the credentials.
Options
| Option | What it does |
|---|---|
--remote <url> | Talk to a s3nd server instead of S3 directly |
--token <token> | Bearer token sent with --remote |
--bucket <name> | Bucket name, overriding $S3ND_BUCKET |
--prefix <prefix> | Key prefix inside the bucket |
--expires-in <secs> | Transfer lifetime; 0 for one that does not expire |
-o, --output <path> | Where get writes. - is stdout |
--json | Machine-readable output, for scripts and for doctor in CI |
Configuration otherwise comes from the same environment variables as the library —
S3ND_BUCKET, S3ND_REGION, S3ND_ENDPOINT, and the usual AWS credentials.
See configuration.
s3nd doctor --json exits non-zero when a check fails, so it works as a deployment smoke test.