# CreateBucket

CreateBucket makes a new, empty bucket - the container your objects live in. The bucket is created
in the region of the endpoint that receives the request, so a request to `s3.eu-central-1.strg.com`
creates a bucket in `eu-central-1`, and the endpoint you talk to is all it takes to choose where your
data lives. Bucket names are unique across all of STRG, exactly as on Amazon S3.

**Info: Good to know on STRG**

- The endpoint decides the region, so there is nothing else to keep in step with it. A
  `LocationConstraint` may name the endpoint's own region or be left out; one naming another
  region gets `400 InvalidLocationConstraint`, which tells you which endpoint to use instead.
- Your first bucket in a region is created here too. STRG sets up your storage in that region
  first, which makes the request take a little longer, and the access key the request was signed
  with is set up for that region as well, so its next request there just works. In a region where
  you store nothing yet, every other operation answers the plain truth: `404 NoSuchBucket` for a
  bucket operation, an empty `ListBuckets` result, `501 NotImplemented` for an unsupported
  operation.
- Bucket names are 3-58 characters, rather than Amazon S3's 3-63.
- `x-amz-acl` takes `private` (the default) and `public-read`, which map straight onto the
  dashboard's *Bucket Protection* setting. Grants and `x-amz-object-ownership` get
  `501 NotImplemented`, so a client knows straight away.
- Object Lock is switched on in a second step: `x-amz-bucket-object-lock-enabled: true` gets
  `501 NotImplemented`, and [PutObjectLockConfiguration](https://docs.strg.com/s3-api/PutObjectLockConfiguration) enables
  it once the bucket exists.
- Asking for a bucket you already own answers `409 BucketAlreadyOwnedByYou` in every region,
  `us-east-1` included - the same answer wherever you send it.
- A creation can take up to about 90 seconds - a first bucket in a region above all. One still
  running after that answers `503 SlowDown`, and the same request sent again picks up the creation
  already in progress.
- The key needs *Manage buckets*, which an all-buckets key can hold.
- A bucket deleted and re-created under the same name is a new bucket, and an access key limited
  to the old one does not reach it. [Access keys](https://docs.strg.com/access-keys) explains why.

## When you'd use it

- **Setting up a new project.** A deploy script or an infrastructure tool creates the buckets an
  application needs - `my-app-uploads`, `my-app-backups` - the first time it runs, in the region
  closest to its users.
- **Storing data in a new region.** A team serving customers in Europe creates its first bucket in
  `eu-central-1` by sending CreateBucket to that region's endpoint; STRG sets the region up as
  part of the same request.
- **Tools that create their own bucket.** Backup tools, log shippers and many S3-aware applications
  create the bucket they were configured with if it is not there yet. With an all-buckets key that
  holds *Manage buckets*, they do that against STRG as they would against Amazon S3.
- **An agent organising its work.** An AI agent can create a bucket for a new task - its memory, or
  the files it produces - and keep them apart from everything else.

## Request

```http
PUT / HTTP/1.1
Host: my-bucket.s3.eu-central-1.strg.com
Authorization: AWS4-HMAC-SHA256 Credential=...
x-amz-date: 20261005T120000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-acl: private
Content-Length: 0
```

Path-style, the same request is `PUT /my-bucket` on `s3.eu-central-1.strg.com`. A bucket name
containing a dot uses path-style; [Addressing](https://docs.strg.com/s3-api/overview#addressing) has the details.

### Permissions

The access key needs **Manage buckets** (`buckets:write`). This permission belongs to keys with
access to all buckets, so a key limited to some buckets gets `403 AccessDenied`.
[Access keys](https://docs.strg.com/access-keys) covers permissions and scope.

### URI parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `Bucket` | String | Yes | The name of the bucket to create. 3-58 characters: lowercase letters, digits, dots and hyphens, beginning and ending with a letter or digit, no two adjacent dots, and not formatted as an IPv4 address. Unique across all of STRG. |

### Request headers

Each `x-amz-*` header below may also be sent as a query parameter of a presigned URL.

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `x-amz-acl` | String | No | `private` (the default) or `public-read`. This is the bucket's *Bucket Protection* setting: `private` is *Protected*, `public-read` is *Public*. Any other canned ACL (`public-read-write`, `authenticated-read`) gets `501 NotImplemented`. |
| `x-amz-bucket-object-lock-enabled` | Boolean | No | `false`, or no header, creates the bucket without Object Lock. `true` gets `501 NotImplemented`; Object Lock is enabled once the bucket exists, with [PutObjectLockConfiguration](https://docs.strg.com/s3-api/PutObjectLockConfiguration). Any other value gets `400 InvalidArgument`. |
| `x-amz-grant-full-control` | String | No | STRG answers `501 NotImplemented`. |
| `x-amz-grant-read` | String | No | STRG answers `501 NotImplemented`. |
| `x-amz-grant-read-acp` | String | No | STRG answers `501 NotImplemented`. |
| `x-amz-grant-write` | String | No | STRG answers `501 NotImplemented`. |
| `x-amz-grant-write-acp` | String | No | STRG answers `501 NotImplemented`. |
| `x-amz-object-ownership` | String | No | STRG answers `501 NotImplemented`. |
| `x-amz-bucket-namespace` | String | No | Welcome, and has no effect: STRG has one bucket namespace, shared by all customers. |
| `Content-MD5` | String | No | Checked against the request body when one is sent. A mismatch is `400 BadDigest`. |

### Request body

Optional. An empty body creates the bucket in the endpoint's region.

```xml
<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <LocationConstraint>eu-central-1</LocationConstraint>
</CreateBucketConfiguration>
```

| Element | Required | Description |
| --- | --- | --- |
| `LocationConstraint` | No | The endpoint's own region, or empty. Another region gets `400 InvalidLocationConstraint`; that region's own endpoint is the one that creates buckets there. |
| `Location` | No | STRG answers `501 NotImplemented`. |
| `Bucket` | No | STRG answers `501 NotImplemented`. |
| `Tags` | No | STRG answers `501 NotImplemented`. |

Any other element, or a root element other than `CreateBucketConfiguration`, gets
`400 MalformedXML`.

## Response

### Response headers

| Name | Description |
| --- | --- |
| `Location` | `/` followed by the bucket name, for example `/my-bucket`. |
| `x-amz-request-id` | The request ID, handy for a support request. |

`x-amz-bucket-arn` is not part of the response.

### Response body

None. A successful request answers `200 OK` with an empty body.

## Errors

These are the answers CreateBucket can give besides `200 OK`, and the situation behind each.

| Code | HTTP status | When |
| --- | --- | --- |
| `InvalidBucketName` | 400 | The name breaks the naming rules above - including a name of 59-63 characters, which Amazon S3 would accept. |
| `BucketAlreadyOwnedByYou` | 409 | You already own a bucket with this name, in this region or another. Also the answer when a creation of the same name is already in progress and your request asked for a different `x-amz-acl` than it did: the bucket is created with the other request's setting. |
| `BucketAlreadyExists` | 409 | Another STRG customer holds the name, so a different one is needed. |
| `TooManyBuckets` | 400 | You have reached 100 buckets in this region. |
| `InvalidLocationConstraint` | 400 | `LocationConstraint` names a region other than the endpoint's. |
| `InvalidArgument` | 400 | `x-amz-bucket-object-lock-enabled` is neither `true` nor `false`. |
| `MalformedXML` | 400 | The request body is not a valid `CreateBucketConfiguration`. |
| `MaxMessageLengthExceeded` | 400 | The request body is larger than 2 MiB. |
| `BadDigest` | 400 | `Content-MD5` does not match the request body. |
| `XAmzContentSHA256Mismatch` | 400 | `x-amz-content-sha256` does not match the request body. |
| `NotImplemented` | 501 | The request carries `x-amz-bucket-object-lock-enabled: true`, an `x-amz-grant-*` header, `x-amz-object-ownership`, a canned ACL other than `private` or `public-read`, `Location`, `Bucket` or `Tags` in the body, a streaming (`aws-chunked`) body, or a query parameter CreateBucket does not take. |
| `AccessDenied` | 403 | The access key lacks *Manage buckets*, or is limited to some buckets; or the request is unsigned. |
| `InvalidAccessKeyId` | 403 | The access key does not exist, has expired or has been revoked. A key that is simply not set up for this region yet never gets this answer from CreateBucket: the creation sets it up there. |
| `AccountProblem` | 403 | Your account has no verified card on file yet - creating a bucket needs one ([A card is required](https://docs.strg.com/billing#a-card-is-required)). The dashboard's **Billing** page is where a card is added. |
| `SignatureDoesNotMatch` | 403 | The request signature does not match. |
| `RequestTimeTooSkewed` | 403 | The request time is more than 15 minutes from the server's. |
| `AuthorizationHeaderMalformed` | 400 | The signature's credential scope names a region other than the endpoint's. |
| `SlowDown` | 503 | The bucket is still being created after 90 seconds - most likely your first bucket in a region, where storage is set up first. It finishes on its own, and the same request sent again, with the same name and endpoint, returns its outcome. The response carries `Retry-After`, and the AWS SDKs retry this answer automatically. |
| `ServiceUnavailable` | 503 | A temporary failure, or another change to the same bucket is still in progress; the request can be sent again in a moment. |

## Differences from Amazon S3

Each row is something STRG does its own way, and what that means for your code.

| Aspect | Amazon S3 | STRG |
| --- | --- | --- |
| Region | Set by `LocationConstraint`; without one, the bucket is created in `us-east-1` | Always the endpoint's region. `LocationConstraint` may be left out or name the endpoint's region; another region is `400 InvalidLocationConstraint` |
| First bucket in a region | Any region | Any region. Storage is set up in that region first, so the request takes longer, and the key it was signed with is set up for that region too. Until a region holds one of your buckets, every other operation there answers the truth: `404 NoSuchBucket` for a bucket operation, an empty `ListBuckets` result, `501 NotImplemented` for an unsupported operation |
| Bucket name length | 3-63 characters | 3-58 characters |
| Re-creating a bucket you own | `200 OK` in `us-east-1`, `BucketAlreadyOwnedByYou` elsewhere | `409 BucketAlreadyOwnedByYou` everywhere, including when you own the name in another region |
| Object Lock at creation (`x-amz-bucket-object-lock-enabled: true`) | Enabled with the bucket | A second step: `true` is `501 NotImplemented`, and [PutObjectLockConfiguration](https://docs.strg.com/s3-api/PutObjectLockConfiguration) enables Object Lock once the bucket exists |
| Canned ACLs | `private`, `public-read`, `public-read-write`, `authenticated-read` | `private` and `public-read`, the two *Bucket Protection* settings. Others are `501 NotImplemented` |
| Grants, `x-amz-object-ownership` | Available | `501 NotImplemented` |
| `Location`, `Bucket`, `Tags` in the body | Available for some bucket types | `501 NotImplemented` |
| Account regional namespace (`x-amz-bucket-namespace`) | Available | No effect: one namespace for all customers |
| Bucket limit | Per account | 100 buckets per region |
| A slow creation | Not applicable | Up to about 90 seconds, then `503 SlowDown` with `Retry-After`; sending the request again joins the creation in progress |
| Permissions | `s3:CreateBucket`, plus `s3:PutBucketAcl` for a public ACL and Object Lock permissions for Object Lock | *Manage buckets*, on all-buckets keys |
| `x-amz-bucket-arn` response header | Returned for directory buckets | Not returned |

## Examples

Creating `my-bucket` in `eu-central-1`:

**AWS CLI**

```bash
aws s3api create-bucket \
  --bucket my-bucket \
  --endpoint-url https://s3.eu-central-1.strg.com \
  --region eu-central-1
```

**Python (boto3)**

```python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.eu-central-1.strg.com",
    region_name="eu-central-1",
)

s3.create_bucket(Bucket="my-bucket")
```

**JavaScript (AWS SDK v3)**

```javascript
import { CreateBucketCommand, S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
  endpoint: "https://s3.eu-central-1.strg.com",
  region: "eu-central-1",
});

await client.send(new CreateBucketCommand({ Bucket: "my-bucket" }));
```

Creating `my-bucket` as a public-read bucket, with *Bucket Protection* off:

**AWS CLI**

```bash
aws s3api create-bucket \
  --bucket my-bucket \
  --acl public-read \
  --endpoint-url https://s3.eu-central-1.strg.com \
  --region eu-central-1
```

**Python (boto3)**

```python
import boto3

s3 = boto3.client(
    "s3",
    endpoint_url="https://s3.eu-central-1.strg.com",
    region_name="eu-central-1",
)

s3.create_bucket(Bucket="my-bucket", ACL="public-read")
```

**JavaScript (AWS SDK v3)**

```javascript
import { CreateBucketCommand, S3Client } from "@aws-sdk/client-s3";

const client = new S3Client({
  endpoint: "https://s3.eu-central-1.strg.com",
  region: "eu-central-1",
});

await client.send(new CreateBucketCommand({ Bucket: "my-bucket", ACL: "public-read" }));
```

A bucket that will use Object Lock is created the same way, and
[PutObjectLockConfiguration](https://docs.strg.com/s3-api/PutObjectLockConfiguration) then enables Object Lock on it.

## Related

- [DeleteBucket](https://docs.strg.com/s3-api/DeleteBucket)
- [HeadBucket](https://docs.strg.com/s3-api/HeadBucket)
- [ListBuckets](https://docs.strg.com/s3-api/ListBuckets)
- [GetBucketLocation](https://docs.strg.com/s3-api/GetBucketLocation)
- [PutBucketAcl](https://docs.strg.com/s3-api/PutBucketAcl)
- [PutObjectLockConfiguration](https://docs.strg.com/s3-api/PutObjectLockConfiguration)
- [Object Lock](https://docs.strg.com/object-locks)
- [Access keys](https://docs.strg.com/access-keys)
- [S3 API overview](https://docs.strg.com/s3-api/overview)
