[{"data":1,"prerenderedAt":1292},["ShallowReactive",2],{"blog-\u002Fblog\u002Falternativa-ao-vercel-self-hosted":3,"blog-surround-\u002Fblog\u002Falternativa-ao-vercel-self-hosted":1282,"blog-en-alt-\u002Fblog\u002Falternativa-ao-vercel-self-hosted":1290},{"id":4,"title":5,"author":6,"body":7,"category":1264,"cover":1265,"date":1266,"description":1267,"draft":1268,"extension":1269,"lastReviewed":1265,"meta":1270,"navigation":767,"path":1271,"readingTime":1272,"seo":1273,"sitemap":1274,"stem":1275,"tags":1276,"__hash__":1281},"blog_pt\u002Fblog\u002Falternativa-ao-vercel-self-hosted.md","Alternativa ao Vercel: hospedar Next.js sem lock-in","Equipe HeroCtl",{"type":8,"value":9,"toc":1237},"minimark",[10,14,17,22,25,60,63,66,70,75,78,81,84,87,91,94,97,109,120,139,150,154,157,160,184,187,191,194,198,201,207,213,219,222,226,229,232,243,246,249,253,256,259,266,269,272,276,279,519,522,526,529,535,541,547,553,556,560,563,567,608,611,615,631,695,702,837,840,844,847,887,890,894,897,934,938,941,948,951,955,958,989,992,996,999,1020,1023,1027,1030,1035,1055,1060,1076,1082,1085,1089,1095,1104,1118,1128,1154,1169,1175,1179,1182,1185,1188,1213,1216,1230,1233],[11,12,13],"p",{},"Vercel é o melhor produto de DX que existe pra Next.js. Build automático em cada push, preview deploys com URL única por commit, edge runtime que roda perto do usuário, ISR funcionando com uma linha de configuração, analytics e Web Vitals integrados sem instalar nada. Pra quem está começando uma aplicação Next.js sozinho, é objetivamente a melhor escolha técnica.",[11,15,16],{},"A conta começa a doer em três pontos previsíveis. Esse post mapeia esses pontos com números reais, defende o Vercel onde ele acerta, e mostra três rotas de saída — cada uma com seu trade-off. No fim, um passo a passo de migração técnica e um cálculo concreto de quanto um time brasileiro economiza ao sair.",[18,19,21],"h2",{"id":20},"onde-o-vercel-acerta","Onde o Vercel acerta",[11,23,24],{},"Vale começar pela parte difícil de admitir. Vercel resolve problemas reais que outros provedores não resolvem com a mesma elegância:",[26,27,28,36,42,48,54],"ul",{},[29,30,31,35],"li",{},[32,33,34],"strong",{},"Zero-config pra Next.js."," O time do Vercel mantém o framework. Cada release nova tem suporte testado no provedor antes de virar GA. Você não precisa configurar adapter, runtime, build cache, nada.",[29,37,38,41],{},[32,39,40],{},"Preview deploys por commit."," Cada pull request abre uma URL pública isolada com o build daquele commit. Designer revisa, PM aprova, QA testa — sem subir staging compartilhado.",[29,43,44,47],{},[32,45,46],{},"Edge functions globais."," Código roda em mais de 30 regiões simultaneamente. Pra usuário em São Paulo, a latência de cold start é menor que muito servidor dedicado em GRU.",[29,49,50,53],{},[32,51,52],{},"ISR e SSG out-of-the-box."," Página estática com revalidação programada funciona sem configurar CDN externo, sem invalidação manual.",[29,55,56,59],{},[32,57,58],{},"Analytics e Web Vitals nativos."," Sem instalar script de terceiro, sem adicionar peso no bundle, métricas reais de Core Web Vitals em produção.",[11,61,62],{},"Pra solo dev brasileiro com SaaS de US$5k MRR, com app pequeno e tráfego controlado, o Vercel custa US$20\u002Fmês e libera o desenvolvedor pra escrever produto. É a escolha certa. Não tem ironia nessa frase.",[11,64,65],{},"O problema é o que acontece depois que o produto cresce.",[18,67,69],{"id":68},"os-tres-pontos-onde-doi","Os três pontos onde dói",[71,72,74],"h3",{"id":73},"ponto-1-custo-escalonado-em-usd","Ponto 1 — Custo escalonado em USD",[11,76,77],{},"O plano Pro custa US$20 por desenvolvedor por mês como piso. Em real, com câmbio rondando R$5, isso vira aproximadamente R$100 por dev por mês. Time de cinco pessoas começa em R$500\u002Fmês só de licença, antes de qualquer tráfego ou compute.",[11,79,80],{},"A partir daí o custo é por uso. Funções serverless cobram por GB-segundo de execução mais invocação por requisição. Tráfego de saída cobra por GB. Vercel KV, Vercel Postgres, Vercel Blob — cada serviço gerenciado tem sua tabela de preços, todas em USD.",[11,82,83],{},"A consequência operacional é fatura imprevisível. Tráfego sazonal — Black Friday, lançamento de feature, citação na imprensa — multiplica por dez o custo daquele mês. Em USD, com câmbio variando 5% num mês ruim, você descobre que orçou em R$5,00 e fechou em R$5,30. A multiplicação é clara: 10x de tráfego e 6% de câmbio adicional vira fatura 10,6x maior em real.",[11,85,86],{},"Pra startup brasileira com revenue em real e custo em dólar, o spread de margem some primeiro. Pra agência que cobra cliente em real e paga infra em dólar, a margem some segundo.",[71,88,90],{"id":89},"ponto-2-lock-in-de-primitivas","Ponto 2 — Lock-in de primitivas",[11,92,93],{},"Esse é o ponto que ninguém vê até precisar sair.",[11,95,96],{},"ISR (Incremental Static Regeneration) é uma feature do Next.js, mas a implementação otimizada do Vercel usa CDN proprietária com invalidação de tag global. Self-hosted, ISR funciona localmente — cada nó tem sua cópia do cache em disco. Pra invalidar uma tag em três nós você precisa de orquestração explícita.",[11,98,99,100,104,105,108],{},"Edge runtime usa primitivas no estilo Cloudflare Workers — ",[101,102,103],"code",{},"fetch"," global, sem acesso a ",[101,106,107],{},"fs",", sem módulos Node nativos. Código escrito pra edge não roda direto em Node tradicional sem refator.",[11,110,111,112,115,116,119],{},"Image Optimization roda na infra do Vercel. Você manda ",[101,113,114],{},"\u003CImage src=\"\u002Ffoo.jpg\" \u002F>"," e o provedor entrega WebP redimensionado, com cache global. Self-hosted, você precisa rodar ",[101,117,118],{},"sharp"," na build, ou usar um proxy de imagem dedicado, ou desabilitar a feature.",[11,121,122,123,126,127,130,131,134,135,138],{},"Vercel KV, Postgres e Blob são wrappers de Upstash Redis, Neon Postgres e armazenamento S3-compatível com SDK próprio. Migrar de ",[101,124,125],{},"@vercel\u002Fkv"," pra ",[101,128,129],{},"ioredis"," direto é uma tarde de refator. Migrar de ",[101,132,133],{},"@vercel\u002Fpostgres"," pra cliente padrão é mais uma tarde. Migrar de ",[101,136,137],{},"@vercel\u002Fblob"," pra S3 envolve revisar cada upload no app.",[11,140,141,142,145,146,149],{},"Nenhuma dessas barreiras é intransponível. Mas saída do Vercel não é ",[101,143,144],{},"git remote set-url"," seguido de ",[101,147,148],{},"vercel logout",". É uma sprint de refator pra app de tamanho médio.",[71,151,153],{"id":152},"ponto-3-bandwidth-e-funcoes-fora-de-controle","Ponto 3 — Bandwidth e funções fora de controle",[11,155,156],{},"Vercel não tem cap rígido por padrão no plano Pro. Você define alertas de orçamento, mas a aplicação continua servindo até o limite ser atingido — e o limite é configurável pra cima, não pra baixo.",[11,158,159],{},"Os três cenários ruins são previsíveis:",[26,161,162,168,174],{},[29,163,164,167],{},[32,165,166],{},"DDoS leve."," Mil requisições por segundo por uma hora batem em volume de bandwidth e invocação que rotineiramente passa de US$200 num plano normal. Vercel tem proteção contra ataques massivos, mas o limiar pra ativar a defesa é alto.",[29,169,170,173],{},[32,171,172],{},"Post viral."," Sua página entra no Hacker News ou no front do Reddit, e quinhentas mil pessoas acessam num dia. O custo cai sobre você, não sobre o anunciante.",[29,175,176,179,180,183],{},[32,177,178],{},"Bug em loop."," Função em produção com ",[101,181,182],{},"setInterval"," que esqueceu de limpar, ou rota que chama a si mesma recursivamente em SSR — descoberto na fatura.",[11,185,186],{},"Você descobre o estrago quando o cartão chega. O caminho de recurso existe, mas é caso a caso e depende de boa vontade do provedor. Não é uma garantia contratual de teto.",[18,188,190],{"id":189},"as-tres-rotas-de-saida","As três rotas de saída",[11,192,193],{},"Sair do Vercel não significa pular pra Kubernetes. Há um espectro, e cada degrau troca uma coisa por outra.",[71,195,197],{"id":196},"rota-a-hospedado-mais-previsivel","Rota A — Hospedado, mais previsível",[11,199,200],{},"Render, Railway e Fly.io ocupam essa faixa. Você ainda paga por instância em USD, ainda confia no provedor pra disponibilidade, ainda tem painel web e CI\u002FCD integrado. A diferença é o modelo de cobrança.",[11,202,203,206],{},[32,204,205],{},"Render."," Preço fixo por instância por mês. Web service básico US$7\u002Fmês, instância maior US$25-85\u002Fmês. Latência decente pra São Paulo via Render-Cloud na região leste dos EUA. Tem free tier limitado pra projetos pessoais. Suporte a Next.js standalone direto, sem adapter custom.",[11,208,209,212],{},[32,210,211],{},"Railway."," Modelo por uso (CPU + memória + bandwidth) com cap configurável. Preço previsível porque você define o teto. Boa pra MVP rodando barato, escala pra cima quando precisa. UX de console é excelente.",[11,214,215,218],{},[32,216,217],{},"Fly.io."," Multi-region edge sem cobrança separada por função. Você sobe a aplicação e ela roda em N regiões com mesmo preço. Pra app que precisa de presença global mas não quer pagar tabela de função, é a escolha mais óbvia.",[11,220,221],{},"Trade-off da Rota A: você ainda paga em USD, ainda depende de provedor único pra disponibilidade, ainda tem que aceitar a tabela de preço deles quando muda. Mas saiu do modelo serverless-por-invocação e ganhou previsibilidade de custo. Pra muito time, é o suficiente.",[71,223,225],{"id":224},"rota-b-self-hosted-simples","Rota B — Self-hosted simples",[11,227,228],{},"Painéis de orquestração modernos viraram categoria nos últimos dois anos. Coolify, Dokploy, Kamal — cada um com sua filosofia, todos compartilhando o mesmo modelo: instala painel num servidor único, conecta repositório, deploya aplicação.",[11,230,231],{},"Os números mudam de regime nessa rota. Um servidor cloud na Hetzner custa em torno de €5\u002Fmês — perto de R$30. Esse servidor único hospeda confortavelmente cinco aplicações Next.js de tamanho médio, mais um banco Postgres pequeno, mais um Redis. A DX cai pra \"instala painel, conecta repo, escolhe domínio, deploya\". Não tem build cache global, não tem preview deploy automático em cada commit (depende de configuração extra), não tem edge global.",[11,233,234,235,238,239,242],{},"O detalhe técnico que viabiliza a rota é o build standalone do Next.js. Adicionando ",[101,236,237],{},"output: 'standalone'"," no ",[101,240,241],{},"next.config.js",", o build gera um servidor Node compacto com todas as dependências necessárias copiadas pra dentro. A imagem Docker resultante fica em torno de 150 MB. Cada instância da aplicação consome aproximadamente 100 MB de RAM em idle, escalando conforme tráfego. Cinco apps Next.js num servidor de 4 GB sobram memória.",[11,244,245],{},"Trade-off da Rota B: você perde edge global. Usuário em Tóquio acessando seu app em SP vai sentir latência. Você perde preview deploy automático por commit (precisa configurar manualmente, ou usar painel que suporte). Você ganha previsibilidade total de custo: a fatura do servidor é a mesma todo mês, independente de tráfego.",[11,247,248],{},"Pra time brasileiro com clientes brasileiros, a perda de edge global é, na prática, irrelevante. Latência São Paulo → São Paulo é menor que latência São Paulo → Vercel-edge-São Paulo, na maioria das medições.",[71,250,252],{"id":251},"rota-c-self-hosted-com-alta-disponibilidade","Rota C — Self-hosted com alta disponibilidade",[11,254,255],{},"Aqui mora o HeroCtl. A diferença pra Rota B é o tipo de garantia que você consegue dar pro cliente.",[11,257,258],{},"Painéis self-hosted simples são, por construção, single-server. Quando aquele servidor cai, o cliente cai junto. Pra app pessoal ou MVP, é aceitável. Pra contrato B2B com SLA escrito, não é.",[11,260,261,262,265],{},"A Rota C tira esse ponto único de falha colocando 3 ou 4 servidores num mesmo cluster, com plano de controle replicado entre eles. Se um servidor morre, os outros continuam servindo — e o cluster reagenda automaticamente os contêineres que estavam no nó morto pra outros nós saudáveis. Eleição de coordenador novo leva cerca de 7 segundos depois de um ",[101,263,264],{},"kill -9"," no servidor que estava liderando.",[11,267,268],{},"Roteador integrado emite certificados Let's Encrypt automaticamente, faz rolling deploy sem janela de manutenção, faz health check em cada contêiner. Você não monta cinco produtos pra ter ingress + TLS + métricas + logs — vem tudo no mesmo binário.",[11,270,271],{},"A faixa de aplicação é específica: quando a startup precisa de SLA escrito de cliente (geralmente acima de US$10k MRR ou em contrato B2B sério), a Rota B começa a ficar arriscada. Um único servidor, mesmo confiável, é uma narrativa difícil de defender quando o cliente pergunta \"e se aquele servidor cair?\". A Rota C resolve isso sem virar Kubernetes.",[18,273,275],{"id":274},"lado-a-lado","Lado a lado",[11,277,278],{},"A tabela é a versão honesta da decisão. Não tem coluna sem ressalva.",[280,281,282,307],"table",{},[283,284,285],"thead",{},[286,287,288,292,295,298,301,304],"tr",{},[289,290,291],"th",{},"Critério",[289,293,294],{},"Vercel",[289,296,297],{},"Render",[289,299,300],{},"Railway",[289,302,303],{},"Coolify",[289,305,306],{},"HeroCtl",[308,309,310,331,349,365,382,399,417,432,449,469,484,501],"tbody",{},[286,311,312,316,319,322,325,328],{},[313,314,315],"td",{},"Custo mínimo BRL\u002Fmês",[313,317,318],{},"~R$100\u002Fdev",[313,320,321],{},"~R$35",[313,323,324],{},"~R$25",[313,326,327],{},"~R$30 (1 VPS)",[313,329,330],{},"~R$120 (3-4 VPS)",[286,332,333,336,339,342,345,347],{},[313,334,335],{},"Custo previsível",[313,337,338],{},"Não",[313,340,341],{},"Sim",[313,343,344],{},"Sim (com cap)",[313,346,341],{},[313,348,341],{},[286,350,351,354,357,359,361,363],{},[313,352,353],{},"Edge global",[313,355,356],{},"Sim (30+ regiões)",[313,358,338],{},[313,360,338],{},[313,362,338],{},[313,364,338],{},[286,366,367,370,373,376,378,380],{},[313,368,369],{},"ISR Next.js",[313,371,372],{},"Nativo, otimizado",[313,374,375],{},"Funciona local",[313,377,375],{},[313,379,375],{},[313,381,375],{},[286,383,384,387,390,393,395,397],{},[313,385,386],{},"Image Optimization",[313,388,389],{},"Hospedado",[313,391,392],{},"Build\u002Fproxy",[313,394,392],{},[313,396,392],{},[313,398,392],{},[286,400,401,404,407,410,412,415],{},[313,402,403],{},"Preview deploys",[313,405,406],{},"Automático por commit",[313,408,409],{},"Manual\u002Fbranch",[313,411,409],{},[313,413,414],{},"Manual",[313,416,414],{},[286,418,419,422,424,426,428,430],{},[313,420,421],{},"TLS automático",[313,423,341],{},[313,425,341],{},[313,427,341],{},[313,429,341],{},[313,431,341],{},[286,433,434,437,439,442,444,446],{},[313,435,436],{},"Multi-region",[313,438,341],{},[313,440,441],{},"Limitado",[313,443,441],{},[313,445,338],{},[313,447,448],{},"Configurável",[286,450,451,454,457,460,463,466],{},[313,452,453],{},"SLA contratual",[313,455,456],{},"99,99% (Enterprise)",[313,458,459],{},"99,95%",[313,461,462],{},"99,9%",[313,464,465],{},"Best-effort",[313,467,468],{},"Configurável (você opera)",[286,470,471,474,476,478,480,482],{},[313,472,473],{},"Alta disponibilidade real",[313,475,341],{},[313,477,341],{},[313,479,341],{},[313,481,338],{},[313,483,341],{},[286,485,486,489,491,493,495,498],{},[313,487,488],{},"Suporte em PT",[313,490,338],{},[313,492,338],{},[313,494,338],{},[313,496,497],{},"Comunidade",[313,499,500],{},"Sim (Business)",[286,502,503,506,509,512,514,517],{},[313,504,505],{},"Lock-in de primitivas",[313,507,508],{},"Alto (KV\u002FPostgres\u002FBlob\u002FEdge)",[313,510,511],{},"Baixo",[313,513,511],{},[313,515,516],{},"Nenhum",[313,518,516],{},[11,520,521],{},"A coluna que importa muda conforme o estágio. Solo dev olha a primeira linha. Time crescendo olha \"custo previsível\". Startup com cliente B2B olha \"SLA contratual\" e \"alta disponibilidade real\".",[18,523,525],{"id":524},"quando-ficar-no-vercel","Quando ficar no Vercel",[11,527,528],{},"Honestidade é o mecanismo de defesa de qualquer comparativo. Quatro cenários onde sair é prejuízo:",[11,530,531,534],{},[32,532,533],{},"Solo dev fazendo SaaS pequeno em USD com revenue saudável."," Se a aplicação já cobra em dólar e o revenue passa de US$30k MRR, US$100-300\u002Fmês de Vercel é ruído contábil. O tempo gasto migrando vale mais do que a economia.",[11,536,537,540],{},[32,538,539],{},"Marketing site Next.js de baixa complexidade."," Página estática com formulário de contato. Vercel faz isso de graça no plano Hobby, e o tier gratuito não tem limite duro pra esse perfil de tráfego. Trocar pra self-hosted é mover problema em vez de resolver.",[11,542,543,546],{},[32,544,545],{},"Time pequeno sem ninguém pra cuidar de infra, com revenue justificando."," Vercel é, no fim, terceirização de operação. Se sua margem comporta o preço, e o seu único dev sênior precisa estar escrevendo produto, manter o Vercel é decisão de alocação de tempo, não de tecnologia.",[11,548,549,552],{},[32,550,551],{},"Edge global crítico pra UX."," Aplicação com usuários em três continentes onde latência abaixo de 50ms globalmente é parte do produto. Self-hosted com presença global é caro e operacionalmente complicado. Vercel resolve.",[11,554,555],{},"Se você está em qualquer um desses quatro perfis, fecha essa aba e volta pro código. O resto do post não é pra você ainda.",[18,557,559],{"id":558},"migracao-tecnica-do-vercel-pra-self-hosted","Migração técnica do Vercel pra self-hosted",[11,561,562],{},"Pra quem decidiu sair, o caminho tem sete passos. Cada um leva entre uma tarde e dois dias, dependendo do tamanho do app.",[71,564,566],{"id":565},"_1-inventario","1. Inventário",[11,568,569,570,573,574,577,578,580,581,580,583,580,585,580,588,591,592,595,596,599,600,603,604,607],{},"Antes de mover qualquer coisa, mapeia o que está em uso. Lista de variáveis de ambiente do projeto Vercel — copia tudo num arquivo ",[101,571,572],{},".env.example"," versionado. Lista de dependências Vercel-only que aparecem no ",[101,575,576],{},"package.json",": ",[101,579,125],{},", ",[101,582,133],{},[101,584,137],{},[101,586,587],{},"@vercel\u002Fanalytics",[101,589,590],{},"@vercel\u002Fspeed-insights",". Lista de features Next.js que dependem de runtime específico: ISR (busca por ",[101,593,594],{},"revalidate"," no código), middleware (existe ",[101,597,598],{},"middleware.ts"," na raiz?), edge runtime (",[101,601,602],{},"export const runtime = 'edge'","), Image Optimization (",[101,605,606],{},"\u003CImage \u002F>"," em quantas rotas?).",[11,609,610],{},"O inventário não muda nada. Mas decide a ordem dos próximos passos.",[71,612,614],{"id":613},"_2-build-standalone","2. Build standalone",[11,616,617,618,238,620,622,623,626,627,630],{},"Adiciona ",[101,619,237],{},[101,621,241],{},". Esse modo faz o build copiar pra ",[101,624,625],{},".next\u002Fstandalone\u002F"," apenas as dependências de produção realmente usadas, mais um servidor Node mínimo (",[101,628,629],{},"server.js",").",[632,633,638],"pre",{"className":634,"code":635,"language":636,"meta":637,"style":637},"language-js shiki shiki-themes github-dark-default","\u002F\u002F next.config.js\nmodule.exports = {\n  output: 'standalone',\n  \u002F\u002F demais opções\n}\n","js","",[101,639,640,649,670,683,689],{"__ignoreMap":637},[641,642,645],"span",{"class":643,"line":644},"line",1,[641,646,648],{"class":647},"sH3jZ","\u002F\u002F next.config.js\n",[641,650,652,656,660,663,667],{"class":643,"line":651},2,[641,653,655],{"class":654},"sFSAA","module",[641,657,659],{"class":658},"sZEs4",".",[641,661,662],{"class":654},"exports",[641,664,666],{"class":665},"suJrU"," =",[641,668,669],{"class":658}," {\n",[641,671,673,676,680],{"class":643,"line":672},3,[641,674,675],{"class":658},"  output: ",[641,677,679],{"class":678},"s9uIt","'standalone'",[641,681,682],{"class":658},",\n",[641,684,686],{"class":643,"line":685},4,[641,687,688],{"class":647},"  \u002F\u002F demais opções\n",[641,690,692],{"class":643,"line":691},5,[641,693,694],{"class":658},"}\n",[11,696,697,698,701],{},"Build local com ",[101,699,700],{},"next build"," produz uma pasta de uns 150 MB. Dockerfile fica curto:",[632,703,707],{"className":704,"code":705,"language":706,"meta":637,"style":637},"language-dockerfile shiki shiki-themes github-dark-default","FROM node:20-alpine AS builder\nWORKDIR \u002Fapp\nCOPY package.json pnpm-lock.yaml .\u002F\nRUN corepack enable && pnpm install --frozen-lockfile\nCOPY . .\nRUN pnpm build\n\nFROM node:20-alpine\nWORKDIR \u002Fapp\nCOPY --from=builder \u002Fapp\u002F.next\u002Fstandalone .\u002F\nCOPY --from=builder \u002Fapp\u002F.next\u002Fstatic .\u002F.next\u002Fstatic\nCOPY --from=builder \u002Fapp\u002Fpublic .\u002Fpublic\nEXPOSE 3000\nCMD [\"node\", \"server.js\"]\n","dockerfile",[101,708,709,723,731,739,747,754,762,769,777,784,792,800,808,817],{"__ignoreMap":637},[641,710,711,714,717,720],{"class":643,"line":644},[641,712,713],{"class":665},"FROM",[641,715,716],{"class":658}," node:20-alpine ",[641,718,719],{"class":665},"AS",[641,721,722],{"class":658}," builder\n",[641,724,725,728],{"class":643,"line":651},[641,726,727],{"class":665},"WORKDIR",[641,729,730],{"class":658}," \u002Fapp\n",[641,732,733,736],{"class":643,"line":672},[641,734,735],{"class":665},"COPY",[641,737,738],{"class":658}," package.json pnpm-lock.yaml .\u002F\n",[641,740,741,744],{"class":643,"line":685},[641,742,743],{"class":665},"RUN",[641,745,746],{"class":658}," corepack enable && pnpm install --frozen-lockfile\n",[641,748,749,751],{"class":643,"line":691},[641,750,735],{"class":665},[641,752,753],{"class":658}," . .\n",[641,755,757,759],{"class":643,"line":756},6,[641,758,743],{"class":665},[641,760,761],{"class":658}," pnpm build\n",[641,763,765],{"class":643,"line":764},7,[641,766,768],{"emptyLinePlaceholder":767},true,"\n",[641,770,772,774],{"class":643,"line":771},8,[641,773,713],{"class":665},[641,775,776],{"class":658}," node:20-alpine\n",[641,778,780,782],{"class":643,"line":779},9,[641,781,727],{"class":665},[641,783,730],{"class":658},[641,785,787,789],{"class":643,"line":786},10,[641,788,735],{"class":665},[641,790,791],{"class":658}," --from=builder \u002Fapp\u002F.next\u002Fstandalone .\u002F\n",[641,793,795,797],{"class":643,"line":794},11,[641,796,735],{"class":665},[641,798,799],{"class":658}," --from=builder \u002Fapp\u002F.next\u002Fstatic .\u002F.next\u002Fstatic\n",[641,801,803,805],{"class":643,"line":802},12,[641,804,735],{"class":665},[641,806,807],{"class":658}," --from=builder \u002Fapp\u002Fpublic .\u002Fpublic\n",[641,809,811,814],{"class":643,"line":810},13,[641,812,813],{"class":665},"EXPOSE",[641,815,816],{"class":658}," 3000\n",[641,818,820,823,826,829,831,834],{"class":643,"line":819},14,[641,821,822],{"class":665},"CMD",[641,824,825],{"class":658}," [",[641,827,828],{"class":678},"\"node\"",[641,830,580],{"class":658},[641,832,833],{"class":678},"\"server.js\"",[641,835,836],{"class":658},"]\n",[11,838,839],{},"Imagem final em torno de 180 MB. Roda igual em qualquer ambiente que suporte container.",[71,841,843],{"id":842},"_3-substituicao-de-armazenamento","3. Substituição de armazenamento",[11,845,846],{},"Cada serviço gerenciado do Vercel tem alternativa direta:",[26,848,849,860,875],{},[29,850,851,854,855,126,857,859],{},[32,852,853],{},"Vercel KV → Redis."," Você sobe um Redis no cluster (HeroCtl roda como job comum) ou usa Upstash hospedado. Cliente troca de ",[101,856,125],{},[101,858,129],{},". API é parecida; o adapter dá pra esconder atrás de uma função.",[29,861,862,865,866,126,868,871,872,659],{},[32,863,864],{},"Vercel Postgres → Postgres."," Postgres no cluster (job comum) ou Supabase\u002FNeon hospedados. Migration scripts continuam iguais. Cliente troca de ",[101,867,133],{},[101,869,870],{},"pg"," ou ",[101,873,874],{},"postgres.js",[29,876,877,880,881,126,883,886],{},[32,878,879],{},"Vercel Blob → S3-compatível."," Cloudflare R2 (sem cobrança de saída), Backblaze B2, ou MinIO no próprio cluster. Cliente troca de ",[101,882,137],{},[101,884,885],{},"@aws-sdk\u002Fclient-s3"," apontando pro endpoint custom.",[11,888,889],{},"A regra geral: faz a substituição num branch separado, com testes de integração rodando contra o serviço novo, antes de tocar produção.",[71,891,893],{"id":892},"_4-image-optimization","4. Image Optimization",[11,895,896],{},"Três caminhos, escolha um:",[26,898,899,910,918],{},[29,900,901,906,907,909],{},[32,902,903,905],{},[101,904,118],{}," direto no servidor."," Next.js detecta ",[101,908,118],{}," instalado e usa ele pra Image Optimization local. Funciona, mas consome CPU do mesmo processo que serve a aplicação.",[29,911,912,917],{},[32,913,914,659],{},[101,915,916],{},"next-image-export-optimizer"," Pré-otimiza todas as imagens na build. Bom pra blog ou site com imagens estáticas. Inviável pra app com upload de usuário.",[29,919,920,923,924,871,927,930,931,933],{},[32,921,922],{},"Proxy de imagem dedicado."," ",[101,925,926],{},"imgproxy",[101,928,929],{},"imageflow"," rodando como serviço separado. URL do ",[101,932,606],{}," aponta pra esse proxy. Resolve qualquer caso de uso, custa um job a mais no cluster.",[71,935,937],{"id":936},"_5-isr","5. ISR",[11,939,940],{},"Self-hosted, ISR funciona — Next.js standalone implementa o cache local em disco. O ponto frágil é invalidação multi-region.",[11,942,943,944,947],{},"Cluster com 3 nós significa 3 cópias do cache em disco, cada uma com expiração própria. Pra blog ou site cujo conteúdo muda algumas vezes por dia, isso é aceitável: a inconsistência de alguns segundos entre nós é invisível pro usuário. Pra dashboard de e-commerce com preço atualizando a cada minuto, você precisa de invalidação coordenada — geralmente via webhook que chama ",[101,945,946],{},"revalidatePath"," em todos os nós simultaneamente.",[11,949,950],{},"A maioria dos casos cai no primeiro perfil. Não vira o problema que parece à primeira vista.",[71,952,954],{"id":953},"_6-cicd","6. CI\u002FCD",[11,956,957],{},"Trocar o auto-deploy do Vercel por pipeline próprio:",[26,959,960,973,979],{},[29,961,962,965,966,580,969,972],{},[32,963,964],{},"Build:"," GitHub Actions (ou GitLab CI, ou Jenkins) roda em cada push. ",[101,967,968],{},"pnpm install",[101,970,971],{},"pnpm build",", gera imagem Docker.",[29,974,975,978],{},[32,976,977],{},"Push:"," registry de imagem (ECR, Docker Hub, GHCR). Tag por commit SHA ou data.",[29,980,981,984,985,988],{},[32,982,983],{},"Deploy:"," chamada de API contra o orquestrador (",[101,986,987],{},"heroctl deploy job.json"," ou equivalente). Rolling update sem downtime.",[11,990,991],{},"Tempo de pipeline pra app médio fica em torno de 4-6 minutos. Vercel faz em 2-3 minutos. A diferença é real, mas não é catastrófica.",[71,993,995],{"id":994},"_7-cutover","7. Cutover",[11,997,998],{},"Última etapa, e a mais delicada:",[26,1000,1001,1008,1011,1014,1017],{},[29,1002,1003,1004,1007],{},"Sobe a versão self-hosted apontando pra um domínio temporário (",[101,1005,1006],{},"new.seuapp.com",", por exemplo).",[29,1009,1010],{},"Roda em paralelo por 7 dias. Usuários internos testam. Tráfego de canário direcionado por flag.",[29,1012,1013],{},"Compara métricas: erro rate, latência p95, custo de infra projetado.",[29,1015,1016],{},"Se parity ok, troca DNS principal pra apontar pro novo backend. TTL baixo (60s) ajuda no rollback rápido.",[29,1018,1019],{},"Mantém Vercel ligado por mais 7 dias. Só desativa o projeto depois de confirmar que ninguém está no DNS antigo.",[11,1021,1022],{},"Migração total pra app médio leva 2-3 semanas com um dev dedicado. Pra app pequeno, uma semana. Pra monolito Next.js gigante com 50 rotas e middleware complexo, um trimestre.",[18,1024,1026],{"id":1025},"calculo-concreto-pra-time-brasileiro","Cálculo concreto pra time brasileiro",[11,1028,1029],{},"Numero pra fechar o argumento. Time de cinco devs brasileiros com aplicação Next.js de tamanho médio (50 rotas, banco Postgres, storage de imagens, tráfego de 2 milhões de requisições\u002Fmês).",[11,1031,1032],{},[32,1033,1034],{},"Cenário Vercel:",[26,1036,1037,1040,1043,1046,1049],{},[29,1038,1039],{},"5 × Pro (US$20\u002Fdev\u002Fmês) = US$100\u002Fmês",[29,1041,1042],{},"Bandwidth e function invocations (estimativa com tráfego informado): US$50-200\u002Fmês",[29,1044,1045],{},"Vercel Postgres (instância produção pequena): US$30\u002Fmês",[29,1047,1048],{},"Vercel Blob (50 GB armazenado, 100 GB transferência): US$20\u002Fmês",[29,1050,1051,1054],{},[32,1052,1053],{},"Total: US$200-400\u002Fmês = R$1.000 a R$2.000\u002Fmês"," ao câmbio atual.",[11,1056,1057],{},[32,1058,1059],{},"Cenário HeroCtl Community em 4 servidores Hetzner:",[26,1061,1062,1065,1068,1071],{},[29,1063,1064],{},"4 × CX22 (€5,18\u002Fmês cada) = €21\u002Fmês",[29,1066,1067],{},"Cloudflare R2 (50 GB armazenado, sem cobrança de saída): ~€5\u002Fmês",[29,1069,1070],{},"Postgres rodando como job no próprio cluster: zero adicional",[29,1072,1073,1054],{},[32,1074,1075],{},"Total: €25-30\u002Fmês = R$150-180\u002Fmês",[11,1077,1078,1081],{},[32,1079,1080],{},"Diferença: R$850 a R$1.850\u002Fmês."," Em 12 meses, R$10.000 a R$22.000 de economia. Equivalente a um mês de salário de dev pleno na faixa intermediária do mercado brasileiro.",[11,1083,1084],{},"A economia paga uma migração feita em quatro semanas no primeiro ano, e fica disponível como margem operacional nos anos seguintes. Em 36 meses, R$30k-66k de diferença. É linha de orçamento que vale aparecer na reunião financeira.",[18,1086,1088],{"id":1087},"perguntas-que-recebemos","Perguntas que recebemos",[11,1090,1091,1094],{},[32,1092,1093],{},"HeroCtl roda Next.js direto?","\nSim. Build standalone gera imagem Docker, e HeroCtl orquestra qualquer imagem. Não tem adapter custom, não tem template específico — o Dockerfile mostrado acima funciona sem modificação.",[11,1096,1097,1100,1101,1103],{},[32,1098,1099],{},"E ISR sem CDN global?","\nFunciona localmente em cada nó do cluster. Cluster com 3 nós significa 3 caches independentes com expiração própria. Pra invalidação coordenada multi-nó, você usa ",[101,1102,946],{}," chamado via webhook em todos os nós. Pra maioria dos casos (blog, site institucional, dashboard com revalidação a cada minuto), a inconsistência transitória é invisível.",[11,1105,1106,1109,1110,1113,1114,1117],{},[32,1107,1108],{},"Como faço preview deploys?","\nHeroCtl não tem preview deploy automático por commit nativo, mas suporta múltiplas versões do mesmo job rodando lado a lado. Configuração comum: pipeline cria um job com sufixo da branch (",[101,1111,1112],{},"meu-app-feature-x","), com domínio temporário (",[101,1115,1116],{},"feature-x.preview.seuapp.com","), TLS automático pelo roteador integrado. Quando a branch é mergeada e deletada, o job é despromovido. Quem quer DX exata do Vercel monta isso em 100-200 linhas de pipeline.",[11,1119,1120,1123,1124,1127],{},[32,1121,1122],{},"Edge functions sobrevivem?","\nEdge functions usam primitivas no estilo Cloudflare Workers e não rodam em Node tradicional. Self-hosted, você converte pra rotas server-side normais (",[101,1125,1126],{},"export const runtime = 'nodejs'",") ou separa em serviços próprios. Refator é por arquivo, geralmente entre 10 minutos e 2 horas dependendo do código.",[11,1129,1130,1133,1135,1136,1139,1140,1142,1143,1145,1146,1149,1150,1153],{},[32,1131,1132],{},"E se eu uso Vercel Postgres?",[101,1134,133],{}," é wrapper de Neon Postgres. Você troca pra ",[101,1137,1138],{},"@neondatabase\u002Fserverless"," (mantém Neon hospedado), ou ",[101,1141,870],{},"\u002F",[101,1144,874],{}," apontando pra um Postgres no cluster. Schema migra direto via ",[101,1147,1148],{},"pg_dump"," + ",[101,1151,1152],{},"pg_restore",". Para 95% dos apps, é uma tarde de trabalho.",[11,1155,1156,1159,1160,1162,1163,1165,1166,1168],{},[32,1157,1158],{},"Vercel Image Optimization tem substituto?","\nTrês opções: ",[101,1161,118],{}," direto no servidor (funciona, consome CPU local), ",[101,1164,916],{}," na build (bom pra imagens estáticas), proxy dedicado tipo ",[101,1167,926],{}," rodando como serviço separado (resolve qualquer caso). Pra app com upload de usuário, a terceira opção é a melhor escolha.",[11,1170,1171,1174],{},[32,1172,1173],{},"Quanto tempo leva migração pra app médio?","\nAplicação Next.js com 50 rotas, Postgres, storage e middleware: 2-3 semanas com um dev dedicado seguindo o passo a passo desse post. Aplicação pequena (10-15 rotas, sem storage gerenciado): uma semana. Monolito gigante com middleware complexo e dependência forte de edge runtime: trimestre inteiro.",[18,1176,1178],{"id":1177},"fechamento","Fechamento",[11,1180,1181],{},"Vercel é uma boa escolha. Pra muito caso, é a escolha certa. O ponto desse post não é \"Vercel é ruim\" — é \"Vercel não é a única escolha\". A maioria dos times brasileiros que olham a fatura mensal e suspiram não está olhando pra fora porque o produto deles é pior. Está olhando porque a economia em real, em escala de empresa, é grande o suficiente pra pagar uma migração feita com calma e sobrar caixa.",[11,1183,1184],{},"A escolha entre as três rotas depende de onde você está. Render e Railway resolvem o problema de previsibilidade sem mudar muito o modelo operacional. Coolify e Dokploy resolvem o custo radicalmente, em troca de um único servidor. HeroCtl resolve o custo e mantém a alta disponibilidade real, em troca de operar 3-4 servidores.",[11,1186,1187],{},"Se você quer testar a Rota C no menor caminho:",[632,1189,1193],{"className":1190,"code":1191,"language":1192,"meta":637,"style":637},"language-bash shiki shiki-themes github-dark-default","curl -sSL get.heroctl.com\u002Finstall.sh | sh\n","bash",[101,1194,1195],{"__ignoreMap":637},[641,1196,1197,1201,1204,1207,1210],{"class":643,"line":644},[641,1198,1200],{"class":1199},"sQhOw","curl",[641,1202,1203],{"class":654}," -sSL",[641,1205,1206],{"class":678}," get.heroctl.com\u002Finstall.sh",[641,1208,1209],{"class":665}," |",[641,1211,1212],{"class":1199}," sh\n",[11,1214,1215],{},"Sobe 3 servidores pequenos, instala em cada um, aponta o domínio. Sobe a aplicação Next.js como job. Verifica que o roteador integrado emitiu certificado, que o rolling deploy funcionou, que matar um servidor não derrubou o site. Depois decide se a economia compensa.",[11,1217,1218,1219,1224,1225,1229],{},"Pra ler mais: ",[1220,1221,1223],"a",{"href":1222},"\u002Fblog\u002Fpor-que-criamos-o-heroctl","Por que criamos o HeroCtl"," explica a tese geral por trás do produto, e ",[1220,1226,1228],{"href":1227},"\u002Fblog\u002Fheroku-auto-hospedado-2026","Heroku auto-hospedado em 2026"," cobre a faixa de uso adjacente — quando você quer DX tipo Heroku rodando na sua infra, sem precisar do nível de HA do HeroCtl.",[11,1231,1232],{},"A intenção, como sempre, é a mesma: orquestração de contêineres, sem cerimônia.",[1234,1235,1236],"style",{},"html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sQhOw, html code.shiki .sQhOw{--shiki-default:#FFA657}",{"title":637,"searchDepth":651,"depth":651,"links":1238},[1239,1240,1245,1250,1251,1252,1261,1262,1263],{"id":20,"depth":651,"text":21},{"id":68,"depth":651,"text":69,"children":1241},[1242,1243,1244],{"id":73,"depth":672,"text":74},{"id":89,"depth":672,"text":90},{"id":152,"depth":672,"text":153},{"id":189,"depth":651,"text":190,"children":1246},[1247,1248,1249],{"id":196,"depth":672,"text":197},{"id":224,"depth":672,"text":225},{"id":251,"depth":672,"text":252},{"id":274,"depth":651,"text":275},{"id":524,"depth":651,"text":525},{"id":558,"depth":651,"text":559,"children":1253},[1254,1255,1256,1257,1258,1259,1260],{"id":565,"depth":672,"text":566},{"id":613,"depth":672,"text":614},{"id":842,"depth":672,"text":843},{"id":892,"depth":672,"text":893},{"id":936,"depth":672,"text":937},{"id":953,"depth":672,"text":954},{"id":994,"depth":672,"text":995},{"id":1025,"depth":651,"text":1026},{"id":1087,"depth":651,"text":1088},{"id":1177,"depth":651,"text":1178},"comparativo",null,"2026-02-04","Vercel cobra em USD, escala custo serverless por requisição, e empurra você pra dentro das primitivas dele. Pra times brasileiros, a conta vira ruim rápido. Como rodar Next.js fora.",false,"md",{},"\u002Fblog\u002Falternativa-ao-vercel-self-hosted","13 min",{"title":5,"description":1267},{"loc":1271},"blog\u002Falternativa-ao-vercel-self-hosted",[1277,1278,1279,1264,1280],"vercel","next-js","self-hosted","lock-in","nuWDgcPIxRXZ_mSI9lNod2iJnR294jmSi4cnuiusYEk",[1265,1283],{"title":1284,"path":1285,"stem":1286,"description":1287,"date":1288,"category":1289,"children":-1},"Alternativa ao Kubernetes em 2026: PaaS auto-hospedado pra times brasileiros","\u002Fblog\u002Falternativa-kubernetes-paas-brasil","blog\u002Falternativa-kubernetes-paas-brasil","Times brasileiros operam com restrições diferentes: orçamento em real, hospedagem em DigitalOcean ou AWS São Paulo, LGPD em vez de GDPR. Como isso muda a escolha de orquestrador.","2025-11-25","caso-de-uso",{"path":1291},"\u002Fen\u002Fblog\u002Fself-hosted-vercel-alternative",1777362184578]