From 918f0cece94d4db40e7c4960c3b9be58aa9c46fb Mon Sep 17 00:00:00 2001
From: Thomas Desmond <24610108+thomas-desmond@users.noreply.github.com>
Date: Mon, 31 Mar 2025 09:31:55 -0700
Subject: [PATCH 1/3] New reference architecture diagram: Storing user
generated content
---
.../ai-generated-content-in-r2.svg | 7378 ++++++++++++++++
.../uploads-to-r2-via-signed-urls.svg | 7379 +++++++++++++++++
src/content/docs/r2/api/s3/presigned-urls.mdx | 1 +
.../reference-architecture/by-solution.mdx | 1 +
.../storing-user-generated-content.mdx | 86 +
5 files changed, 14845 insertions(+)
create mode 100644 src/assets/images/reference-architecture/storing-user-generated-content/ai-generated-content-in-r2.svg
create mode 100644 src/assets/images/reference-architecture/storing-user-generated-content/uploads-to-r2-via-signed-urls.svg
create mode 100644 src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
diff --git a/src/assets/images/reference-architecture/storing-user-generated-content/ai-generated-content-in-r2.svg b/src/assets/images/reference-architecture/storing-user-generated-content/ai-generated-content-in-r2.svg
new file mode 100644
index 000000000000000..8ef75b13e8a2e43
--- /dev/null
+++ b/src/assets/images/reference-architecture/storing-user-generated-content/ai-generated-content-in-r2.svg
@@ -0,0 +1,7378 @@
+
diff --git a/src/assets/images/reference-architecture/storing-user-generated-content/uploads-to-r2-via-signed-urls.svg b/src/assets/images/reference-architecture/storing-user-generated-content/uploads-to-r2-via-signed-urls.svg
new file mode 100644
index 000000000000000..4d8b88e4f985842
--- /dev/null
+++ b/src/assets/images/reference-architecture/storing-user-generated-content/uploads-to-r2-via-signed-urls.svg
@@ -0,0 +1,7379 @@
+
diff --git a/src/content/docs/r2/api/s3/presigned-urls.mdx b/src/content/docs/r2/api/s3/presigned-urls.mdx
index 47297fe78c32529..1d9a4ffe1205e97 100644
--- a/src/content/docs/r2/api/s3/presigned-urls.mdx
+++ b/src/content/docs/r2/api/s3/presigned-urls.mdx
@@ -195,3 +195,4 @@ Presigned URLs can only be used with the `.r2.cloudflarestorage.com`
## Related resources
* [Create a public bucket](/r2/buckets/public-buckets/)
+* [Storing user generated content](/reference-architecture/diagrams/storage/storing-user-generated-content/)
diff --git a/src/content/docs/reference-architecture/by-solution.mdx b/src/content/docs/reference-architecture/by-solution.mdx
index 38603e479da8846..e0b769e57fce68b 100644
--- a/src/content/docs/reference-architecture/by-solution.mdx
+++ b/src/content/docs/reference-architecture/by-solution.mdx
@@ -125,3 +125,4 @@ Architecture content for our developer platform.
- [Egress-free object storage in multi-cloud setups](/reference-architecture/diagrams/storage/egress-free-storage-multi-cloud/)
- [On-demand Object Storage Data Migration](/reference-architecture/diagrams/storage/on-demand-object-storage-migration/)
- [Event notifications for storage](/reference-architecture/diagrams/storage/event-notifications-for-storage/)
+- [Storing User Generated Content](/reference-architecture/diagrams/storage/storing-user-generated-content/)
diff --git a/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx b/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
new file mode 100644
index 000000000000000..8a51f664f787437
--- /dev/null
+++ b/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
@@ -0,0 +1,86 @@
+---
+title: Storing user generated content
+pcx_content_type: reference-architecture-diagram
+products:
+ - R2
+sidebar:
+ order: 1
+ label: Storing user generated content
+updated: 2025-03-31
+---
+
+## Introduction
+
+User generated content (UGC) is an essential aspect of modern applications. This includes users uploading profile photos, documents, and videos, as well as AI models generating images, summaries, or structured data. Therefore, applications require a reliable, scalable, and cost-effective solution for storing and accessing this content.
+
+Cloudflare [R2](/r2/) is an S3-compatible object storage with zero egress fees, making it ideal for handling content uploads and delivery at scale. Combined with Cloudflare [Workers](/workers/) and Cloudflare's global network, it enables fast, secure, and cost-effective workflows for ingesting and managing UGC.
+
+This reference architecture explores two common UGC workflows, both optimized for performance, security, and cost efficiency:
+
+1. **Secure User Uploads to R2 via Signed URLs:** Allowing users to upload files (profile images, documents, etc.) efficiently and securely without overloading backend systems.
+2. **AI-Generated Content Stored in R2:** Storing content generated by Workers AI or external AI services, ensuring inference results are persistently available for future use.
+
+## Use Cases
+
+### Use Case 1: Secure User Uploads to R2 via Signed URLs
+
+User generated content typically starts with file uploads, including profile pictures, resumes, rich media, and documents. Applications must securely validate and store these uploads while avoiding latency, high costs, and unnecessary complexity in the backend.
+
+In this architecture, we use **R2** as the primary storage layer and a **Worker** to control upload access. Files are uploaded directly from the user's browser or device to R2 using signed URLs, which are generated by the Worker after validating the user's permissions and upload intent.
+
+This approach avoids routing large files through the application backend or Worker, reducing latency and operational cost—while ensuring tight control over access and security.
+
+And because R2 is natively integrated with Cloudflare's global network, files stored in R2 are accessible with low latency from anywhere in the world—and **without any egress fees**, even as your application scales.
+
+
+
+**How it Works**
+
+1. **User initiates upload from the frontend:** The app collects file details (e.g. size, name) and calls a backend API (a Cloudflare Worker) to begin the upload process.
+2. **Worker authenticates the user and validates the request:** The Worker confirms that the user is logged in, has upload permissions, and that the file is within acceptable limits (e.g. 10MB max, allowed MIME types).
+3. **Worker returns a signed PUT URL to R2:** A signed URL allows the frontend to upload directly to R2 for a limited time, under a specific key or namespace. No need for the Worker to handle large files directly.
+4. **Frontend uploads the file directly to R2:** The file is streamed directly from the client to R2.
+5. **(Optional) Trigger post-upload workflows:** R2 offers [event notifications](/r2/buckets/event-notifications/) to send messages to a queue when data in your R2 bucket changes, like a new upload. Example post-processing:
+ - Scan, moderate, or transform the file.
+ - Write metadata (e.g. `user_id`, `file_path`, `timestamp`) to [D1](/d1/), Cloudflare's serverless SQL database.
+ - Notify the user or update a dashboard/UI.
+
+For more information on uploading data directly from the client to R2, refer to the documentation on [presigned URLs](/r2/api/s3/presigned-urls/).
+
+### Use Case 2: AI-Generated Content Stored in R2
+
+Many modern applications utilize AI-generated content, which can include product descriptions, profile pictures, audio clips, and more. When this content is created in response to user actions or scheduled events, it must be stored immediately, reliably, and at scale.
+
+This architecture employs [Workers AI](/workers-ai/) to perform inference at the edge and then stores the generated output directly in Cloudflare R2, all within a single Worker.
+
+
+
+**How it Works**
+
+1. **User initiates content generation:** The frontend sends a request to a Cloudflare Worker to create content using an AI model (e.g. "Create a thumbnail image for this product").
+2. **Worker invokes Workers AI:** The Worker passes the user input to a model deployed on Workers AI.
+3. **Generated output is returned to the Worker:** The response could be plain text, a Base64 image, a binary buffer, or other structured data—depending on the model type.
+4. **Worker uploads the output to R2 directly:** No signed URL or client upload is needed. The Worker performs a secure, authenticated `PUT` request to store the output in a designated bucket.
+5. **Worker returns success and metadata to the frontend:** The client receives a reference to the stored file (such as a path, object key, or signed download URL if needed).
+
+Refer to [Use R2 from Workers](/r2/api/workers/workers-api-usage/) for more information on accessing R2 buckets via Cloudflare Workers.
+
+## Summary
+
+By storing **user-generated content in Cloudflare R2**, applications gain:
+
+- A highly scalable storage backend
+- Fast access through Cloudflare's edge computing
+- Predictable costs with zero egress fees
+- Seamless AI + UGC workflows that maximize efficiency
+
+This architecture ensures that content is stored, processed, and delivered **fast, securely, and cost-effectively**.
+
+## Related Links
+
+- [Cloudflare R2 Product Page](/developer-platform/products/r2/)
+- [R2 Presigned URLs](/r2/api/s3/presigned-urls/)
+- [Use R2 from Workers](/r2/api/workers/workers-api-usage/)
+- [Why choose Cloudflare R2 vs Amazon S3](/pg-cloudflare-r2-vs-aws-s3/)
+- [Migrating Data to R2](/r2/data-migration/)
+- [Event notifications for storage reference architecture](/reference-architecture/diagrams/storage/event-notifications-for-storage/)
From fa78eba1d2360acc219500882ee9801d49993ba6 Mon Sep 17 00:00:00 2001
From: Jun Lee
Date: Wed, 2 Apr 2025 09:49:25 +0100
Subject: [PATCH 2/3] Apply suggestions from code review
---
.../diagrams/storage/storing-user-generated-content.mdx | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx b/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
index 8a51f664f787437..cac5f8b30c5fca3 100644
--- a/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
+++ b/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
@@ -37,12 +37,12 @@ And because R2 is natively integrated with Cloudflare's global network, files st
**How it Works**
1. **User initiates upload from the frontend:** The app collects file details (e.g. size, name) and calls a backend API (a Cloudflare Worker) to begin the upload process.
-2. **Worker authenticates the user and validates the request:** The Worker confirms that the user is logged in, has upload permissions, and that the file is within acceptable limits (e.g. 10MB max, allowed MIME types).
-3. **Worker returns a signed PUT URL to R2:** A signed URL allows the frontend to upload directly to R2 for a limited time, under a specific key or namespace. No need for the Worker to handle large files directly.
+2. **Worker authenticates the user and validates the request:** The Worker confirms that the user is logged in, has upload permissions, and that the file is within acceptable limits (for example, 10MB max, allowed MIME types).
+3. **Worker returns a signed PUT URL to R2:** A signed URL allows the frontend to upload directly to R2 for a limited time, under a specific key or namespace. There is no need for the Worker to handle large files directly.
4. **Frontend uploads the file directly to R2:** The file is streamed directly from the client to R2.
5. **(Optional) Trigger post-upload workflows:** R2 offers [event notifications](/r2/buckets/event-notifications/) to send messages to a queue when data in your R2 bucket changes, like a new upload. Example post-processing:
- Scan, moderate, or transform the file.
- - Write metadata (e.g. `user_id`, `file_path`, `timestamp`) to [D1](/d1/), Cloudflare's serverless SQL database.
+ - Write metadata (for example, `user_id`, `file_path`, `timestamp`) to [D1](/d1/), Cloudflare's serverless SQL database.
- Notify the user or update a dashboard/UI.
For more information on uploading data directly from the client to R2, refer to the documentation on [presigned URLs](/r2/api/s3/presigned-urls/).
@@ -57,7 +57,7 @@ This architecture employs [Workers AI](/workers-ai/) to perform inference at the
**How it Works**
-1. **User initiates content generation:** The frontend sends a request to a Cloudflare Worker to create content using an AI model (e.g. "Create a thumbnail image for this product").
+1. **User initiates content generation:** The frontend sends a request to a Cloudflare Worker to create content using an AI model (for example, "Create a thumbnail image for this product").
2. **Worker invokes Workers AI:** The Worker passes the user input to a model deployed on Workers AI.
3. **Generated output is returned to the Worker:** The response could be plain text, a Base64 image, a binary buffer, or other structured data—depending on the model type.
4. **Worker uploads the output to R2 directly:** No signed URL or client upload is needed. The Worker performs a secure, authenticated `PUT` request to store the output in a designated bucket.
From a535947d4bf8ec43fb5edeb97f0c8805790983cd Mon Sep 17 00:00:00 2001
From: Thomas Desmond <24610108+thomas-desmond@users.noreply.github.com>
Date: Wed, 2 Apr 2025 07:13:50 -0700
Subject: [PATCH 3/3] Fix broken links
---
.../diagrams/storage/storing-user-generated-content.mdx | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx b/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
index 8a51f664f787437..7e0c3c36c61b7ee 100644
--- a/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
+++ b/src/content/docs/reference-architecture/diagrams/storage/storing-user-generated-content.mdx
@@ -78,9 +78,9 @@ This architecture ensures that content is stored, processed, and delivered **fas
## Related Links
-- [Cloudflare R2 Product Page](/developer-platform/products/r2/)
+- [Cloudflare R2 Product Page](/r2/)
- [R2 Presigned URLs](/r2/api/s3/presigned-urls/)
- [Use R2 from Workers](/r2/api/workers/workers-api-usage/)
-- [Why choose Cloudflare R2 vs Amazon S3](/pg-cloudflare-r2-vs-aws-s3/)
- [Migrating Data to R2](/r2/data-migration/)
- [Event notifications for storage reference architecture](/reference-architecture/diagrams/storage/event-notifications-for-storage/)
+- [Why choose Cloudflare R2 vs Amazon S3](https://www.cloudflare.com/pg-cloudflare-r2-vs-aws-s3/)