The goal
You need somewhere to keep files on OCI, such as backups, logs or exports. Object Storage suits this well. This post takes you through the commands you'll use every week.
You'll need a working OCI CLI and a compartment.
The ideas you need
| Term | Meaning |
|---|---|
| Namespace | A unique name for your tenancy's storage. You don't choose it |
| Bucket | A container for objects, in one compartment and region |
| Object | A file plus its metadata |
| Prefix | The folder-like part of a name, as in logs/2026/app.log |
| Storage tier | Standard, Infrequent Access or Archive |
There aren't real folders. logs/2026/app.log is simply one object with slashes in its name.
Step 1: find your namespace
oci os ns get
export C=ocid1.compartment.oc1..your-compartment-id
The CLI usually works out the namespace for you, so you won't need to pass it. You will see it in URLs, though.
If you get NotAuthorizedOrNotFound on the commands below, you need a policy like this one, created by an administrator:
Allow group lab-users to manage object-family in compartment lab
For help with this, read your first group and policy.
Step 2: create a bucket
oci os bucket create \
--compartment-id "$C" \
--name lab-bucket-01 \
--public-access-type NoPublicAccess
Bucket names must be unique in the namespace, and you can't use every character. NoPublicAccess is the default, and you should keep it. See the bucket security baseline.
Confirm the setting:
oci os bucket get --name lab-bucket-01 \
--query 'data.{name:name, public:"public-access-type", tier:"storage-tier", versioning:versioning}'
Step 3: upload files
echo "hello object storage" > hello.txt
oci os object put \
--bucket-name lab-bucket-01 \
--file hello.txt
# Give it a folder-like name
oci os object put \
--bucket-name lab-bucket-01 \
--file hello.txt \
--name reports/2026/hello.txt
Large files are split into parts automatically. If an upload fails, you may be left with uncommitted parts that still cost money.
object put asks for confirmation if the object exists. Add --force to overwrite it, but only if you're sure. If you turn on versioning, you can keep older copies.
For a whole directory, use bulk upload. See bulk upload and sync.
Step 4: list and inspect
oci os object list --bucket-name lab-bucket-01 \
--query 'data[].{name:name, size:size}' --output table
# Only one "folder"
oci os object list --bucket-name lab-bucket-01 --prefix reports/2026/ --all
# Details of one object
oci os object head --bucket-name lab-bucket-01 --name hello.txt
object list returns only part of a large bucket by default. Add --all when you need every object.
Step 5: download
oci os object get \
--bucket-name lab-bucket-01 \
--name reports/2026/hello.txt \
--file downloaded.txt
cat downloaded.txt
Step 6: share one file with a link
Someone without an OCI account needs a file. Don't make the bucket public. Create a pre-authenticated request (PAR), which is a URL that expires:
EXPIRES=$(date -u -d "+1 day" +%Y-%m-%dT%H:%M:%SZ)
oci os preauth-request create \
--bucket-name lab-bucket-01 \
--name share-hello \
--access-type ObjectRead \
--object-name hello.txt \
--time-expires "$EXPIRES"
The date line uses GNU syntax. On macOS or Windows, type the timestamp by hand. The output holds the link in a field called full-path on current CLI versions, or access-uri on others, which you add to your region's Object Storage endpoint.
Warning
Anyone with a PAR link can use it, with no login. You can see the URL only once, when you create it. Keep expiry short, and use the narrowest access type. To revoke one early, delete it.
List and delete links:
oci os preauth-request list --bucket-name lab-bucket-01 \
--query 'data[].{name:name, id:id, access:"access-type", expires:"time-expires"}' --output table
oci os preauth-request delete --bucket-name lab-bucket-01 --par-id <id> --force
If a link fails, see PAR returning 404 or 403.
Choosing a storage tier
| Tier | Good for | Note |
|---|---|---|
| Standard | Frequently read data | The default |
| Infrequent Access | Data read rarely but needed fast | Has retrieval fees and a minimum retention |
| Archive | Long-term retention | Restore before reading, which takes time |
Set it per object:
oci os object put --bucket-name lab-bucket-01 --file hello.txt \
--name archive/hello.txt --storage-tier Archive
An Archive object can't be downloaded straight away. Restore it first:
oci os object restore --bucket-name lab-bucket-01 --name archive/hello.txt
oci os object restore-status --bucket-name lab-bucket-01 --name archive/hello.txt
Check current pricing and minimum retention periods before you choose. To automate moves between tiers, use lifecycle policies.
Common errors
| Error | Likely cause | Fix |
|---|---|---|
BucketNotFound | Wrong name, or wrong region | Check --region, and the bucket name |
NotAuthorizedOrNotFound | Missing policy | Add a policy in the bucket's compartment |
BucketAlreadyExists | Name is taken in the namespace | Choose another |
BucketNotEmpty | Objects, versions or uploads remain | Remove them first |
| Archive object won't download | It hasn't been restored | Run object restore, then wait |
401 NotAuthenticated | API key or clock problem | See 401 errors |
Step 7: clean up
oci os object bulk-delete --bucket-name lab-bucket-01 --dry-run
oci os object bulk-delete --bucket-name lab-bucket-01 --force
oci os bucket delete --name lab-bucket-01 --force
Caution
bulk-deleteremoves everything that matches, with no recycle bin unless versioning is on. Always start with--dry-run, and read the bucket name twice. If something goes wrong, see deleted object recovery.
Prevent it next time
- Keep buckets private, and share with short-lived PARs.
- Add lifecycle rules, so that old data moves to a cheaper tier or is removed.
- Turn on versioning for data you can't afford to lose.
- From private instances, use a service gateway rather than internet routes.