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.
¿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 × NLo 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:
// 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:
- El original es el mayor costo de almacenamiento. Ocupa casi el 90% del espacio en el ejemplo y no se muestra a nadie.
- La salida sigue a las visualizaciones, no al volumen guardado. En una app popular supera con facilidad al almacenamiento, en proveedores que cobran egress.
- 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
AbortIncompleteMultipartUploadpara 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:
- 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.
- 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.
- 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.
- Pon caché delante de los archivos públicos, con un
Cache-Controllargo en archivos que no cambian, para que la salida del storage ocurra una vez por archivo y no una vez por visita. - 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.
- 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
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.
Más en Storage
Ver los 15 artículos- Qué es una URL prefirmada (presigned URL)Una URL prefirmada (presigned URL) es un enlace temporal a un archivo privado que funciona sin login. Mira cómo funciona, sus límites y cuándo usarla.
- Qué es el almacenamiento de objetosEl almacenamiento de objetos guarda archivos como objetos con clave y metadatos, accesibles por una API HTTP. Mira cómo funciona, para qué sirve y sus límites.
- Qué es S3 y qué significa 'compatible con S3'S3 es el almacenamiento de objetos de Amazon y su API se volvió el estándar del sector. Aprende qué significa ser compatible con S3 y cómo conectarte.
- Subir archivos grandes: carga multiparte y reanudableLa carga multiparte divide un archivo grande en partes que se envían en paralelo y se reintentan por separado. Mira el paso a paso en Python y cómo reanudar.