Objetivos de aprendizaje
Después de leer este artículo podrás:
- Entender qué cambia entre escribir en el sistema de archivos y enviar a un bucket
- Comparar ambos en velocidad, persistencia, escala, costo y entrega al navegador
- Migrar la subida de archivos del disco a object storage sin cambiar el resto de la app
En esta página
La primera subida de casi todo proyecto es un fs.writeFile("./uploads/..."). Funciona en tu computadora, funciona en el primer deploy y un día las fotos de los usuarios desaparecen después de una actualización, o la mitad devuelve 404 cuando agregas una segunda instancia. El problema no es el código, sino el lugar donde terminó el archivo.
Los dos lugares más comunes para guardar los archivos de una aplicación son el disco de la propia aplicación y un object storage. No hay un ganador universal: cada uno resuelve un tipo de archivo, y la mayoría de las apps maduras usa los dos.
¿Qué es el disco de la aplicación?#
Es el sistema de archivos que ve tu proceso: la carpeta del proyecto, /tmp, cualquier ruta en la que escribes con open() o fs.writeFile. Ofrece la semántica completa de archivos: abrir, leer un fragmento, escribir en medio, añadir al final, renombrar de forma atómica, bloquear. Todo ocurre en local, sin red, y por eso es rápido.
Su punto débil es que ese disco pertenece a una máquina (o a un contenedor). Dos consecuencias:
- La persistencia depende de la plataforma. La documentación de Docker es directa: los datos escritos en la capa escribible del contenedor no persisten cuando el contenedor se destruye. Los volúmenes y discos persistentes existen para resolverlo, pero cada proveedor tiene su regla sobre qué sobrevive a un reinicio, a un redeploy o a un cambio de servidor.
- No es compartido. Si ejecutas dos copias de la app, cada una tiene su propio disco. El archivo que guardó la instancia A no existe para la instancia B.
La guía The Twelve-Factor App resume la regla que siguen la mayoría de las plataformas: el sistema de archivos del proceso sirve como caché breve, de una sola transacción, y cualquier dato que deba persistir va a un servicio externo con estado.
¿Qué es object storage?#
El object storage guarda archivos como objetos dentro de buckets, cada uno identificado por una clave como uploads/2026/foto.webp. Hablas con él mediante una API HTTP, en general compatible con S3: subes el archivo entero con PUT, lo lees con GET y lo borras con DELETE.
Cambia la semántica de archivo por otras ventajas. En Amazon S3, las escrituras y los borrados tienen consistencia fuerte de lectura después de escritura: en cuanto el PUT responde con éxito, cualquier lector en cualquier servidor ve el archivo nuevo. La capacidad crece sin redimensionar ningún disco, y el archivo recibe una URL que el navegador puede descargar directo, con caché de CDN, o mediante una URL firmada cuando es privado.
El precio: no hay edición parcial. En el S3 estándar, cambiar un byte significa subir el objeto entero otra vez. El append existe solo en una clase específica (S3 Express One Zone, en directory buckets). Cada operación también es una petición de red, con mucha más latencia que un disco local; AWS vende una clase aparte solo para bajar la latencia a un dígito de milisegundos.
¿Cuál es la diferencia lado a lado?#
| Criterio | Disco de la aplicación | Object storage |
|---|---|---|
| Acceso | Sistema de archivos (open, fs) |
API HTTP (PUT, GET, DELETE) |
| Latencia por operación | Muy baja, local | Un viaje de ida y vuelta por la red |
| Editar un fragmento o añadir | Sí | No (objeto entero), salvo clases específicas |
| Compartido entre instancias | No | Sí |
| Sobrevive al cambio de contenedor o servidor | Depende de la plataforma | Sí, es independiente de la app |
| Capacidad | Limitada al disco de la máquina | Crece con el uso |
| Servir al navegador | Pasa por tu app | URL directa, CDN, enlace firmado |
| Costo típico | Incluido en el servidor | Por GB almacenado, a veces por petición y por salida |
| Bueno para | Temporales, cachés, base local, sesiones | Subidas, multimedia, exportaciones, copias de seguridad |
La fila del costo cambia mucho entre proveedores. Muchos cobran también el tráfico de salida, que pesa cuando sirves multimedia; mira qué son las tarifas de egress.
¿Cuándo el disco de la aplicación es la opción correcta?#
- Archivos temporales. Redimensionar una imagen, descomprimir un ZIP, generar un PDF antes de enviarlo. Usa el directorio temporal del sistema y borra al terminar.
- Cachés que se pueden rehacer. Si el archivo desaparece, la app lo recrea. Perder la caché cuesta tiempo, no datos.
- Bases embebidas y archivos de estado de un solo proceso. SQLite, la carpeta de sesión de un bot de WhatsApp, índices locales. Necesitan escribir en medio del archivo y baja latencia, cosas que el object storage no ofrece. Aquí el disco tiene que ser persistente, y conviene enviar copias periódicas a otro lugar.
- Configuración y código. Lo que llega con el deploy vive en el disco por definición.
¿Cuándo object storage es la opción correcta?#
- Subidas de usuarios. Avatares, adjuntos, documentos. Son datos del usuario, no del servidor, y deben sobrevivir a cualquier deploy. Para el patrón completo de "archivo en el storage, clave en la base de datos", mira imágenes en la base de datos o en object storage.
- Archivos servidos al público. Imágenes de producto, videos, descargas. Si salen directo del storage o de la CDN, no ocupan el ancho de banda ni la memoria de tu app.
- Más de una instancia. En cuanto pones un balanceador de carga delante de dos copias de la app, el disco local deja de ser una opción para archivos compartidos.
- Archivos grandes o volumen que crece. Gigabytes de multimedia no encajan bien en un disco que tienes que redimensionar a mano.
- Copias de seguridad. Una copia guardada en el mismo disco que debe proteger no protege nada.
Para ver dónde entra el block storage (el tipo de disco detrás de un volumen), lee object, block y file storage.
¿Cómo migrar las subidas del disco a object storage?#
El cambio suele ser pequeño: donde había una escritura en disco, entra un PUT al bucket, y la base de datos pasa a guardar la clave en lugar de la ruta local. Ejemplo en Node.js con el AWS SDK v3, que funciona con cualquier storage compatible con S3:
// npm install @aws-sdk/client-s3
import { randomUUID } from "node:crypto";
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
const s3 = new S3Client({
region: process.env.S3_REGION ?? "us-east-1",
endpoint: process.env.S3_ENDPOINT, // omítelo en AWS; defínelo en un storage compatible
forcePathStyle: process.env.S3_PATH_STYLE === "true", // algunos storages compatibles lo exigen
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY,
secretAccessKey: process.env.S3_SECRET_KEY,
},
});
// Antes: await writeFile(`./uploads/${nombre}`, datos)
export async function guardarSubida(datos, contentType) {
const key = `uploads/${randomUUID()}`;
await s3.send(
new PutObjectCommand({
Bucket: process.env.S3_BUCKET,
Key: key,
Body: datos,
ContentType: contentType,
}),
);
return key; // guarda la clave en la base de datos, no una ruta del disco
}Tres cuidados en la migración:
- Mueve los archivos antiguos. Un
aws s3 sync ./uploads s3://tu-bucket/uploads --endpoint-url "$S3_ENDPOINT"copia lo que ya existe. Después, actualiza en la base de datos las rutas antiguas a las nuevas claves. - Deja el disco como borrador. Si procesas el archivo antes de guardarlo (miniatura, conversión), hazlo en el directorio temporal y sube solo el resultado.
- Decide la visibilidad. Los archivos públicos reciben una URL directa; los privados se abren con un enlace firmado. Mira archivos públicos o privados.
Cómo hacerlo en Square Cloud#
En Square Cloud existen los dos lugares. El disco de la aplicación persiste entre reinicios y deploys: un nuevo commit (ZIP o push) sobrescribe solo los archivos que trae, y el resto se queda. Por eso la carpeta de autenticación de un bot de WhatsApp sigue conectada después de un reinicio. También puedes abrir y editar esos archivos desde el navegador, sin redeploy. Eso sí, cada aplicación tiene su propio disco. Si usas load balancing para servir un dominio con varias aplicaciones, no comparten archivos, así que las subidas compartidas deben ir al object storage.
El Blob Storage es el object storage de la plataforma, con API compatible con S3: el código de arriba funciona apuntando S3_ENDPOINT a https://s3-blob.squarecloud.app (región auto), y aws-cli y rclone sirven para la migración. Los archivos pueden tener hasta 10 GB, y la subida multipart solo es obligatoria por encima de 100 MB. Los archivos públicos se sirven desde una CDN global en el edge, y los privados se abren con un enlace temporal de hasta 24 horas o con un enlace para compartir revocable de hasta 30 días.
No hay tarifa de salida ni de entrada, y todos los planes incluyen una cuota de 5 GB a 250 GB. Las reglas por carpeta definen visibilidad, caducidad y limpieza automática, lo que ayuda a mantener bajo control la carpeta de temporales.
Mira los detalles y las cuotas en la página del Blob Storage.
Blob Storage
Object storage compatible con S3, sin tarifas de salida
Preguntas frecuentes
¿Los archivos guardados en el disco del contenedor desaparecen?
Depende de cómo trate la plataforma al contenedor. La documentación de Docker dice que los datos escritos en la capa del contenedor no persisten cuando el contenedor se destruye. Los volúmenes y discos persistentes cambian eso, así que revisa la regla de tu proveedor.
¿Puedo usar object storage como si fuera una carpeta?
Solo en parte. Lees y escribes archivos enteros por HTTP, con una clave parecida a una ruta. En el S3 estándar no hay edición de un fragmento en medio del archivo ni append: para cambiar un objeto, subes una versión nueva completa.
¿Puedo ejecutar una base SQLite en object storage?
No directamente. SQLite lee y escribe páginas pequeñas en medio del archivo, lo que exige un sistema de archivos de verdad. Deja el archivo de la base en el disco y envía copias periódicas al object storage.
¿El object storage es más lento que el disco?
Por operación, sí: cada lectura es una petición HTTP por la red. Para servir archivos a muchos usuarios suele ganar, porque el navegador descarga directo de él y puede estar detrás de una CDN sin pasar por tu app.
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.