Skip to main content
TrailBase provides built-in file upload handling with automatic storage, JSON schema validation, and secure access controls.

Overview

File upload features:
  • JSON Schema validation - Enforce file types and constraints
  • Object storage - Local filesystem or S3-compatible storage
  • Automatic cleanup - Orphaned files are deleted
  • Content type detection - MIME type inference
  • Record API integration - Upload files as part of record creation/updates
  • Access control - Files inherit record permissions

Basic File Upload

1. Define Schema

Add a file upload column to your table:
migrations/main/U1234567890__add_avatar_to_profiles.sql
File Upload Schema:
  • std.FileUpload - Single file
  • std.FileUploads - Multiple files (array)
  • Second parameter: column name
  • Third parameter (optional): allowed MIME types

2. Upload File from Client

3. Access Uploaded Files

Files are automatically stored and accessible via the Record API:

File Upload Schema

Single File Upload

Multiple File Uploads

Upload multiple files:

Mixed Content

Combine different file types:

File Metadata

The FileUpload type contains:
Always use mime_type for validation, not content_type. The mime_type is inferred by TrailBase and cannot be spoofed by clients.

Accessing Files

Download File

Files are served via the Record API:
Example:

Direct URL Construction

For convenience, construct URLs directly:

Updating Files

Replace File

Remove File

TrailBase automatically deletes orphaned files. When you replace or remove a file, the old file is queued for deletion.

File Storage

Local Filesystem

By default, files are stored in traildepot/uploads/:
Files are organized by UUID prefix for efficient storage.

S3-Compatible Storage

Configure S3 or compatible storage (MinIO, DigitalOcean Spaces, etc.):
For production deployments, use S3 or compatible storage for better scalability and CDN integration.

Access Control

File access inherits record permissions:
traildepot/config.textproto
With this configuration:
  • Anyone can view profile avatars (world-readable)
  • Only the profile owner can upload/change their avatar

Private Files

traildepot/config.textproto
Files are only accessible to the document owner.

Validation

File Type Constraints

Restrict file types using MIME type patterns:

Client-Side Validation

Always validate on the server. Client-side validation can be bypassed. TrailBase validates MIME types based on file content, not the provided Content-Type header.

Real-World Example: Blog with Images

From the Blog Example:
migrations/main/U1725019362__create_articles.sql
Create article with image:
Display article with image:

Image Optimization

Client-Side Resizing

Resize images before upload to reduce bandwidth:

WASM Image Processing

Process images server-side using WASM:

Cleanup

Automatic Cleanup

TrailBase automatically deletes orphaned files:
  1. When a record is deleted, files are queued for deletion
  2. When a file column is updated, the old file is queued
  3. A background job processes the deletion queue

Manual Cleanup

Query pending deletions:
Force cleanup via SQL:
Manual deletion bypasses TrailBase’s cleanup mechanism. Only use for debugging.

Best Practices

1

Validate File Types

Always specify allowed MIME types in your schema:
2

Limit File Sizes

Implement client-side size limits:
3

Use Descriptive Column Names

Name columns based on their purpose:
4

Optimize Images

Resize large images before upload:
  • Reduce dimensions to reasonable sizes (e.g., 1200x1200)
  • Compress quality for web delivery
  • Consider WebP format for better compression
5

Use CDN for Production

Serve files through a CDN for better performance:
  • Configure S3 with CloudFront
  • Use custom domain for files
  • Enable caching headers

Troubleshooting

File Upload Fails

Symptom: Upload returns 400 error Solutions:
  1. Check MIME type constraints in schema
  2. Verify file is not corrupted
  3. Check request Content-Type is multipart/form-data
  4. Ensure file size is within limits

File Not Found

Symptom: File URL returns 404 Solutions:
  1. Verify record exists and contains file metadata
  2. Check file column is not NULL
  3. Verify filename matches exactly
  4. Check access permissions

Files Not Deleted

Symptom: Old files remain after update/delete Solutions:
  1. Check _file_deletions table for pending deletions
  2. Wait for background cleanup job (runs periodically)
  3. Verify object storage credentials are correct

Next Steps

First App

Build an app with file uploads

Database Setup

Learn about file upload schemas

Authentication

Secure file uploads

WASM Runtime

Process files with WebAssembly

Examples