Aurabase Logo
aurabasedocs
docs›Services›Storage

Storage

REST API per project on S3 storage (MinIO), on-the-fly image transformations with derivative cache, HMAC signed URLs, public or private buckets, trash and restore.

6 min read·Level intermediate·Revised on Apr 15, 2026
This English text was generated automatically from the French original and has not been reviewed yet.
#
Overview

One bucket, one origin, one CDN

The aura-storage service manages your binary files: upload, download, image transformations, signed URLs, trash. It exposes its own REST API under /v1/storage/{project_id} and relies on S3 storage (MinIO) internally — the S3 tools (rclone, boto3) do not connect to it directly.

Objects are organized into buckets. Each bucket has a policy (public or private), size limits, an optional TTL, and a set of RLS policies that control who can read/write each path.

Info

The metadata lives in the project schema: storage_buckets, storage_objects, storage_derivatives, storage_project_settings, storage_audit_log. The bytes are in S3 storage.

#
Mental model

Path → RLS → CDN → origin

During a read, the service checks for access to the requested path and then serves the bytes from storage. If the query carries transformation parameters, the corresponding derivative is reused if it already exists, otherwise calculated and then cached. In upload, the flow is reversed: client → service → storage, after writing control and bucket limits.

schematext
                              ┌───── cache dérivés ─────┐
   GET /v1/storage/{pid}/… ─▶ │ dérivé déjà calculé ?   │
                              │ non ⇢ origine           │
                              └──────────┬──────────────┘
                                         │
                              ┌──────────▼──────────────┐
                              │ aura-storage            │
                              │  ─ contrôle d'accès     │
                              │  ─ transformations      │
                              │  ─ cache des dérivés    │
                              └──────────┬──────────────┘
                                         │
                                  stockage S3 (MinIO)
#
Primitives

Six native abilities

REST API per project

Routes /v1/storage/{project_id}/… on S3 storage (MinIO) — this is not an S3 API: S3 SDKs do not plug into it.

Transforms on the fly

width, height, fit, format (jpeg/png/webp/gif), quality, rotate, flip. Each combination is hidden as a derivative.

Signed URLs

HMAC signature on method + bucket + key + expiration. TTL 3600 s by default, secret rotation per project.

Multipart upload

Simple upload in multipart/form-data, or init / part / complete for large files.

Trash and restoration

Soft deletion: /trash lists deleted objects, /restore/{key} restores them.

Public or private buckets

The bucket carries the access policy, size limits and the list of authorized MIME types.

#
Examples

Four basic operations

avatar.tstypescript
const { data, error } = await aura.storage.upload('avatars', `${user.id}/${file.name}`, file, {
    contentType: file.type,
    upsert: true,
})

// Without upsert, a path already occupied fails in 409 (CONFLICT code)
Astuce

Transformation URLs are immutable by parameters. ?width=240&format=png and ?width=240&format=webp are two distinct URLs, therefore two distinct derivatives: each combination is only calculated once, then reread from the derivative cache.

#
Access policies

RLS on object paths

Object metadata lives in the storage_objects table of the project schema (columns bucket_name, key, owner_id, metadata, deleted_at), with RLS enabled. There is no storage schema nor storage.foldername() function: policies are written on the columns.

policies delivered by defaultsql
-- Read: own object, or any object from a public bucket
create policy storage_objects_select on storage_objects for select
  using (
    owner_id = auth.uid()
    or exists (select 1 from storage_buckets b
                  where b.name = storage_objects.bucket_name and b.public)
  );

-- Writing: only your own objects
create policy storage_objects_insert on storage_objects for insert
  with check (owner_id = auth.uid());
Last updated · Apr 15, 2026