File Management

SonicJs integrates with Cloudflare R2 to store and retrieve file assets such as images, videos, PDFs and so on.

Cloudflare R2

In case you are not familiar with R2, here is what is does in a nutshell:

Cloudflare R2 Storage provides developers with the capability to securely store substantial volumes of unstructured data while mitigating the significant expenses typically associated with egress bandwidth fees in conventional cloud storage services.

R2 serves as a versatile solution applicable to various scenarios, encompassing but not restricted to:

  • Facilitating storage for cloud-native applications.
  • Serving as a repository for web content within cloud environments.
  • Enabling storage for podcast episodes.
  • Supporting the establishment and management of data lakes, essential for analytics and big data endeavors.
  • Offering cloud storage output for extensive batch processes, including the storage of machine learning model artifacts or datasets.

Tus Open Protocol

SonicJs leverages TUS Open Protocol to store and retrieve file assets such as images, videos, PDFs and so on from Cloudflare R2.

The tus project endeavors to simplify and enhance the accessibility of resumable file uploads on a broad scale. Central to this initiative are the protocol specifications and the diverse array of freely accessible client and server implementations.

From a technical standpoint, the tus protocol is constructed atop HTTP/HTTPS, rendering it compatible across various platforms, spanning browsers, desktop software, and mobile applications. This approach not only ensures widespread availability but also leverages the extensive ecosystem and established best practices inherent in the HTTP framework.

R2 File Upload

Finally, let's get to some code!

File fields

Configure file fields in your data schema in the exported fields variable from a table file.

You can configure which bucket to use to upload to as well as the path to store the file in the bucket when uploaded from that field.

The code example below is for a simple blog post definition schema:

export const definition = {
  id: text("id").primaryKey(),
  title: text("title"),
  body: text("body"),
  image: text("image"),
  images: text("attachments", { mode: "json" }).$type<string[]>(),

export const fields: ApiConfig["fields"] = {
  image: {
    type: "file",
    bucket: (ctx) => ctx.env.R2_STORAGE,
    path: "images",
  images: {
    type: "file[]",
    bucket: (ctx) => ctx.env.R2_STORAGE,
    path: "attachments",


The TUS Open Protocol API is available for uploading files. The tus api is available at /tus.
In addition to the normal tus api 3 headers should be passed in the request to properly handle finding the correct bucket, the path to store the file, permissions, hooks, etc.

  • sonic-route - the route of the table the file is being uploaded to e.g 'posts'
  • sonic-field - the field name of the file e.g. 'image'
  • sonic-mode - should be 'create' if calling manually

Managing files from the Admin UI

The Sonic Backend Admin allows you to manage files for tables that you had added file fields to.

The UI uses Uppy, a modular open source JavaScript file uploader

Headless CMS Upload Image

You can also upload multiple files using the file[] array type field. The SonicJs backend UI automatically generates a form that will render a repeating files control, allowing you to manage a list of images, perhaps for a carousel or image rotator.

Headless CMS Upload Multiple Images

You can also select from all previously uploaded images by using the "Pick Existing" button:

Headless CMS Upload Select Existing Images