R2 Fields
Cloudflare R2 is a globally distributed object storage service that allows you to store and serve large amounts of unstructured data, such as images, videos, and other media files. With Cloesce, you can easily integrate R2 into your application by defining R2 fields in your Models.
Many of the same concepts and syntax for defining KV fields in Cloesce also apply to R2 fields. Read the KV fields chapter for more information.
Defining an Environment Binding
To use R2 fields in your Models, you first need to define an environment binding for the R2 bucket in your Cloesce schema:
env {
r2 {
my_bucket
}
}
Defining an R2 Field
Note
R2 is used to store large unstructured data. For this reason, Cloesce will not query and buffer the full value of an R2 field into the worker runtime. Instead, only a
HEADrequest is made to R2 to check for existence and retrieve metadata.
A field in a Model can exist in Cloudflare R2 by using the r2 block, which specifies the binding and key for a field.
Unlike KV fields, no specific type is necessary for an R2 field declaration, as the actual value is never queried and buffered into memory in the application layer.
model Image {
keyfield {
id: string
}
r2 (my_bucket, "images/{id}.jpg") {
my_image
}
}
The above snippet defines a Model Image with an R2 field my_image that is stored in the bucket my_bucket under the key “images/{id}.jpg”.
The {id} in the key is a placeholder that will be replaced with the actual value of the id keyfield when accessing R2. See information about keyfields in the KV fields chapter.
Paginated List Queries
Cloesce supports paginated prefix list queries for R2 fields, using the same paginated modifier on the r2 block as KV fields.
This allows you to efficiently retrieve lists of objects stored in R2 with a common key prefix, without having to load all objects into memory at once.
model Image {
keyfield {
id: string
}
r2 (my_bucket, "images/") paginated {
my_image
}
}
In the above example, the paginated block indicates that my_image is an R2 field that should be queried using a paginated prefix list query. When you query for my_image, Cloesce will automatically handle the pagination logic and return a list of objects that match the specified key prefix (e.g. "images/foo", "images/bar", etc.).
Generated Types
Backend
Since Cloesce does not fetch the actual value of an R2 field into the application layer, the Cloudflare standard R2ObjectBody type is used for all R2 fields in the generated backend code.
Frontend
It is possible to serialize the r2object type (or a Model field under the r2 block).
Cloesce will send a subset of the full R2 HEAD response metadata back to the frontend, including the key, version, size, etag, httpEtag, uploaded timestamp, and any custom metadata defined on the R2 object. This allows you to work with R2 objects in the frontend without having to fetch the full object data.
export class R2Object {
key!: string;
version!: string;
size!: number;
etag!: string;
httpEtag!: string;
uploaded!: Date;
customMetadata?: Record<string, string>;
}