File Storage - Overview

Anvil bundles an object/blob store directly inside the database binary, so deployments don't need a sidecar S3/MinIO instance. Files live as :storage.Object nodes in the system storage schema; binary content is held by a pluggable backend (local FS by default, optionally AWS S3, Cloudflare R2, MinIO, Google Cloud Storage, or Azure Blob).

Modeled after Supabase Storage but graph-native: buckets and files are first-class graph entities, so they participate in Cypher queries, relationships, row-level security policies, triggers, and edge functions.

Architecture

The storage subsystem has three layers:

LayerResponsibilityExamples
GraphBucket / Object metadata as nodes:storage.Bucket, :storage.Object
RefcountContent-addressed dedup + lifetimeRefCounter::incref/decref
BackendBytes on disk or in the cloudLocalBackend, S3Backend

Backend blobs are content-addressed (SHA-256). Two objects with identical bytes share one backend file - uploading the same image twice is free after the first time.

How it compares

FeatureAnvil StorageS3 / R2Supabase Storage
Built-in to DBYesNoPostgres extension
Graph-nativeYes (Cypher MATCH)NoPartial (SQL)
RLS for objectsNativeIAM onlyNative
Signed URLsHMAC, bucket-versionedPre-signedJWT-based
Image transformBuilt-inExternal (Lambda)Pro tier
Resumable uploadTUS 1.0.0MultipartTUS
Content dedupRefcountedNoNo

What's in the box

ComponentSurface
REST API/storage/v1/bucket, /storage/v1/object, /storage/v1/upload/resumable, /storage/v1/render
Cypher DDLCREATE BUCKET, ALTER BUCKET, DROP BUCKET, SHOW BUCKETS
Cypher helpersfile_url, signed_url, file_size, file_mime, bucket_size, image_metadata
TriggersBEFORE/AFTER INSERT/UPDATE/DELETE on :storage.Object
Client SDKsanvilent for Rust / TypeScript / Python / Go
CLIanvil storage create-bucket / upload / download / ls / rm / sign / usage / gc
Hammer UI/storage panel with browser, upload, preview, signed URLs