# s3nd with MinIO

> Move files and local-first app data through a MinIO bucket with s3nd: the createBucket() configuration, the CLI starter, and what to know about this provider.

Canonical: https://www.s3nd.sh/providers/minio · Markdown: https://www.s3nd.sh/providers/minio.md · Français: https://www.s3nd.sh/fr/providers/minio

One Docker command, and the real code path runs on your laptop and in CI.

**createBucket()**
```ts
import { createBucket } from '@s3nd/core'

const store = createBucket({
  bucket: 'transfers',
  endpoint: 'http://localhost:9000',
  credentials: { accessKeyId: 'minioadmin', secretAccessKey: 'minioadmin' },
})
```

## Why this one
A local MinIO is the cheapest way to exercise s3nd for real: the same PutObject with the same conditional headers, no credentials to create and no network to wait on. The examples in the repository point at it by default.

## A starter configuration, and what is left to do.
init writes the file with ${VAR} references rather than secrets, so it is meant to be committed; the env file it points at is not.

```sh
s3nd init --provider minio --bucket transfers
```
**s3nd.config.json**
```json
{
  "bucket": "transfers",
  "endpoint": "http://localhost:9000",
  "forcePathStyle": true,
  "prefix": "transfers",
  "expiresIn": "1h",
  "credentials": { "accessKeyId": "minioadmin", "secretAccessKey": "minioadmin" }
}
```

### Then
1. docker run -p 9000:9000 -p 9001:9001 -e MINIO_ROOT_USER=minioadmin -e MINIO_ROOT_PASSWORD=minioadmin quay.io/minio/minio server /data --console-address ":9001"
2. Create the transfers bucket from the console on http://localhost:9001.
3. Run `s3nd doctor`. It performs the operations s3nd needs and reports what happened.

## Notes on MinIO.
- **Path-style addressing** — Self-hosted gateways require https://endpoint/bucket/key. Setting an endpoint turns it on; the starter configuration writes it explicitly so the intent is visible.
- **Self-hosted in production too** — The same configuration, with real credentials and TLS, runs against a MinIO cluster or any Ceph, Garage or SeaweedFS gateway that implements conditional PutObject.
- **Expiry cleanup** — expiresIn stops a transfer being handed over; only a lifecycle rule deletes the object. Give the prefix a rule that expires objects after a day or two, and s3nd doctor turns green.

[The full guide](https://doc.s3nd.sh/docs/providers)
