Skip to content

Storage

Truss provides S3-compatible file storage powered by MinIO. The dashboard gives you a file browser with drag-and-drop uploads. The API provides presigned URLs for direct client uploads and downloads.

Setup

Set these environment variables in apps/api/.env:

MINIO_S3_ENDPOINT=http://localhost:9000
MINIO_CONSOLE_URL=http://localhost:9001
MINIO_ACCESS_KEY=minioadmin
MINIO_SECRET_KEY=minioadmin
MINIO_REGION=us-east-1
MINIO_FORCE_PATH_STYLE=true

Buckets

List buckets

Terminal window
curl http://localhost:8787/api/storage/buckets

Create a bucket

Terminal window
curl -X POST http://localhost:8787/api/storage/buckets \
-H "Content-Type: application/json" \
-d '{"name": "my-bucket"}'

Bucket names must be lowercase, 3-63 characters, using letters, numbers, dots, and hyphens.

Delete a bucket

Terminal window
# Delete empty bucket
curl -X DELETE http://localhost:8787/api/storage/buckets/my-bucket
# Force delete (empties bucket first)
curl -X DELETE "http://localhost:8787/api/storage/buckets/my-bucket?force=true"

Objects

List objects

Terminal window
curl "http://localhost:8787/api/storage/buckets/my-bucket/objects?prefix=images/&max_keys=50"

Upload via presigned URL

The recommended upload flow: get a presigned URL from the API, then upload directly to S3.

Terminal window
# 1. Get presigned upload URL
curl -X POST http://localhost:8787/api/storage/buckets/my-bucket/objects/presign-upload \
-H "Content-Type: application/json" \
-d '{"key": "images/photo.jpg", "contentType": "image/jpeg"}'
# 2. Upload directly to the returned URL
curl -X PUT "$PRESIGNED_URL" \
-H "Content-Type: image/jpeg" \
--data-binary @photo.jpg
// JavaScript: presigned upload
const { url, headers } = await fetch('/api/storage/buckets/my-bucket/objects/presign-upload', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'images/photo.jpg', contentType: 'image/jpeg' })
}).then(r => r.json());
await fetch(url, {
method: 'PUT',
headers,
body: file // File object from input
});

Download via presigned URL

Terminal window
curl -X POST http://localhost:8787/api/storage/buckets/my-bucket/objects/presign-download \
-H "Content-Type: application/json" \
-d '{"key": "images/photo.jpg", "expiresIn": 3600}'

Returns a presigned GET URL valid for the specified duration (default 900 seconds, max 7 days).

Upload text content directly

For small text files, you can upload content directly through the API:

Terminal window
curl -X POST http://localhost:8787/api/storage/buckets/my-bucket/objects/upload-text \
-H "Content-Type: application/json" \
-d '{"key": "config.json", "content": "{\"version\": 1}", "contentType": "application/json"}'

Delete objects

Terminal window
# Single object
curl -X DELETE http://localhost:8787/api/storage/buckets/my-bucket/objects \
-H "Content-Type: application/json" \
-d '{"key": "images/photo.jpg"}'
# Bulk delete (up to 1000 keys)
curl -X POST http://localhost:8787/api/storage/buckets/my-bucket/objects/bulk-delete \
-H "Content-Type: application/json" \
-d '{"keys": ["file1.txt", "file2.txt", "file3.txt"]}'

Multipart uploads

For large files (>100MB), use multipart uploads:

Terminal window
# 1. Initialize
curl -X POST http://localhost:8787/api/storage/buckets/my-bucket/objects/multipart/init \
-H "Content-Type: application/json" \
-d '{"key": "large-file.zip", "contentType": "application/zip"}'
# 2. Get presigned URL for each part
curl -X POST http://localhost:8787/api/storage/buckets/my-bucket/objects/multipart/presign-part \
-H "Content-Type: application/json" \
-d '{"key": "large-file.zip", "uploadId": "...", "partNumber": 1}'
# 3. Upload each part to its presigned URL
# 4. Complete the upload
curl -X POST http://localhost:8787/api/storage/buckets/my-bucket/objects/multipart/complete \
-H "Content-Type: application/json" \
-d '{"key": "large-file.zip", "uploadId": "...", "parts": [{"partNumber": 1, "etag": "..."}]}'

Bucket policies

Set access policies on buckets (e.g., public read):

Terminal window
# Get current policy
curl http://localhost:8787/api/storage/buckets/my-bucket/policy
# Set policy
curl -X PUT http://localhost:8787/api/storage/buckets/my-bucket/policy \
-H "Content-Type: application/json" \
-d '{"policy": {"Version": "2012-10-17", "Statement": [{"Effect": "Allow", "Principal": "*", "Action": ["s3:GetObject"], "Resource": ["arn:aws:s3:::my-bucket/*"]}]}}'

Client API

Storage buckets are also available via the management API:

Terminal window
curl http://localhost:8787/v1/storage/buckets \
-H "apikey: truss_sk_your_key"