s3nd

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 doctor

Or globally, for the drop-box use:

npm install -g @s3nd/cli
s3nd put ./report.pdf

It 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 8WTXQC8R

put, get, rm

$ s3nd put ./report.pdf
report.pdf, 284 kB, expires 14/09/2026 10:25
K7QP2M4X

The 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 K7QP2M4X

get 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.pdf

This 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

OptionWhat 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
--jsonMachine-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.

On this page