For the complete documentation index, see llms.txt. Prefer markdown by appending.mdto documentation URLs or sendingAccept: text/markdown.
Storage
Cloudflare R2 storage for files, images, and documents, with upload validation, authenticated file delivery, and an extensible ownership pattern.
Edge Kit includes the infrastructure for uploading, storing, serving, and deleting files in your application. Use it as the starting point for customer attachments, product media, generated reports, or other files your product needs.
Files live in Cloudflare R2, an object store connected directly to your Worker. The kit brings together the bucket binding, server functions, validation, and a protected delivery route. A complete avatar upload flow demonstrates how these pieces fit together.
Why R2?
R2 keeps file contents in object storage, while D1 holds their ownership and product relationships. The Worker binding provides direct access for uploads and downloads, and local simulation lets you develop file features without writing to your production bucket.
Storage infrastructure
The integration gives you a working pattern for the full file lifecycle:
| Capability | Included |
|---|---|
| Uploads | Authenticated server functions and file validation |
| Object storage | An R2 bucket binding available to your server code |
| File delivery | A protected route that returns file content and HTTP metadata |
| Ownership | Server-derived object keys and access checks in the included flow |
| Deletion | Authenticated removal and an account cleanup example |
| Development | Local R2 storage separate from your production bucket |
You can build new file features on the same connection and server boundaries. Each feature defines its file formats, storage location, and access policy.
Uploads
The browser submits a file to a server function. The Worker checks the session and validates the file, chooses its storage key, and writes it to R2 with the appropriate content metadata. It returns an application URL that the UI can use to display or download the result.
For a document attachment, for example, associate the stored file with its document record in D1. This gives your application a place to track its owner, label, and relationship to the rest of your product.
Upload processing runs in your Worker. Choose file-size and processing rules appropriate to the feature and Workers request limits.
Validation and metadata
Treat a file's name and browser-supplied type as input, alongside its size and content. Define the accepted formats for each feature on the server and give the customer a useful explanation when an upload does not meet those rules.
A PDF attachment feature, for example, can define its own size and type rules with Zod:
import { z } from "zod";
const documentSchema = z
.file()
.max(10 * 1024 * 1024)
.mime(["application/pdf"]);This example allows files up to 10 MiB with the declared PDF type. These are rules for the new attachment feature, separate from the avatar defaults below. MIME validation does not inspect the file's contents; add content checks when the feature requires them.
An object key is the storage address, while the original filename is presentation data. Keeping them separate lets you choose predictable ownership boundaries without trusting a filename as a path. Store a customer-friendly label with the related database record when your interface needs one.
For downloads, choose the response's content type and disposition around the file's purpose. A product image may render inline; an exported report may download as an attachment. Keep user-provided content from being served as executable application content.
Access and delivery
The included delivery route checks the session and ownership before returning an object from R2. File content, content type, and cache metadata are delivered together, so the browser can render the result correctly.
Build on this pattern for private documents or downloads. For shared attachments, check access to the parent resource, such as a project, before serving its files. Product images intended for everyone can use a deliberately public delivery policy.
File permissions
Keep upload, read, replacement, and deletion rules aligned. Knowing a file's URL should not grant access to a private resource.
Public and private files
Choose delivery around the audience for the file:
| Audience | Access policy |
|---|---|
| One customer | Resolve the session and verify ownership before serving |
| Members of a shared resource | Check the resource's permissions before serving |
| Anyone with an approved sharing link | Add an explicit sharing policy, expiration, and revocation rules |
| Public visitors | Use a deliberately public URL and suitable caching |
The kit's protected route is the starting point for private delivery. Public buckets, expiring sharing links, and large direct-to-storage uploads are design choices you can add for your product; they need their own permissions and delivery setup. R2's presigned URL guide explains an option for direct object access.
File management
Deletion belongs to the feature that owns the file. Use the included ownership checks as a reference when replacing an attachment, removing a record, or cleaning up an account.
For collections of files, track their relationship to your product data and make cleanup cover the complete collection. Background jobs provide a place for processing or cleanup that should happen outside the customer's request.
An object write and a database update are separate operations. If an upload succeeds but saving its record fails, decide how that unreferenced object will be removed. When replacing a file, keep the previous one available until the new object and its record are ready, then schedule cleanup as needed.
For processing workflows, track a state such as pending, ready, or failed on the product record. That gives the UI a useful status while a job generates a preview or report, and lets a retry resume without creating a second logical file.
Storage allowances
If your plans include a file count or storage allowance, record the usage needed to enforce that offer and check it during uploads. Keep replacement and deletion in the same accounting policy so customers recover the allowance when files are removed.
The billing catalog describes the allowance customers purchase; the upload operation enforces it. Test concurrent or repeated submissions when a feature must not exceed its limit.
Avatar example
Account settings demonstrate the complete upload and deletion flow. The example accepts JPEG, PNG, and WebP images up to 5 MiB, stores them under the customer's ownership, and uses the protected route to display them. Account deletion also cleans up the customer's avatars.
Use this example as a reference when adding another file type. Adapt the validation, object keys, and delivery permissions to that feature.
![]()
Configuration
Connect your bucket to the UPLOADS binding through Wrangler configuration. Local development simulates R2 separately, and Local Explorer lets you inspect the stored objects.
Cloudflare's Workers storage API covers additional object operations. The feature recipe shows how to connect a new UI to protected server logic and product data.
How is this guide?
Last updated on