¿Cuánto cuesta guardar archivos e imágenes de los usuarios?

Guardar uploads cuesta la suma de tres líneas: GB almacenados al mes, peticiones de subida y lectura, y la salida de datos cuando alguien descarga. En muchos proveedores, la salida pesa más que el almacenamiento.

Actualizado el 7 min de lectura

Objetivos de aprendizaje

Después de leer este artículo podrás:

  • Entender las líneas que componen la factura de guardar archivos de usuarios
  • Estimar el costo de un año de uploads con una cuenta paso a paso
  • Reducir el gasto con compresión, reglas de ciclo de vida y caché
En esta página

Foto de perfil, adjunto de chat, comprobante en PDF, imagen de producto: casi toda app termina guardando archivos que envían los usuarios. Al principio el volumen es pequeño y la factura ni aparece. El problema es que los uploads se acumulan. A diferencia del tráfico, que sube y baja, lo que guardaste sigue ahí el mes siguiente, y el otro. Por eso conviene estimar un año de uploads antes de elegir dónde guardarlos.

Los números de este artículo son hipotéticos, elegidos para facilitar la cuenta, y están en dólares estadounidenses. No son precios de ningún proveedor; los valores reales cambian, varían por región y están en las páginas oficiales, así que revisa las páginas oficiales de AWS y de Backblaze antes de decidir.

costo mensualmes 1mes 6mes 12Salidavaría con las vistasPeticionesestablesAlmacenamientocrece cada mes
Cada mes suma archivos nuevos a los antiguos, así que el almacenamiento solo crece; la salida sigue las vistas.

¿De qué está hecha la factura de guardar uploads?#

En un object storage, que es donde suelen vivir los uploads (mira qué es el object storage), la factura tiene hasta tres líneas:

  • Almacenamiento: precio por GB guardado al mes. Es la línea que crece sola, porque cada mes suma los archivos nuevos a los antiguos.
  • Peticiones: cada subida (PUT) y cada lectura (GET) puede cobrarse, en general por millar. Pesa en apps con muchos archivos pequeños, como miniaturas.
  • Salida de datos (egress): precio por GB que sale del storage hacia internet cuando alguien abre el archivo. En varios proveedores es la línea más cara. El artículo sobre tarifas de salida explica cómo funciona.

Fuera del storage entran el procesamiento (generar miniaturas consume CPU de tu servidor) y, si la usas, la CDN delante de los archivos públicos.

¿Cómo cobran los proveedores cada línea?#

Dos modelos de cobro, con los valores hipotéticos que usa la cuenta más adelante:

Concepto (valor hipotético) Proveedor A: cobra cada línea Proveedor B: franquicia de salida
Almacenamiento US$0,02 por GB/mes US$5 por TB/mes
Subidas (PUT, COPY, POST, LIST) US$0,01 por 1.000 Sin cargo
Lecturas (GET) US$0,001 por 1.000 Sin cargo
Salida a internet Primeros 100 GB/mes sin cargo, luego US$0,10 por GB Sin cargo hasta 2 veces el volumen almacenado, luego US$0,02 por GB

Los dos diseños existen en el mercado. S3 cobra cada línea por separado y tiene clases más baratas para archivos que se leen poco, como el proveedor A. B2 tiene almacenamiento más barato por GB e incluye las peticiones y parte de la salida, como el proveedor B. Ninguno es más barato en todos los casos: la respuesta depende de cuánto guardas y de cuánto se descarga.

¿Cómo estimar el volumen de uploads?#

Haz la cuenta con cuatro números:

GB por mes = uploads por mes × tamaño medio × número de versiones guardadas
GB guardados en el mes N = GB por mes × N

Lo que más mueve la factura es el número de versiones. Muchas apps guardan el original subido, una versión de visualización y una miniatura. Una foto de celular pesa algunos MB; la misma imagen redimensionada en WebP para mostrarla pesa unos cientos de KB, y la miniatura algunas decenas.

Ejemplo hipotético: una app con 5.000 usuarios activos, cada uno de los cuales sube 10 fotos al mes. Cada upload genera un original de 3 MB, una versión de visualización de 300 KB y una miniatura de 40 KB. Cada mes la app sirve 1 millón de visualizaciones de la versión grande y 3 millones de miniaturas.

El script de abajo calcula la factura del mes 12 y funciona en cualquier versión reciente de Node.js:

js
// costo-uploads.mjs: node costo-uploads.mjs
// Ejemplo hipotético en US$: el proveedor A cobra cada línea; el B tiene franquicia de salida.
// No son precios de ningún proveedor; cámbialos por los de las páginas oficiales antes de usar el resultado.
const uploadsPorMes = 50_000; // 5.000 usuarios x 10 fotos
const meses = 12;
const mbPorUpload = 3 + 0.3 + 0.04; // original + versión de visualización + miniatura
const putsPorUpload = 3;
const getsPorMes = 4_000_000; // 1 millón de visualizaciones + 3 millones de miniaturas
const gbDescargadosPorMes = 1_000_000 * 0.0003 + 3_000_000 * 0.00004; // 420 GB

const gbGuardados = (uploadsPorMes * mbPorUpload * meses) / 1000;

const proveedorA = {
  almacenamiento: gbGuardados * 0.02,
  peticiones:
    ((uploadsPorMes * putsPorUpload) / 1000) * 0.01 +
    (getsPorMes / 1000) * 0.001,
  salida: Math.max(0, gbDescargadosPorMes - 100) * 0.1,
};
const proveedorB = {
  almacenamiento: (gbGuardados / 1000) * 5, // US$ 5 por TB-mes
  peticiones: 0, // sin cobro por petición
  salida: Math.max(0, gbDescargadosPorMes - 2 * gbGuardados) * 0.02, // franquicia de 2x lo almacenado
};

console.log(`Guardado en el mes ${meses}: ${gbGuardados.toFixed(0)} GB`);
for (const [nombre, c] of Object.entries({ "Proveedor A": proveedorA, "Proveedor B": proveedorB })) {
  const total = c.almacenamiento + c.peticiones + c.salida;
  console.log(
    `${nombre}: almacenamiento US$ ${c.almacenamiento.toFixed(2)}, ` +
      `peticiones US$ ${c.peticiones.toFixed(2)}, ` +
      `salida US$ ${c.salida.toFixed(2)}, total US$ ${total.toFixed(2)}`,
  );
}

Resultado, con cerca de 2 TB guardados en el mes 12:

Proveedor Almacenamiento Peticiones Salida Total del mes 12
Proveedor A US$40,08 US$5,50 US$32,00 US$77,58
Proveedor B US$10,02 US$0,00 US$0,00 US$10,02

Los números salen de los valores hipotéticos, sin impuestos ni tipo de cambio. En el proveedor B, la salida queda sin cargo solo porque el volumen descargado (420 GB) es menor que 2 veces lo almacenado; en el primer mes, con solo 167 GB guardados, la franquicia sería de 334 GB y los 86 GB restantes se cobrarían.

¿Qué pesa más: almacenamiento, peticiones o salida?#

Ejecuta el mismo script sin guardar el original (cambia mbPorUpload a 0.3 + 0.04). El almacenamiento del mes 12 baja de 2.004 GB a 204 GB, y el total en el proveedor A baja de US$77,58 a US$41,58. La salida sigue igual, en US$32,00, porque los visitantes nunca descargaban el original.

El ejemplo deja tres conclusiones:

  1. El original es el mayor costo de almacenamiento. Ocupa casi el 90% del espacio en el ejemplo y no se muestra a nadie.
  2. La salida sigue a las visualizaciones, no al volumen guardado. En una app popular supera con facilidad al almacenamiento, en proveedores que cobran egress.
  3. Las peticiones rara vez dominan, salvo con millones de archivos diminutos o lecturas repetidas sin caché.

¿Qué costos ocultos aparecen?#

  • Archivos huérfanos. El usuario borra su cuenta o cambia la foto, y el archivo viejo se queda en el bucket para siempre. Borra el objeto junto con el registro en la base de datos.
  • Uploads multipart incompletos. En subidas grandes divididas en partes, las partes de una subida abandonada siguen ocupando espacio. AWS recomienda una regla de ciclo de vida con AbortIncompleteMultipartUpload para borrarlas después de algunos días. Mira cómo subir archivos grandes.
  • Versionado activado. Con versionado, sobrescribir un archivo no borra la versión anterior, y cada versión se cobra.
  • Duración mínima en clases frías. Las clases de acceso infrecuente cobran un tiempo mínimo de almacenamiento (30 días en S3 Standard-IA, de 90 a 180 días en las clases Glacier). Mover allí archivos que se borrarán pronto puede salir más caro.
  • Imágenes en la base de datos o en el disco del servidor. Guardar bytes en la base encarece el disco y los dumps; guardarlos en el disco local de la aplicación ata los archivos a una máquina. Compara en imágenes en la base de datos vs object storage y object storage vs disco local.
  • Hotlinking. Otro sitio que usa el enlace directo de tus imágenes genera salida en tu factura.

¿Cómo reducir el costo de guardar uploads?#

En orden de retorno:

  1. Redimensiona y comprime al subir. Genera la versión de visualización en WebP o AVIF con un ancho máximo y decide si el original realmente tiene que quedarse.
  2. Limita tamaño y tipo de archivo antes de aceptar la subida. Un límite de 10 MB y una lista de extensiones permitidas evitan videos de 2 GB en un campo de foto de perfil.
  3. Usa reglas de ciclo de vida para borrar temporales, mover originales a una clase más barata y limpiar subidas incompletas. Mira reglas de ciclo de vida.
  4. Pon caché delante de los archivos públicos, con un Cache-Control largo en archivos que no cambian, para que la salida del storage ocurra una vez por archivo y no una vez por visita.
  5. Sube directo del navegador al storage con una URL prefirmada, para que el archivo no pase por tu servidor ni consuma su ancho de banda.
  6. Elige el proveedor por la línea que más pesa en tu caso. Muchas visualizaciones piden salida barata; mucho volumen guardado pide almacenamiento barato. El artículo sobre el costo del object storage compara modelos de precio.

Cómo hacerlo en Square Cloud#

En Square Cloud, los uploads pueden ir al Blob Storage, un object storage con API compatible con S3 (aws-cli, rclone, boto3 y los SDKs de AWS), API REST y panel. No cobra tarifa de salida ni de entrada, así que la línea de salida del ejemplo no existe aquí: la descarga no tiene cobro de ancho de banda. El límite que sí aplica es un rate limit de peticiones S3 por plan.

Todos los planes incluyen una cuota de Blob, de 5 GB a 250 GB. El Hobby, desde R$12,49 al mes, incluye de 5 a 15 GB. Los archivos públicos se sirven por una CDN global en el edge; los privados se abren con un enlace temporal de hasta 24 horas o con un enlace para compartir revocable de hasta 30 días.

Las reglas por carpeta cubren buena parte de este artículo: tamaño máximo, extensiones permitidas, expiración, caché y limpieza automática. Los archivos pueden tener hasta 10 GB, y la subida multipart solo es obligatoria por encima de 100 MB. Mira los detalles en la página de Blob Storage.

Blob Storage

Object storage compatible con S3, sin tarifas de salida

Más información

Preguntas frecuentes

¿Cuánto cuesta guardar 1 TB de imágenes al mes?

Solo el almacenamiento es el volumen en GB por el precio por GB-mes del proveedor. Suponiendo US$0,02 por GB-mes (valor hipotético), 1 TB (1.000 GB) sale por US$20 al mes; en un proveedor que cobrara US$5 por TB-mes, también hipotético, saldría por US$5. Las peticiones y la salida de datos se cobran aparte.

¿Es más barato guardar imágenes en la base de datos?

Casi nunca. El disco de una base de datos suele costar más por GB que un object storage, las imágenes inflan los dumps y cada lectura pasa por la base. El patrón habitual es guardar el archivo en el object storage y solo su clave en la base.

¿Qué pesa más en la factura de uploads?

Depende del uso. En una app con muchas visualizaciones, la salida de datos suele ser la línea más grande en proveedores que cobran egress. En una app que guarda originales grandes y casi no los muestra, domina el almacenamiento acumulado.

¿Debo guardar la foto original que subió el usuario?

Solo si la necesitas, por ejemplo para reprocesarla después. Una foto de celular pesa algunos MB, y la versión de visualización en WebP puede pesar unos cientos de KB. Descartar el original o moverlo a una clase más barata elimina la mayor parte del almacenamiento.

Siguiente artículoObject storage o disco de la aplicación: dónde guardar archivosEl disco de la aplicación es rápido, pero está atado a una máquina; el object storage es accesible desde cualquier lugar. Compáralos y mira cuándo usar cada uno.

Más en Storage

Ver los 15 artículos