Objetivos de aprendizado
Depois de ler este artigo, você vai conseguir:
- Entender o que muda entre gravar no sistema de arquivos e enviar para um bucket
- Comparar os dois em velocidade, persistência, escala, custo e entrega ao navegador
- Migrar o upload de arquivos do disco para object storage sem mudar o resto do app
O primeiro upload de quase todo projeto é um fs.writeFile("./uploads/..."). Funciona no seu computador, funciona no primeiro deploy, e um dia as fotos dos usuários somem depois de uma atualização, ou metade delas dá 404 quando você sobe uma segunda instância. O problema não é o código: é o lugar onde o arquivo foi parar.
Os dois lugares mais comuns para guardar os arquivos de uma aplicação são o disco da própria aplicação e um object storage. Não há vencedor universal: cada um resolve um tipo de arquivo, e a maioria dos apps maduros usa os dois.
O que é o disco da aplicação?#
É o sistema de arquivos que o seu processo enxerga: a pasta do projeto, o /tmp, qualquer caminho em que você grava com open() ou fs.writeFile. Ele oferece a semântica completa de arquivos: abrir, ler um trecho, gravar no meio, acrescentar no fim, renomear de forma atômica, travar. Tudo isso acontece localmente, sem rede, e por isso é rápido.
O ponto fraco é que esse disco pertence a uma máquina (ou a um container). Duas consequências:
- Persistência depende da plataforma. A documentação do Docker é direta: dados gravados na camada gravável do container não persistem quando o container é destruído. Volumes e discos persistentes existem para resolver isso, mas cada provedor tem sua regra sobre o que sobrevive a um restart, a um redeploy ou à troca de servidor.
- Não é compartilhado. Se você roda duas cópias do app, cada uma tem o próprio disco. O arquivo que a instância A gravou não existe para a instância B.
O guia The Twelve-Factor App resume a regra que a maioria das plataformas segue: o sistema de arquivos do processo serve como cache breve, de uma única transação, e qualquer dado que precise persistir vai para um serviço externo com estado.
O que é object storage?#
Object storage guarda arquivos como objetos dentro de buckets, cada um identificado por uma chave como uploads/2026/foto.webp. Você fala com ele por uma API HTTP, em geral compatível com S3: envia o arquivo inteiro com PUT, lê com GET, apaga com DELETE.
Ele troca a semântica de arquivo por outras vantagens. No Amazon S3, gravações e exclusões têm consistência forte de leitura após escrita: assim que o PUT responde com sucesso, qualquer leitor em qualquer servidor vê o arquivo novo. A capacidade cresce sem você redimensionar disco, e o arquivo ganha uma URL que o navegador pode baixar direto, com cache de CDN, ou por uma URL assinada quando é privado.
O preço disso: não há edição parcial. No S3 padrão, para mudar um byte você envia o objeto inteiro de novo. O append existe só numa classe específica (S3 Express One Zone, em directory buckets). Cada operação também é uma requisição de rede, com latência bem maior que a de um disco local; a AWS vende uma classe à parte justamente para baixar a latência a um dígito de milissegundo.
Qual a diferença lado a lado?#
| Critério | Disco da aplicação | Object storage |
|---|---|---|
| Acesso | Sistema de arquivos (open, fs) |
API HTTP (PUT, GET, DELETE) |
| Latência por operação | Muito baixa, local | Uma ida e volta pela rede |
| Editar um trecho ou acrescentar | Sim | Não (objeto inteiro), salvo classes específicas |
| Compartilhado entre instâncias | Não | Sim |
| Sobrevive à troca de container ou servidor | Depende da plataforma | Sim, independe do app |
| Capacidade | Limitada ao disco da máquina | Cresce conforme o uso |
| Servir ao navegador | Passa pelo seu app | URL direta, CDN, link assinado |
| Custo típico | Incluso no servidor | Por GB armazenado, às vezes por requisição e por saída |
| Bom para | Temporários, caches, banco local, sessões | Uploads, mídia, exports, cópias de segurança |
O custo da última linha muda bastante entre provedores. Muitos cobram também pelo tráfego de saída, o que pesa quando você serve mídia; veja o que são taxas de egress.
Quando o disco da aplicação é a escolha certa?#
- Arquivos temporários. Redimensionar uma imagem, descompactar um ZIP, gerar um PDF antes de enviar. Use o diretório temporário do sistema e apague no fim.
- Caches que podem ser refeitos. Se o arquivo sumir, o app recria. Perder o cache custa tempo, não dados.
- Bancos embutidos e arquivos de estado de um único processo. SQLite, a pasta de sessão de um bot de WhatsApp, índices locais. Precisam de escrita no meio do arquivo e de baixa latência, coisas que object storage não oferece. Aqui o disco precisa ser persistente, e vale mandar cópias periódicas para fora.
- Configuração e código. O que vem no deploy fica no disco por definição.
Quando object storage é a escolha certa?#
- Uploads de usuários. Avatares, anexos, documentos. São dados do usuário, não do servidor, e precisam sobreviver a qualquer deploy. Para o padrão completo de "arquivo no storage, chave no banco", veja imagens no banco ou em object storage.
- Arquivos servidos ao público. Imagens de produto, vídeos, downloads. Saindo direto do storage ou da CDN, eles não ocupam a banda nem a memória do seu app.
- Mais de uma instância. Assim que você coloca um load balancer na frente de duas cópias do app, o disco local deixa de ser uma opção para arquivos compartilhados.
- Arquivos grandes ou volume que cresce. Gigabytes de mídia não cabem bem num disco que você precisa redimensionar à mão.
- Cópias de segurança. Uma cópia guardada no mesmo disco que ela protege não protege nada.
Para entender onde o block storage (o tipo de disco que fica por trás de um volume) entra nessa conta, leia object, block e file storage.
Como migrar os uploads do disco para object storage?#
A troca costuma ser pequena: onde havia uma gravação em disco, entra um PUT no bucket, e o banco passa a guardar a chave em vez do caminho local. Exemplo em Node.js com o AWS SDK v3, que funciona com qualquer storage compatível com 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, // omita na AWS; defina num storage compatível
forcePathStyle: process.env.S3_PATH_STYLE === "true", // alguns storages compatíveis exigem
credentials: {
accessKeyId: process.env.S3_ACCESS_KEY,
secretAccessKey: process.env.S3_SECRET_KEY,
},
});
// Antes: await writeFile(`./uploads/${nome}`, dados)
export async function salvarUpload(dados, contentType) {
const key = `uploads/${randomUUID()}`;
await s3.send(
new PutObjectCommand({
Bucket: process.env.S3_BUCKET,
Key: key,
Body: dados,
ContentType: contentType,
}),
);
return key; // guarde a chave no banco, não um caminho do disco
}Três cuidados na migração:
- Mova os arquivos antigos. Um
aws s3 sync ./uploads s3://seu-bucket/uploads --endpoint-url "$S3_ENDPOINT"copia o que já existe. Depois, atualize no banco os caminhos antigos para as novas chaves. - Mantenha o disco como rascunho. Se você processa o arquivo antes de guardar (miniatura, conversão), faça isso no diretório temporário e envie só o resultado.
- Decida a visibilidade. Arquivos públicos ganham URL direta; privados abrem por link assinado. Veja arquivos públicos ou privados.
Como fazer isso na Square Cloud#
Na Square Cloud, os dois lugares existem. O disco da aplicação é persistente entre restarts e deploys: um novo commit (ZIP ou push) sobrescreve só os arquivos que vêm nele, e o resto fica. É por isso que a pasta de autenticação de um bot de WhatsApp continua conectada depois de um restart. Você também abre e edita esses arquivos pelo navegador, sem redeploy. Só que cada aplicação tem o próprio disco. Se você usa load balancing para servir um domínio com várias aplicações, elas não compartilham arquivos, então os uploads compartilhados devem ir para o object storage.
O Blob Storage é o object storage da plataforma, com API compatível com S3: o código acima funciona apontando S3_ENDPOINT para https://s3-blob.squarecloud.app (região auto), e o aws-cli e o rclone servem para a migração. Arquivos têm até 10 GB, e o multipart só é obrigatório acima de 100 MB. Arquivos públicos saem por uma CDN global na edge, e os privados abrem por link temporário de até 24 horas ou por link de compartilhamento revogável de até 30 dias.
Não há taxa de saída nem de entrada, e todo plano inclui uma cota de 5 GB a 250 GB. Regras por pasta definem visibilidade, expiração e limpeza automática, o que ajuda a manter a pasta de temporários sob controle.
Veja os detalhes e as cotas na página do Blob Storage.
Blob Storage
Object storage compatível com S3, sem taxa de saída
Perguntas frequentes
Arquivos salvos no disco do container somem?
Depende de como a plataforma trata o container. A documentação do Docker diz que dados gravados na camada do container não persistem quando o container é destruído. Volumes e discos persistentes mudam isso, então confira a regra do seu provedor.
Posso usar object storage como se fosse uma pasta?
Só em parte. Você lê e grava arquivos inteiros por HTTP, com uma chave parecida com um caminho. Não há edição de um trecho no meio do arquivo nem append no S3 padrão: para mudar um objeto, você envia uma versão nova inteira.
Dá para rodar um banco SQLite em object storage?
Não diretamente. O SQLite precisa ler e gravar páginas pequenas no meio do arquivo, o que exige um sistema de arquivos de verdade. Mantenha o arquivo do banco no disco e envie cópias periódicas para o object storage.
Object storage é mais lento que o disco?
Para cada operação, sim: cada leitura é uma requisição HTTP pela rede. Para servir arquivos a muitos usuários, ele costuma ganhar, porque entrega direto ao navegador e pode ficar atrás de uma CDN sem passar pelo seu app.
Mais em Storage
Ver todos os 15 artigos- O que é uma URL assinada (pre-signed URL) e quando usarUma URL assinada (pre-signed URL) é um link temporário para um arquivo privado. Veja como funciona, o que ela não faz e quando usar.
- O que é armazenamento de objetos (object storage)Armazenamento de objetos guarda arquivos como objetos com chave e metadados, acessados por API HTTP. Veja como funciona, para que serve e seus limites.
- O que é S3 e armazenamento compatível com S3S3 é o armazenamento de objetos da Amazon e virou a API padrão do setor. Veja o que significa ser compatível com S3, o que muda e como conectar via boto3.
- Upload de arquivos grandes: multipart e upload retomávelO upload multipart divide um arquivo grande em partes enviadas em paralelo e reenviadas uma a uma. Veja o passo a passo em Python, como retomar e os erros comuns.