# Installation

> Install s3nd and give it credentials.

Canonical: https://doc.s3nd.sh/docs/installation · Markdown: https://doc.s3nd.sh/docs/installation.md

Not sure which package you need? [Quick start](https://doc.s3nd.sh/docs/quick-start) starts from what you are building
and installs only that.

```sh
npm install @s3nd/core
```

```sh
pnpm add @s3nd/core
```

```sh
yarn add @s3nd/core
```

```sh
bun add @s3nd/core
```

That is the server-side package. Depending on what you are building you may want one of the
others instead, or as well:

| Package          | Install it when                                                   |
| ---------------- | ----------------------------------------------------------------- |
| `@s3nd/core`     | Your server talks to the bucket. Brings the AWS SDK.              |
| `@s3nd/react`    | Your React app sends or receives transfers. Never pulls the SDK.  |
| `@s3nd/cli`      | You want the `s3nd` command. Install it globally.                 |
| `@s3nd/protocol` | You are writing a client or server for a runtime the others miss. |

`@s3nd/react` depends on `@s3nd/protocol`, never on `s3nd`, so a front-end
install does not drag a storage client into `node_modules`.

Node 20 or later — that is what AWS SDK v3 requires. `@aws-sdk/client-s3` and
`@aws-sdk/s3-request-presigner` come along as dependencies, so there is nothing else to install
and no peer dependency to satisfy.

The package ships ESM and CommonJS builds with TypeScript declarations for both, so `import` and
`require` both work. It runs on your server only — there is no browser build, and no code path
that would put credentials in front of a user.

## Credentials

s3nd never asks for credentials it does not need. Pass them explicitly:

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

const store = createBucket({
  bucket: 'my-bucket',
  region: 'eu-west-3',
  credentials: {
    accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
    secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
  },
})
```

Or omit them and let the AWS default provider chain do its job — environment variables, the shared
config file, an EC2 instance role, an ECS task role, a Lambda execution role:

```ts
const store = createBucket({ bucket: 'my-bucket', region: 'eu-west-3' })
```

On a managed runtime, the role is the better answer: nothing to rotate and nothing to leak.

## Environment variables

Every option except `client` falls back to an environment variable, so with `S3_BUCKET` and the
usual `AWS_*` variables set, this is enough:

```ts
const store = createBucket()
```

See [Configuration](https://doc.s3nd.sh/docs/configuration) for the full list.

## IAM permissions

The minimum policy for a bucket used by s3nd:

```json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject"],
      "Resource": "arn:aws:s3:::my-bucket/*"
    }
  ]
}
```

`getUrl()` needs no extra permission: presigning is a local computation over the credentials you
already hold. The URL it produces grants exactly the `s3:GetObject` your own credentials have.

Snapshots need nothing beyond these three. `putSnapshot()` is a `PutObject`, `getSnapshot()` is a
`GetObject`, and the conditional writes ride along as headers on the same call.
