Object Storage

Enterprise Asset Storage

Store and serve massive digital assets with our S3-compatible object storage. Automatically optimized by a global CDN, Afribase Storage provides lightning-fast delivery for images, videos, and documents across the continent.

Storage Infrastructure

Unified S3 Access

Afribase Storage is fully S3-compatible, allowing you to use existing tools and libraries to manage your files with enterprise-grade interoperability.

African CDN Nodes

Static assets are cached at the edge across our regional nodes, ensuring your users in Lagos or Cairo receive content with minimal latency.

Storage must be **enabled** in your project settings before you can upload files. Go to **Dashboard → Project Settings → Service Management** and toggle **Storage** on, then click **Refresh** to provision the service.

Quick Start — Raw Fetch API

You don't need an SDK. Upload and retrieve files using plain fetch() calls from any JavaScript environment.

01

Upload a File

Send the file as a raw body with your API key and auth token.
typescript
const STORAGE_URL = "https://your-project.afribase.dev/storage/v1/YOUR_PROJECT";
const BUCKET = "my-bucket";

const file = document.getElementById('fileInput').files[0];
const fileName = `${Date.now()}.${file.name.split('.').pop()}`;

const res = await fetch(`${STORAGE_URL}/object/${BUCKET}/${fileName}`, {
  method: 'POST',
  headers: {
    'apikey': YOUR_ANON_KEY,
    'Authorization': `Bearer ${session.access_token}`
  },
  body: file  // Send the File/Blob directly — no FormData needed
});

if (!res.ok) throw new Error(await res.text());
console.log("Uploaded!", await res.json());
02

Get the Public URL

For public buckets, construct the URL directly — no API call needed.
typescript
const publicUrl = `${STORAGE_URL}/object/public/${BUCKET}/${fileName}`;
// Use it in an <img> or <a> tag immediately
03

List Files in a Bucket

typescript
const res = await fetch(`${STORAGE_URL}/object/list/${BUCKET}`, {
  method: 'POST',
  headers: {
    'apikey': YOUR_ANON_KEY,
    'Authorization': `Bearer ${session.access_token}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ prefix: '', limit: 100 })
});
const files = await res.json();
04

Delete a File

typescript
await fetch(`${STORAGE_URL}/object/${BUCKET}/file-to-delete.png`, {
  method: 'DELETE',
  headers: {
    'apikey': YOUR_ANON_KEY,
    'Authorization': `Bearer ${session.access_token}`
  }
});

SDK Reference

If you're using the Afribase client library, storage operations are even simpler.

01

Upload an Image

Use our SDK to securely upload files from your user's devices.

JavaScript

typescript
const { data, error } = await afribase.storage
  .from('avatars')
  .upload('profiles/avatar-1.png', file);

Python

python
data = client.storage.from_("avatars").upload(
  "profiles/avatar-1.png", file_bytes
)

Dart

dart
final data = await client.storage
  .from('avatars')
  .upload('profiles/avatar-1.png', file);

Swift

swift
let data = try await afribase.storage
  .from("avatars")
  .upload(path: "profiles/avatar-1.png", file: fileData)

Kotlin

kotlin
val data = afribase.storage
  .from("avatars")
  .upload("profiles/avatar-1.png", fileBytes)

Go

go
data, err := client.Storage.From("avatars").Upload(
  "profiles/avatar-1.png", fileReader,
)
02

Generate Public Link

Retrieve a high-speed public URL for your media assets stored in public buckets.

JavaScript

typescript
const { data } = afribase.storage.from('avatars').getPublicUrl('avatar-1.png');

Python

python
url = client.storage.from_("avatars").get_public_url("avatar-1.png")

Dart

dart
final url = client.storage.from('avatars').getPublicUrl('avatar-1.png');

Swift

swift
let url = afribase.storage.from("avatars").getPublicUrl(path: "avatar-1.png")

Kotlin

kotlin
val url = afribase.storage.from("avatars").getPublicUrl("avatar-1.png")

Go

go
url := client.Storage.From("avatars").GetPublicUrl("avatar-1.png")
03

Signed URLs & Image Transforms

Optimize images on the fly or generate temporary signed URLs for private files.

JavaScript

typescript
// Signed URL (expires in 60s)
const { data } = await afribase.storage
  .from('docs').createSignedUrl('private.pdf', 60);

// Image Transform
const { data: img } = afribase.storage
  .from('avatars').getPublicUrl('user.png', {
    transform: { width: 200, height: 200 }
  });

Python

python
# Signed URL
url = client.storage.from_("docs").create_signed_url("private.pdf", 60)

# Image Transform
url = client.storage.from_("avatars").get_public_url(
  "user.png", transform={"width": 200}
)

Dart

dart
// Signed URL
final url = await client.storage
  .from('docs').createSignedUrl('private.pdf', 60);

// Image Transform
final imgUrl = client.storage.from('avatars').getPublicUrl(
  'user.png', transform: TransformOptions(width: 200)
);

Kotlin

kotlin
// Signed URL
val url = afribase.storage
  .from("docs").createSignedUrl("private.pdf", 60)

// Image Transform
val imgUrl = afribase.storage.from("avatars")
  .getPublicUrl("user.png") { transform(width = 200) }
Buckets can be marked as **Public** for assets intended for everyone, or **Private** to protect sensitive user documents using Row Level Security.

Fine-grained Security

Control who can read and write files using **Storage Roles**. You can define specific permissions for different user levels or automated services.

Viewer

Read-only access to specific buckets.

Editor

Upload and manage files within a bucket.

Admin

Full control over bucket configuration and data.

Access Control & Troubleshooting

Managing Storage Policies

Since Storage metadata is stored in a separate schema, you must use the **Schema Selector** in the Auth Policies dashboard to switch to "storage". Target the "objects" table to define your rules.

If you're getting a "new row violates row-level security policy" error, create an INSERT policy for the storage.objects table using the owner column:

sql
-- Pattern for user-specific uploads
(bucket_id = 'your_bucket') AND (auth.uid() = owner)

Type Mismatch: uuid = integer

If you get operator does not exist: uuid = integer, you are comparing auth.uid() (UUID) to an integer. Cast the table column to UUID in your expression:

auth.uid() = user_id::uuid

© 2026 Afribase Cloud Infrastructure. Produced by Altris Product Systems.