#File storage R2
8 messages · Page 1 of 1 (latest)
Hi @mellow bloom. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
Here’s what’s in the provided sources about Convex’s built‑in storage vs using Cloudflare R2 via the Convex R2 component.
Convex Storage (built‑in)
Pros
- Fully managed and integrated: no extra setup beyond Convex itself; files live in Convex’s own “storage” table and are accessed via
ctx.storageand HTTP actions. [Auth thread] - Simple public URLs:
ctx.storage.getUrl()returns a permanent URL (non‑expiring) that you can persist and use directly (sized for large files, including gigabytes). [Image/file caching] - Works well with HTTP actions: you can implement arbitrary authorization logic by streaming files from a function or HTTP action instead of giving out URLs directly. [Auth thread]
Cons / limitations (from sources)
- No built‑in image optimization or “smart CDN” layer today; images are served “straight from S3 every time and are slower than we’d like.” [Image/file caching]
- CDN‑style caching for storage/file fetches is on the roadmap but not implemented yet. [Image/file caching]
- HTTP action request/response size is limited to 20 MB; for larger files you must use storage URLs instead of proxying through an action. [Auth thread; Image/file caching]
- Bandwidth of Convex Storage is billed as part of Convex; that charge does not apply to external services like R2. [R2/S3 billing]
Cloudflare R2 via the Convex R2 component
What it gives you
- A dedicated Convex component (
@convex-dev/r2) that “wraps the API” of R2: upload hooks, signed URLs, metadata sync, and helpers for listing/serving/deleting files. [Cloudflare R2; Risks with deep integrations] - Client‑side upload hooks (
useUploadFilefor React / Svelte) that:- Generate signed upload URLs
- Upload the browser file directly to R2
- Sync metadata into Convex and optionally run callbacks. [Uploading files]
- Server‑side helpers:
r2.store(ctx, blob | Buffer | Uint8Array, options)to upload from actions (e.g., generated or downloaded files). [Storing from actions]r2.getUrl(key, { expiresIn? })to generate expiring file URLs; default expiry 15 minutes, configurable. [Serving files]r2.getMetadata,r2.listMetadata,r2.pageMetadata, andonSyncMetadatato work with metadata in Convex. [Accessing metadata]r2.deleteObject(ctx, key)to delete files. [Deleting files]
- R2 bandwidth is billed by Cloudflare, not as Convex Storage bandwidth. Convex charges normal action compute for the code you run around R2. [R2/S3 billing]
Pros (vs Convex storage, from sources)
- Timed URLs: unlike
ctx.storage.getUrl(permanent),r2.getUrlcan generate URLs with a custom expiration (expiresIn), which is useful for access control and link leakage. [Serving files; Auth thread] - CDN‑style delivery / caching: the R2 component is explicitly suggested as the answer to performance/caching needs that Convex Storage doesn’t yet solve, and as the “gold standard” approach for more advanced file pipelines. [Image/file caching; UploadThing thread]
- Cost flexibility: when using R2, you avoid Convex storage bandwidth charges; instead you pay Cloudflare’s storage/egress model, which in some use cases can be cheaper. [R2/S3 billing]
- More control over storage backend: you can also point self‑hosted Convex at an S3‑compatible backend (including R2) using
S3_ENDPOINT_URL, although that’s at the infra level rather than the component level. [Self‑hosting with S3/R2]
Cons / tradeoffs
- More setup: you must:
- Create and configure an R2 bucket, CORS rules, and API token in Cloudflare.
- Set
R2_BUCKET,R2_TOKEN,R2_ACCESS_KEY_ID,R2_SECRET_ACCESS_KEY,R2_ENDPOINTas Convex env vars. - Add the R2 component to
convex.config.ts. [Cloudflare R2]
- Two systems to manage: operationally you now have Convex and Cloudflare R2 (billing, quotas, CORS policies, etc.).
- Some logic may need to move: for large processing workflows (e.g., heavy PDF processing in actions) you might decide to offload more work to Cloudflare Workers or other infra; one Discord thread mentions hitting limits when loading a ~10 MB PDF back from R2 for processing in Convex. [10MB PDF thread]
When to choose which (based on sources)
- Use Convex Storage when:
- You want the simplest possible setup.
- File sizes are moderate and you don’t need timed URLs or advanced CDN behavior.
- You’re fine with Convex handling storage + bandwidth billing.
- Use Cloudflare R2 component when:
- You care about expiring URLs, stronger control over link lifetime, or tighter integration with an external CDN. [Serving files]
- You want Cloudflare’s R2 pricing/egress semantics instead of Convex storage bandwidth. [R2/S3 billing]
- You’re already using Cloudflare and want a standardized storage backend across services.
- You need a more “advanced” or future‑proof file pipeline (R2 component is pointed to in several threads as the better solution for caching/serving media). [Image/file caching; Auth thread]