# Object Storage quickstart

This guide instructs you through storing your first object in [Object Storage](/en/documentation/platform/object-storage/). By the end you will have:

- Your first bucket, which the Azion platform reads without changing it.
- An object stored in that bucket, addressed by its key.
- The object listed in the bucket, which confirms the upload.

A bucket is not a public folder: an object you upload answers no request from the internet until an application is pointed at it. The result rests on three objects, in this order. The **bucket** is the top-level container for objects, and buckets do not nest. Each **object** inside it is a file, its key, and its content type. The key addresses the object: a `/` in a key is part of the key, not a folder. A **connector** of type Object Storage, paired with a Rules Engine rule on an [application](/en/documentation/platform/applications/), is what sends a request to the bucket. This guide creates the first two and stops there.

---

Select the interface you will use. The prerequisites and every stage below follow that choice.

## Prerequisites

- A file on your machine to upload, such as an image.
- Permission to create buckets and objects in your account. For more information, refer to [Teams Permissions](/en/documentation/fundamentals/teams-permissions/).

**Console**

- Access to Azion Console. To sign in, refer to [Access Azion Console](/en/documentation/guides/platform/account-and-billing/how-to-access-azion-console/).

**CLI**

- The [Azion CLI](/en/documentation/devtools/cli/) installed and authorized.

**API**

- A [personal token](/en/documentation/guides/platform/account-and-billing/personal-tokens/) and `curl`.

---

## Create a bucket

A bucket holds the objects you upload. This one gives the Azion platform read-only access, the level for content the platform serves without changing it.

A bucket name is 6 to 63 characters, uses letters, numbers, and the hyphen, and never begins with `azion`. It is unique across every Azion account, so a short generic name is likely to be taken.

**Console**

To create the bucket in Azion Console:

1. **Open the bucket list**

   Access [Azion Console](https://console.azion.com/) > **Object Storage** > **Buckets**.

2. **Open the create form**

   Start a new bucket from the **Buckets** list. An account with no buckets yet offers **Bucket** on the empty list.

3. **Name the bucket**

   Under **General**, in **Name**, enter a name of your own.

4. **Keep the access level**

   Under **Settings**, keep **Workloads Access** as *Read Only*, the default, so the platform reads the objects but cannot modify them.

5. **Select Create Bucket**

The bucket appears in **Buckets**, which lists its **Name**, **Size**, **Last Editor**, and **Last Modified**.

**CLI**

To create the bucket with the Azion CLI, replace `my-first-bucket` with a name of your own:

1. **Run the create command**

   ```bash
   azion create storage bucket --name my-first-bucket --workloads-access read_only
   ```

2. **Read the output**

   The command confirms the bucket:

   ```text
   Bucket created successfully
   ```

   A name another account holds is refused. Choose a different one and run the command again.

The bucket exists and holds no objects. For every flag the command accepts, refer to [Azion CLI create](/en/documentation/devtools/cli/resources/).

**API**

To create the bucket with the Azion API, replace `[TOKEN VALUE]` with your personal token and `my-first-bucket` with a name of your own:

1. **Send the create request**

   ```bash
   curl --request POST \
     --url https://api.azion.com/v4/workspace/storage/buckets \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]' \
     --header 'Content-Type: application/json' \
     --data '{
     "name": "my-first-bucket",
     "workloads_access": "read_only"
   }'
   ```

2. **Read the response**

   A `201` carries the bucket:

   ```json
   {
     "state": "executed",
     "data": {
       "name": "my-first-bucket",
       "workloads_access": "read_only",
       "last_editor": "user@example.com",
       "last_modified": "2026-01-01T12:14:08.914719+00:00",
       "product_version": "1.0"
     }
   }
   ```

   A `400` with the code `17000` means the name is already in use, in your account or another. Choose a different one and send the request again.

The bucket exists and holds no objects.

> **Note**
>
> **Workloads Access** decides only what the Azion platform may do with the bucket. It does not restrict the API or the S3 protocol: a credential that carries write capability writes to a read-only bucket. For more information, refer to [How Object Storage works](/en/documentation/platform/object-storage/how-it-works/).

---

## Upload an object

An object is stored under a key, and the key is how every interface addresses it afterwards. A key holds 1 to 1,024 characters.

**Console**

To upload the file in Azion Console:

1. **Open the bucket**

   In **Buckets**, select the bucket you created.

2. **Add the file**

   Select **Upload files**, or drag the file onto the drop target. The file name becomes the object key. The Console refuses a file larger than 300 MB.

The object is stored in the bucket, under the key taken from the file name.

**CLI**

To upload the file with the Azion CLI, replace the bucket name, the key, and the file path with your own:

1. **Run the create command**

   ```bash
   azion create storage object --bucket-name my-first-bucket --object-key images/logo.png --source ./logo.png
   ```

2. **Read the output**

   The command confirms the object:

   ```text
   Object created successfully
   ```

The object is stored. The `images/` segment is part of the key, not a folder that had to exist first.

> **Caution**
>
> Pass `--source` a path relative to the directory you run the command in, such as `./logo.png`. Azion CLI 4.23.0 resolves an absolute path against the working directory as well, which fails with `no such file or directory` and a doubled path.

**API**

The upload names the bucket and the key in the path, and sends the file as the body. There is no create-then-write sequence: the object exists when the request succeeds.

1. **Send the upload request**

   Replace the key and the file path with your own. Set `Content-Type` to the type of your file, because the stored value is the one this header carries:

   ```bash
   curl --request POST \
     --url https://api.azion.com/v4/workspace/storage/buckets/my-first-bucket/objects/images/logo.png \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]' \
     --header 'Content-Type: image/png' \
     --data-binary '@./logo.png'
   ```

2. **Read the response**

   A `201` carries the key the object is stored under:

   ```json
   {
     "state": "executed",
     "data": {
       "object_key": "images/logo.png"
     }
   }
   ```

The object is stored. The `images/` segment is part of the key, not a folder that had to exist first.

---

## Confirm the object is stored

The bucket lists what it holds, so you can confirm the upload without another interface.

**Console**

To find the object in Azion Console:

1. **Open the bucket list**

   Access [Azion Console](https://console.azion.com/) > **Object Storage** > **Buckets**.

2. **Select the bucket**

   Select the bucket you created.

3. **Find the object by its key**

   The object is listed under its key. A key that holds a `/`, such as `images/logo.svg`, groups under the segment before it: that segment is a prefix, not a folder.

The object is listed under its key, which confirms the upload.

**CLI**

To list what the bucket holds with the Azion CLI:

1. **Run the list command**

   ```bash
   azion list storage object --bucket-name my-first-bucket --details
   ```

2. **Read the output**

   The table carries one row per object, with its key, when it was last modified, and its size in bytes:

   ```text
   KEY              LAST MODIFIED                    SIZE
   images/logo.png  2026-01-01 12:07:27.3 +0000 UTC  408
   ```

   Without `--details` the table carries the key and the modification time alone.

The object is listed under its key, which confirms the upload.

**API**

Two requests confirm the upload: one lists the bucket, and one reads the object back.

1. **List the objects in the bucket**

   ```bash
   curl --request GET \
     --url https://api.azion.com/v4/workspace/storage/buckets/my-first-bucket/objects \
     --header 'Accept: application/json' \
     --header 'Authorization: Token [TOKEN VALUE]'
   ```

   The response lists the key, when it was last modified, its size in bytes, and whether the entry is a prefix:

   ```json
   {
     "continuation_token": null,
     "results": [
       {
         "key": "images/logo.png",
         "last_modified": "2026-01-01T12:14:26.303000Z",
         "size": 408,
         "is_folder": false
       }
     ]
   }
   ```

2. **Download the object**

   Read the object back into a local file, and confirm the content type Azion stored:

   ```bash
   curl --request GET \
     --url https://api.azion.com/v4/workspace/storage/buckets/my-first-bucket/objects/images/logo.png \
     --header 'Authorization: Token [TOKEN VALUE]' \
     --output ./logo-downloaded.png --dump-header -
   ```

   The response headers carry `HTTP/2 200` and the `content-type` the upload set, and the file is written to `./logo-downloaded.png`.

The object reads back with the content type you set, which confirms the upload.

Your first object is stored in Object Storage and addressed by its key. The bucket is reachable through Azion Console, the Azion CLI, the Azion API, and the S3 protocol, and by nothing else yet.

To serve the object to end users, point a [connector](/en/documentation/platform/connectors/) of type Object Storage at the bucket. A Rules Engine rule on the application then sends matching requests to it. For more information, refer to [Use a bucket as an application origin](/en/documentation/guides/application-development/data/use-bucket-as-origin/).

---

## Next steps

- [How Object Storage works](/en/documentation/platform/object-storage/how-it-works.md): What each access level permits, and how a request reaches an object.
- [Use a bucket as an application origin](/en/documentation/guides/application-development/data/use-bucket-as-origin.md): The connector and the rule that put the bucket behind an application.
- [Buckets and objects](/en/documentation/platform/object-storage/buckets-and-objects.md): Every field a bucket carries, every operation, and the error each rejection returns.
- [Use S3-compatible tools with Object Storage](/en/documentation/guides/application-development/data/use-s3-compatible-tools-with-object-storage.md): Create a credential and manage the same objects with an S3 client.
