> ## Documentation Index
> Fetch the complete documentation index at: https://docs.basaltic.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Objects

> Object limits, storage classes, and working with objects through the platform API.

## Objects and their limits

These are S3's own numbers, and they are enforced at S3's values:

| Limit                 | Value                        |
| --------------------- | ---------------------------- |
| Single-request upload | 5 GiB                        |
| Part size             | 5 MiB minimum, 5 GiB maximum |
| Parts per upload      | 10,000                       |

<Warning>
  The single-upload ceiling is checked against the size you **declare**, before
  any payload is read. An oversized `Content-Length` is refused with
  `EntityTooLarge` (`413` on the storage API) without transferring a byte — and
  a body that streams past the limit without declaring it is cut off too.
</Warning>

The 5 MiB floor applies to every part except the last one named at completion,
and it is checked **at completion**, not when the part is uploaded. A part list
whose non-final part is short fails with `EntityTooSmall` after the bytes are
already staged.

Uploads you start and never finish keep their staged parts until something
removes them. Add an `abort_incomplete_multipart_upload` [lifecycle
rule](#lifecycle-rules) rather than relying on remembering.

## Storage classes

Two classes, and they name device tiers rather than access patterns:

| Class      | Backed by                      | Use for                                  |
| ---------- | ------------------------------ | ---------------------------------------- |
| `STANDARD` | Solid-state pool. The default. | Anything served or read regularly.       |
| `COLD`     | Spinning-disk pool.            | Archives, backups, anything read rarely. |

They keep S3's uppercase spelling because the vocabulary is S3's. Set a class
per object with `x-amz-storage-class` on the upload, or move objects between
classes with a lifecycle transition. **The two classes bill separately**, so the
label an object carries decides which counter and which price its bytes land on.

An unsupported class — `STANDARD_IA`, `GLACIER`, anything else S3 defines — is
rejected rather than quietly stored as `STANDARD`.

## Working with objects through the storage API

You do not need an S3 client. The storage API exposes the same object plane
under `/v1/buckets/{bucket}/objects`, authenticated with your ordinary
Basaltic credentials exactly like every other call to this API — useful for a
service that already holds them and should not carry an S3 SDK as well:

<Tabs>
  <Tab title="Console">
    A bucket's **Objects** tab is a file browser over the same routes.
    **Upload** opens the **Upload objects** page, where you set a **Folder
    prefix**, pick a **Storage class** — **Standard** or **Cold** — and add
    **Files**. **New folder** creates a prefix, and selecting rows gives you
    **Delete selected**, which issues one delete per key rather than a bulk
    request — see the note below.

    Opening an object gives you **Download** and **Delete**, a **Versions**
    tab, and a **Properties** tab carrying its **Tags** alongside the
    [retention controls](#object-lock-and-retention).
  </Tab>

  <Tab title="API">
    ```bash theme={null}
    PUT    /v1/buckets/{bucket}/objects/{key}     # body is the object bytes
    GET    /v1/buckets/{bucket}/objects/{key}     # Range requests honoured (206)
    DELETE /v1/buckets/{bucket}/objects/{key}     # ?versionId deletes one version
    GET    /v1/buckets/{bucket}/objects?prefix=&delimiter=&marker=&max_keys=
    ```
  </Tab>

  <Tab title="CLI">
    ```bash theme={null}
    basaltic storage object put <bucket> <key> --file ./report.csv
    basaltic storage object get <bucket> <key> > report.csv
    ```
  </Tab>

  <Tab title="Go">
    ```go theme={null}
    f, err := os.Open("report.csv")
    if err != nil {
        log.Fatal(err)
    }
    defer f.Close()

    _, err = storage.New(cfg).PutObject(ctx, "my-app-assets", "reports/q1.csv", f)
    ```

    Object bytes stream: PutObject takes an io.Reader and GetObject returns an
    io.ReadCloser, so neither needs the whole object in memory.
  </Tab>
</Tabs>

Per-object sub-resources ride as query parameters on these routes — `?tagging`,
`?retention`, `?legal-hold` — and the same `X-Amz-*` headers apply on upload for
storage class, encryption and object-lock settings. `delimiter` gives you the
usual folder semantics through `common_prefixes`, and `max_keys` is capped at
1000 per page.

<Note>
  Bulk delete (`POST ?delete`) and server-side copy (`x-amz-copy-source`) are S3
  endpoint features. Through the storage API, delete objects one at a time.
</Note>
