# Cloudflare R2 vs Amazon S3 para guardar las imágenes de tu web

> R2 y S3 hablan el mismo protocolo, pero se cobran distinto. Cuándo conviene cada uno para las imágenes de una web y cómo lo conectamos a Payload.

URL: https://codegea.com/cloudflare-r2-vs-amazon-s3-para-imagenes
Servidores · 2026-10-18 · Derian Pinto

Si tu web guarda imágenes en un bucket, probablemente pensaste en Amazon S3. Cloudflare R2 hace lo mismo, con la misma API, y se cobra de otra manera. Para las imágenes de una web, esa diferencia pesa más de lo que parece.

## La diferencia que importa: la salida de datos

Cada vez que alguien abre tu web, su navegador descarga las imágenes de tu bucket. Esa descarga es tráfico de salida. En S3 se cobra por ese tráfico. En R2, según la documentación de Cloudflare, **no se cobra la salida de datos** desde el bucket. Lo que se cobra es el almacenamiento y el número de operaciones (las que modifican datos y las que los leen), y hay una capa gratuita mensual para el almacenamiento estándar.

Para un sitio con muchas imágenes y visitas, esa es la parte que más cambia la factura. Para uno pequeño, con pocas imágenes y poco tráfico, la diferencia puede ser mínima. Revisa los precios vigentes de cada proveedor antes de decidir: cambian.

## Qué comparten

R2 se puede usar con la **API de S3**. En la práctica, las librerías y plugins que hablan con S3 funcionan apuntando a otro `endpoint`. Eso nos permite usar en este sitio el plugin de almacenamiento S3 oficial de Payload, el mismo que usarías con Amazon.

## Qué cambia

- **Dominio propio.** R2 permite servir el bucket desde un dominio tuyo, algo como `media.tudominio.com`. Esa opción requiere que el dominio esté añadido como zona en la misma cuenta de Cloudflare que el bucket. La URL `r2.dev` tiene límite de velocidad y es solo para desarrollo; para producción usa tu dominio.
- **Ecosistema.** S3 tiene muchos más servicios alrededor: notificaciones, políticas de ciclo de vida muy finas, integración con el resto de AWS. Si tu aplicación ya vive en AWS, S3 en la misma región es lo más natural.
- **Cloudflare.** R2 se integra con Workers y con la red de Cloudflare, lo que da buen rendimiento para archivos públicos.

## Cómo lo conectamos a Payload

Con el plugin `@payloadcms/storage-s3`. Esta es la configuración de este sitio, resumida:

```ts
s3Storage({
  collections: { media: publicFiles },
  bucket: process.env.S3_BUCKET ?? '',
  config: {
    endpoint: process.env.S3_ENDPOINT,
    region: process.env.S3_REGION ?? 'us-east-1',
    forcePathStyle: true,
    credentials: {
      accessKeyId: process.env.S3_ACCESS_KEY_ID ?? '',
      secretAccessKey: process.env.S3_SECRET_ACCESS_KEY ?? '',
    },
  },
}),
```

El `endpoint` es lo que decide a quién le hablas. En producción apunta a R2; en local, a MinIO, un servidor S3 en un contenedor Docker. El código no cambia.

Para que el navegador pida las imágenes directo al bucket, y no a través de Payload, definimos cómo se construye la URL pública:

```ts
const publicFiles = process.env.S3_PUBLIC_URL
  ? {
      disablePayloadAccessControl: true as const,
      generateFileURL: ({ filename, prefix }) =>
        [process.env.S3_PUBLIC_URL?.replace(/\/$/, ''), prefix, filename].filter(Boolean).join('/'),
    }
  : true;
```

Con `S3_PUBLIC_URL` definida (tu dominio de R2), Payload devuelve esa URL. Sin ella, como pasa en local, sirve él mismo los archivos. Para las credenciales, R2 da un par de claves de API propio, que se crea en el panel de Cloudflare.

## Un detalle que nos mordió

Si subes imágenes desde un script, no reutilices el mismo `context` entre llamadas a `payload.create`. El plugin S3 guarda estado ahí, y la segunda subida del proceso se perdía. Pasar un `context` nuevo en cada llamada lo arregló. Lo contamos junto con otros tropiezos en [así está construido codegea.com](/asi-esta-construido-codegea-nextjs-payload-turso-r2).

## Cuándo elegir cada uno

- **R2:** sitios con muchas imágenes o descargas, donde la salida de datos pesaría, y proyectos donde ya usas Cloudflare para el DNS.
- **S3:** si tu aplicación ya corre en AWS, o necesitas funciones del ecosistema de Amazon que R2 no tiene.

Y para esa decisión de infraestructura, el siguiente paso suele ser poner el resto del sitio detrás de Cloudflare. Lo vemos en [Cloudflare delante de tu web](/cloudflare-delante-de-tu-web-firewall-y-ssl).
