#File storage R2

8 messages · Page 1 of 1 (latest)

mellow bloom
#

Convex storage vs Cloudflare R2. Pros and cons

velvet creekBOT
#

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.storage and 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 (useUploadFile for 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, and onSyncMetadata to 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.getUrl can 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_ENDPOINT as 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]

If you share your concrete use case (image gallery, user‑private docs, video streaming, etc.), I can map it more directly to these tradeoffs using just the info above.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: