Migrar do Railway para a Upuai: do railway.json ao upuai.toml
Guia para levar um app do Railway para a Upuai: o que cada chave do railway.json vira no upuai.toml, variáveis, banco Postgres, domínio e a conta em reais.

Se o seu app roda no Railway com um railway.json na raiz, migrar do Railway para a Upuai é, na maior parte, um trabalho de tradução: cada chave do arquivo vira uma chave do upuai.toml, uma tela do painel ou um aviso honesto de que a função não existe aqui. Este guia faz a tradução chave por chave e depois cuida do que fica em volta: variáveis, banco Postgres, domínio e a conta em reais. A tabela “Chaves sem equivalente” lista o que não existe aqui, e “Quando vale ficar no Railway” diz quando ficar é a decisão certa.
Há um motivo extra para revisar essa configuração agora. Na doc de Config as Code, consultada em 07/10/2026, o Railway marcou o formato como legado (“Config as Code is deprecated. Prefer Infrastructure as Code”), com os arquivos existentes funcionando para serviços antigos até 01/12/2026. Quem ainda depende do railway.json ou do railway.toml vai ter que mexer nele de qualquer jeito; é a hora de decidir onde ele vai morar.
Se você ainda está comparando opções, comece por Alternativa ao Railway no Brasil e pelo comparativo Vercel, Railway, Heroku ou Upuai.
Antes de migrar: o que o seu projeto usa no Railway
Faça um inventário antes de tocar em qualquer arquivo. Para cada serviço, anote:
- Comandos: o que é web, o que é worker, e o build e o start de cada um.
- Bancos: a versão maior do Postgres (15, 16, 17 ou 18) e as extensões ativas (
SELECT extname FROM pg_extension;). - Volumes: o caminho montado (
requiredMountPath) e o tamanho ocupado. - Variáveis: as que usam referência, como
${{Postgres.DATABASE_URL}}ou${{ shared.API_KEY }}, e as fornecidas pela plataforma, comoRAILWAY_PUBLIC_DOMAIN. - Domínios e DNS, serviços com
cronSchedule, enumReplicas,regionemultiRegionConfig, se existirem.
O inventário decide quantos serviços o projeto precisa na Upuai (banco conta como serviço) e se algo cai na categoria sem equivalente.
Do railway.json ao upuai.toml, chave por chave
Os dois arquivos declaram build e deploy dentro do repositório. O upuai.toml fica em <rootDirectory>/upuai.toml, e o rootDirectory é o diretório de trabalho dos comandos. Precedência: o que você editar na UI vence o toml, que vence o Procfile. A doc está em /docs/upuai-toml; as chaves abaixo foram conferidas no schema público do Railway e no upuai-toml-v1.json em 07/10/2026.
Um railway.json típico:
{
"$schema": "https://railway.com/railway.schema.json",
"build": {
"builder": "RAILPACK",
"buildCommand": "pnpm build"
},
"deploy": {
"startCommand": "node dist/server.js",
"preDeployCommand": "pnpm prisma migrate deploy",
"preDeployTimeoutSeconds": 300,
"healthcheckPath": "/health",
"healthcheckTimeout": 120,
"numReplicas": 1,
"sleepApplication": true
}
}
O mesmo serviço em upuai.toml:
#:schema https://upuai.com.br/schemas/upuai-toml-v1.json
[build]
builder = "railpack"
buildCommand = "pnpm build"
[deploy]
startCommand = "node dist/server.js"
releaseCommand = "pnpm prisma migrate deploy"
releaseTimeoutSeconds = 300
healthCheckPath = "/health"
healthCheckTimeout = 120
O sleepApplication sumiu de propósito; a tabela “Chaves sem equivalente” explica.
Chaves com equivalente direto
railway.json | upuai.toml | Observação |
|---|---|---|
build.builder (RAILPACK, DOCKERFILE, NIXPACKS) | build.builder (railpack, dockerfile) | Mesmos builders, em minúsculas. NIXPACKS vira railpack; se o build dependia de nixpacksPlan ou nixpacksConfigPath, vire Dockerfile (ver a tabela “Chaves sem equivalente”). |
build.buildCommand | build.buildCommand | Mesmo nome. |
build.dockerfilePath | build.dockerfilePath | Relativo ao rootDirectory. |
deploy.startCommand | deploy.startCommand | Com vários processos, use [processes.<nome>]. |
deploy.preDeployCommand | deploy.releaseCommand | Roda antes do rollout, na mesma imagem e variáveis; se falhar, o tráfego não troca. |
deploy.preDeployTimeoutSeconds | deploy.releaseTimeoutSeconds | 10 a 1800 segundos; padrão 300. |
deploy.healthcheckPath | deploy.healthCheckPath | C maiúsculo. Sem a chave, o padrão vem do framework detectado. |
deploy.healthcheckTimeout | deploy.healthCheckTimeout | 0 a 600 segundos. |
deploy.numReplicas | processes.<nome>.instances | O schema aceita 1 a 50; o plano limita: 1 no teste, 5 no Starter, 8 no Plus, 10 no Pro, 25 no Business. |
Com web e worker no mesmo serviço:
[processes.web]
command = "node dist/server.js"
[processes.worker]
command = "node dist/worker.js"
instances = 2
Chaves que viram tela ou comando
railway.json | Na Upuai | Observação |
|---|---|---|
deploy.cronSchedule | Aba Agendador do serviço | Sem chave no toml v1. |
deploy.requiredMountPath | Aba Volume ou upuai volume add --path /data --size 5 | Disco ReadWriteOnce: o serviço roda com uma única réplica. |
deploy.limitOverride | Botão Ajustar Recursos | Dentro do envelope do plano. |
Chaves sem equivalente
railway.json | Por que não existe | O que fazer |
|---|---|---|
deploy.sleepApplication | Todo serviço roda com no mínimo 1 instância. | Conte o serviço o mês inteiro; se ele vive dormindo, veja “Quando vale ficar no Railway”. |
deploy.region, deploy.multiRegionConfig | Um datacenter, em Belo Horizonte. | Precisa de várias regiões? Fique no Railway. |
deploy.restartPolicyType, restartPolicyMaxRetries | Sem chave no toml v1; o roadmap da doc lista restartPolicy. | Nada a configurar hoje. |
deploy.overlapSeconds, drainingSeconds | Sem chave no toml v1. | O health check decide quando a versão nova recebe tráfego. |
build.watchPatterns | O auto-deploy segue o rootDirectory. | Ver a regra abaixo. |
environments | O toml v1 é por serviço, não por ambiente. | Variáveis ou UI do serviço. |
nixpacks*, railpackVersion, runtime, registryCredentials, ipv6EgressEnabled | Sem chave no toml v1. | Plano Nixpacks customizado vira Dockerfile. |
A regra de auto-deploy, no lugar do watchPatterns: um push deploya o serviço quando toca o rootDirectory dele ou um caminho que não pertence ao rootDirectory de nenhum outro serviço. Mexer em apps/api deploya só a API; mexer no lockfile, numa config da raiz ou em packages/* deploya todo mundo.
Variáveis de ambiente e referências entre serviços
As variáveis entram pela tela do serviço, com Importar .env (cole o export do Railway) ou pelo Editor raw, e pelo CLI com upuai variables set KEY=VALUE. Três ajustes:
- Referências. No Railway,
${{Postgres.DATABASE_URL}}aponta para outro serviço,${{ shared.API_KEY }}para uma variável compartilhada e${{ PORT }}para o próprio. A Upuai usa a mesma sintaxe${{...}}, mas o alvo precisa existir aqui: troquePostgrespelo nome do seu banco na Upuai. Se a referência não resolve, o editor avisa “Referência vai literal pro container” antes de aplicar; é o erro que só apareceria no primeiro request em produção. RAILWAY_*.RAILWAY_PUBLIC_DOMAIN,RAILWAY_PRIVATE_DOMAINeRAILWAY_TCP_PROXY_PORTnão existem aqui. Umgrep -r RAILWAY_ .mostra onde trocar pelo endereço do serviço na Upuai.- Segredos vão de painel a painel, sem commit. O toml v1 não tem bloco de variáveis.
O banco Postgres: dump no Railway, restore na Upuai
A ordem abaixo evita os dois erros mais comuns: versão diferente e extensão faltando.
- Crie o banco na Upuai com a mesma versão maior do Railway (15, 16, 17 ou 18, escolhida na criação). Versão igual tira a dúvida.
- Ative as extensões antes do restore:
upuai db extensions enable postgis(oupgvector, ou a que o inventário apontou), pelo painel ou pelo CLI, sem reiniciar. Restore que encontraCREATE EXTENSIONsem a extensão para no meio. - Gere o dump no Railway:
pg_dump -Fc "$DATABASE_URL" -f app.dump. - Libere o acesso público do banco só para o seu IP:
upuai db public enable --allow 203.0.113.10/32. - Restaure:
upuai db restore -f app.dump. É umpg_restorecom--clean --if-exists --no-owner --no-acl, e pede confirmação antes de sobrescrever. - Confira e feche:
upuai db connect, contagem das tabelas principais, uma query real do app. Depois,upuai db public disable.
Esse é o ensaio. Na virada, você repete do passo 3 ao 6 com a escrita pausada (ver “Domínio e a virada sem susto”). Para backup, retenção por plano e redimensionamento, leia PostgreSQL gerenciado no Brasil e /docs/postgres.
Domínio e a virada sem susto
- Teste no endereço da Upuai primeiro. Rode o app nele com o banco do ensaio, bata nas rotas que importam e leia os logs. Nada de DNS ainda.
- Baixe o TTL do registro DNS para 300 segundos (ou o mínimo do provedor) um dia antes. A troca propaga em minutos, e a volta também.
- Adicione o domínio:
upuai domain add app.exemplo.com.brmostra os registros DNS a criar e verifica sozinho quando eles propagam. - Dump final com a escrita pausada. Coloque o app do Railway em somente leitura ou manutenção, rode o dump e o restore finais, confira, e só então troque o DNS.
- Mantenha o Railway no ar por alguns dias. Se algo aparecer, a volta é trocar o registro de novo.
A conta em reais: uso por segundo em dólar contra plano fixo em real
O Railway cobra o uso por segundo, em dólar, com um mínimo mensal por plano. A Upuai cobra um plano fixo em real, que limita o que você reserva no workspace. Nenhum é mais barato em abstrato; por isso o cenário é declarado.
Preços do Railway (página de preços ao vivo, consultada em 07/10/2026):
- Free: US$ 0 por mês, com 30 dias de teste e US$ 5 em créditos; depois, US$ 1 de uso incluído por mês, sem cobrança. Até 1 vCPU e 0,5 GB por serviço, 0,5 GB de volume.
- Hobby: mínimo de US$ 5 de uso, que já inclui US$ 5 de crédito. Até 48 vCPU e 48 GB por serviço, volume de até 5 GB, workspace de uma pessoa (membros só no Pro), 7 dias de logs.
- Pro: mínimo de US$ 20, com US$ 20 de crédito e assentos ilimitados.
- Tarifas: memória US$ 0,00000386 por GB por segundo; CPU US$ 0,00000772 por vCPU por segundo; volume US$ 0,00000006 por GB por segundo; saída US$ 0,05 por GB.
Preços da Upuai (página de preços ao vivo e código do produto, 07/10/2026):
- Teste: 15 dias, sem cartão. 2 vCPU, 2 GB, 4 GB, 1 projeto com 2 serviços de 1 instância, 1 ambiente.
- Starter: R$ 19 por mês (R$ 190 por ano). 4 vCPU, 4 GB, 10 GB, 2 projetos, 3 serviços por projeto, 1 ambiente, 5 domínios, logs de 24 horas.
- Plus: R$ 49 por mês. 8 vCPU, 8 GB, 25 GB, 3 projetos, 1 ambiente.
- Pro: R$ 99 por mês. 16 vCPU, 16 GB, 50 GB, 5 projetos, 2 ambientes (staging).
- Business: R$ 199 por mês. 24 vCPU, 24 GB, 100 GB, 10 projetos, 3 ambientes, equipe colaborativa.
O cenário: média de 0,35 vCPU e 0,75 GB de RAM somando app e banco, 1 GB de volume e 5 GB de saída, 30 dias (2.592.000 segundos) no Hobby.
| Item | Conta | Valor |
|---|---|---|
| CPU | 0,35 × 0,00000772 × 2.592.000 | US$ 7,00 |
| Memória | 0,75 × 0,00000386 × 2.592.000 | US$ 7,50 |
| Volume | 1 × 0,00000006 × 2.592.000 | US$ 0,16 |
| Saída | 5 × 0,05 | US$ 0,25 |
| Total no Hobby | os US$ 5 de crédito do mínimo já estão consumidos | US$ 14,91 |
Em reais, com a PTAX de venda do Banco Central de 06/10/2026 (último dia útil disponível na manhã de 07/10), R$ 4,9698: R$ 74,10 e, com 3,5% de IOF, R$ 76,69. Com a PTAX de 02/10/2026 (R$ 5,2238): R$ 77,89 e R$ 80,61 com IOF. Os 3,5% são a alíquota do Decreto nº 12.499/2025 para compras internacionais no cartão; o 6,38% que ainda circula é a antiga. O spread do emissor não está na conta, e o número muda a cada fatura, porque o câmbio muda.
Do outro lado, o Starter custa R$ 19 fixos. O envelope é do workspace inteiro, somando app e banco: um serviço novo nasce com 1 vCPU e 1 GB no Starter (0,5 vCPU e 512 MB no teste), e um banco gerenciado nasce igual, então app mais Postgres do cenário cabem em 4 vCPU e 4 GB. A assinatura é no cartão de crédito, com nota fiscal (NFS-e) automática a cada cobrança. O detalhe de cada plano está na página de preços.
Quando vale ficar no Railway
- O app cabe no Free do Railway. Se 1 vCPU e 0,5 GB por serviço bastam e o uso fica dentro do US$ 1 por mês, nenhum plano fixo compete com isso.
- Você precisa de multirregião ou de dormir sem tráfego.
region,multiRegionConfigesleepApplicationnão têm equivalente na Upuai. - Você precisa de staging abaixo de R$ 99. Teste, Starter e Plus têm 1 ambiente; o segundo entra no Pro.
- Um time de várias pessoas por menos de R$ 199. Equipe colaborativa é do Business; o Pro do Railway dá assentos ilimitados por US$ 20 de mínimo.
Migrar com a sua IA: a skill oficial e as decisões que continuam sendo suas
Se o app foi criado com Claude Code, Cursor ou Codex, a migração também pode ser feita por lá. O CLI da Upuai (a partir da v0.17.0) instala a skill oficial sozinho na primeira execução num projeto linkado, em .claude/skills/upuai/SKILL.md; upuai skill status mostra a versão. Fora do Claude Code, npx skills add saiph-ti/upuai-cli --skill upuai. A doc está em /docs/ai-deploy.
Com a skill, a IA conhece o upuai.toml, os comandos do CLI e o fluxo de deploy: peça a ela que converta o railway.json com as tabelas de “Do railway.json ao upuai.toml, chave por chave” e liste as variáveis a ajustar. O que ela não decide por você: a versão do Postgres, a hora de pausar a escrita, o plano que cabe no seu uso e se algum item sem equivalente é impeditivo. Se o projeto nasceu com IA, Criou um app com IA? Como colocá-lo no ar na Upuai complementa este guia.
Perguntas frequentes
Preciso reescrever código para migrar do Railway?
Na maioria dos casos, não. Muda configuração: o railway.json vira upuai.toml, as variáveis são importadas e as referências RAILWAY_* e ${{...}} são ajustadas. Código que lê PORT e DATABASE_URL do ambiente roda igual.
O sleepApplication tem equivalente?
Não. Todo serviço roda com no mínimo 1 instância; para não rodar, o serviço é excluído. Se o app depende de dormir para caber no orçamento, é um dos casos de “Quando vale ficar no Railway”.
Dá para testar antes de pagar? Sim: 15 dias, sem cartão. O prazo começa quando o primeiro serviço entra no ar (primeiro deploy concluído, ou primeiro banco ou bucket criado). No fim, sem plano, os serviços pausam e os dados ficam guardados por 15 dias antes de serem apagados.
Dá para migrar sem tirar o app do ar? Sem janela nenhuma, não, e desconfie de quem prometer isso. O que dá é encolher a janela: ensaio antes, TTL baixo, dump final com a escrita pausada e troca de DNS em seguida. A janela é o tempo do dump final, do restore e da propagação; os dois primeiros você mede no ensaio.
Comece pelo inventário, converta o arquivo com as tabelas, ensaie o restore e vire o domínio com o TTL baixo. 15 dias grátis, sem cartão; depois, planos a partir de R$ 19 por mês. Começar 15 dias grátis, ver os planos ou abrir a doc do CLI.
Fontes (consultadas em 07/10/2026): Railway, Config as Code · schema do railway.json · Railway, preços e planos · Railway, variáveis · Railway, regiões · PTAX do Banco Central (venda, 02/10 e 06/10/2026) · Decreto nº 12.499/2025 (IOF de 3,5%) · Upuai: /docs/upuai-toml, /docs/postgres, /docs/upuai-cli, /docs/ai-deploy e /pricing.
Faça deploy no Brasil em 5 minutos
PaaS brasileira, preços em Real, infraestrutura LGPD-native.
Ver planosArtigos relacionados
Deploy de API Node no Brasil: o POST que some em produção
A API Node responde no notebook. Em produção o GET passa e o primeiro POST some. Guia de deploy de API Node no Brasil: env, bind, CORS, proxy, healthcheck e body parser.
Bot de WhatsApp na Cloud API: quando sair da biblioteca não oficial
A conta da API oficial do WhatsApp muda em 1º de outubro de 2026: mensagem de serviço e utilidade dentro da janela de 24h passam a ser cobradas. Quando migrar e o que muda no deploy.
Hospedar bot de WhatsApp 24/7 no Brasil (Baileys ou Venom)
Como hospedar um bot de WhatsApp 24/7 no Brasil com Baileys ou Venom: onde a sessão precisa morar para sobreviver ao restart, o risco real de bloqueio do número e o deploy com git push.