Build do Tauri no GitHub Actions: quanto demora
Vitor Ayres (abre em nova aba)
Um app Tauri leva minutos para compilar no GitHub Actions, e a internet está cheia de conselhos genéricos sobre Rust em CI: cache, sccache, trocar o linker, cortar dependências. Quisemos saber quais valem para o Tauri, e quanto.
Este texto registra o que cerca de 380 builds válidos, em 24 lotes, mostraram entre 10 e 12 de setembro de 2026. Cada número abaixo é a mediana de pelo menos 2 amostras, e cada afirmação traz o grau de confiança que o registro de evidências dá a ela. O app é pequeno, com um frontend trivial, e isso limita o que os números dizem.
Resumo
- Runner de 4 núcleos, sem cache, app pequeno: 3 a 5,5 minutos. O cargo é quase tudo.
- Um cache do
target/corta 55 a 65% de um commit comum. rust-cache e actions/cache empatam. - No Linux, não gerar AppImage e rpm economiza 1m14s, mais que qualquer flag.
codegen-units = 1é a opção cara do perfil de release. LTO fat custa bem menos.panic = "abort"corta o binário do Windows pela metade.- sccache, troca de linker e corte de dependências não ajudaram.
- A variação entre runners é de 5 a 30%, até 40% no macOS. Diferença abaixo de 10% é ruído.
Onde o tempo vai
Um build frio, sem cache, num runner de 4 núcleos, estágio por estágio:
| Estágio | Linux | Windows | macOS |
|---|---|---|---|
| Dependências do sistema (apt) | 33 s | 0 | 0 |
| pnpm install | 2 s | 10 s | 3 s |
| Build do frontend | 2 s | 3 s | 2 s |
| cargo | 3m43s | 5m05s | 2m50s |
| Empacotamento | 1m18s | 17 s | 12 s |
Confiança alta. O apt, que muita gente aponta como o vilão do Linux, custa 33 segundos. O cargo custa de 3 a 5 minutos, e dentro dele o piso é a crate do app, que carrega o runtime do Tauri monomorfizado: de 40 a 55 segundos no Linux e de 70 a 110 no Windows, mesmo com tudo o mais em cache.
O tamanho do runner decide os números absolutos. Repositórios públicos ganham 4 núcleos no Linux e no Windows, e privados, 2. O mesmo build frio levou 8m57s contra 5m03s no Linux e 9m41s contra 5m25s no Windows. Confiança média, porque o lado de 2 núcleos é uma amostra só. As proporções entre opções transferem melhor que os tempos.
A variação entre runners idênticos é de 5 a 30%. Builds frios iguais no Linux repetiram com 4 segundos de diferença, mas o Windows espalhou de 4m30s a 5m54s, e dois jobs idênticos no macOS no mesmo run levaram 3m33s e 5m02s. Uma diferença de uma amostra só, abaixo de 20% no Windows ou 40% no macOS, não quer dizer nada.
Cache: o que mais corta
Build quente, depois de uma mudança de uma função na crate do app, mediana de 2:
| Linux | Windows | macOS | |
|---|---|---|---|
| Sem cache | 5m03s | 5m25s | 3m04s |
| rust-cache | 2m17s | 2m06s | 1m17s |
| actions/cache simples | 2m07s | 2m25s | 1m14s |
| rust-cache + sccache | 2m05s | 2m29s | 1m30s |
| sccache sozinho | 3m55s | 4m22s | 1m38s |
Confiança média. O rust-cache e o actions/cache simples diferem menos que a variação em todos os runners. A escolha entre eles é de tamanho e higiene: o rust-cache poda o que não foi usado e sempre recompila a crate do workspace; o actions/cache guarda tudo e chega antes ao limite de 10 GB por repositório.
Encher o cache não custa nada: o build frio com rust-cache levou 4m31s contra 5m03s sem cache. Uma dependência nova custa o mesmo que uma mudança no app: adicionar chrono custou 3 segundos no Linux e 15 no Windows.
Num monorepo de 16 plugins e 434 crates, a opção cache-workspace-crates do rust-cache economizou de 15 a 30 segundos, e o cargo quente ficou em 57 segundos no Linux contra 5m35s sem cache.
Não gere instaladores no pull request
Build frio no Linux, mediana de 2, contra a linha de base com todos os bundlers:
| Linux | tauri build |
empacotamento | diretório de bundles |
|---|---|---|---|
| deb, rpm e AppImage | 5m03s | 1m18s | 339 MB |
| só deb | 3m25s | 4 s | 17,7 MB |
| sem bundle | 3m24s | 2 s | nada |
Confiança alta para o estágio de empacotamento, que ficou entre 1m07s e 1m20s em todo job Linux de quatro lotes, e média para o tempo total. É a maior economia individual no Linux, maior que qualquer flag de compilador.
No Windows, o empacotamento vai de 17 segundos com NSIS e MSI para 11 só com NSIS e 6 sem bundle. No macOS, de 12 segundos com .app e DMG para 2 só com .app. Nenhum vale tirar pelo tempo. O DMG vale tirar dos builds de pull request porque é o passo que falha: 1 de 24 jobs macOS morreu no hdiutil.
O perfil de release
Tempo do cargo no app maior, mediana das amostras agrupadas de dois lotes, com o binário em Linux, Windows e macOS:
| Linux | Windows | macOS | Binário | |
|---|---|---|---|---|
| Referência | 3m51s | 6m08s | 3m25s | 10,3 / 10,4 / 7,2 MB |
codegen-units = 1 |
+26% | +33% | +54% | 8,6 / 9,4 / 5,9 MB |
lto = "fat" |
+14% | -2% | +12% | 8,6 / 9,8 / 6,1 MB |
Perfil fast |
-18% | -23% | -19% | 14,3 / 10,3 / 11,4 MB |
Confiança alta para codegen-units = 1 e para o perfil fast, média para o LTO fat.
Uma unidade de codegen serializa a crate do app, a que carrega o runtime do Tauri, num núcleo só. O binário fica de 15 a 20% menor. Subir para 256 unidades foi na direção contrária do esperado, mais lento no Linux e no Windows, porque com 4 núcleos não há paralelismo para comprar além das 16 unidades padrão.
O LTO fat teve um dia ruim de +44% no macOS que o rerun não repetiu. O LTO thin não muda nada, nem em tempo nem em tamanho. O opt-level sozinho quase não move o tempo: um build Tauri gasta nas dependências, na monomorfização e no link, não no otimizador.
O perfil fast, com opt-level = 1, 256 unidades e LTO desligado, vale cerca de 20% do tempo do cargo, por um binário de 40 a 60% maior no Linux e no macOS. Cache e bundlers valem de 50 a 70%. Ele vem depois deles, e só em pull request.
panic = "abort" é a economia de tamanho mais barata da lista: o binário foi de 10,4 para 4,9 MB no Windows, de 10,3 para 7,6 no Linux e de 7,2 para 5,0 no macOS, com o tempo dentro da variação. Confiança alta para o tamanho, baixa para o tempo. Só serve se o app não captura panics.
O que não ajudou
sccache. Sozinho é a pior opção com cache, porque sem o target/ restaurado toda crate ainda precisa ser linkada e a crate final compilada. Em cima do rust-cache, não ajuda num commit comum: a crate do app recompila de qualquer jeito, e os uploads por objeto às vezes deixam a combinação atrás do rust-cache sozinho. O piloto mostrou um ganho de 3 vezes, mas só porque nada tinha mudado entre os runs.
Pior: o backend do GitHub Actions do sccache grava um item de cache por objeto compilado, e a API de cache limita a taxa por repositório. Matrizes de 24, 30 e 42 jobs perderam de 34 a 100% das escritas, e 4 jobs com sccache entre 10 ainda perderam a metade e derrubaram um save do rust-cache junto. O sccache só avisa como “Cache write errors” nas estatísticas, e o job termina verde com o cache pela metade. Confiança alta, com os contadores nos logs de 24 jobs.
Trocar o linker. O Rust 1.90 em diante já usa rust-lld no Linux, então lld e mold caem no mesmo tempo. No Windows, rust-lld.exe não foi mais rápido.
Cortar dependências. Tirar reqwest e tokio, 29 crates, não teve efeito mensurável, nem frio nem quente, em 4 núcleos.
Compilação incremental. Custa de 7 a 8% num build frio e só paga quando o target/ sobrevive entre builds, cortando um rebuild para 3 a 8 segundos no melhor caso.
Configuração recomendada
Para o pull request: rust-cache, sem bundlers, perfil rápido. Medido junto, o tauri build levou 3m05s, 4m22s e 2m23s frio e 39 segundos, 1m42s e 39 segundos quente, no Linux, no Windows e no macOS. O job inteiro quente, com checkout, toolchain e apt, ficou entre 1m16s e 1m38s no Linux. Confiança média.
- uses: Swatinem/rust-cache@v2
with:
workspaces: src-tauri -> target
- run: pnpm tauri build --no-bundle -- --profile fast
Para a release: o mesmo cache e o perfil como ele é entregue, com todos os bundlers. Um preset de release com sccache, lld e LTO thin por cima foi medido e saiu de 15 a 40 segundos mais lento quente que o cache sozinho. Não há o que acrescentar.
Como verificamos
Foram 24 lotes de resultados entre 10 e 12 de setembro de 2026, em ubuntu-24.04 e windows-2022 com 4 núcleos, num repositório público, e macos-14 com 3. Os três primeiros lotes rodaram com 2 núcleos, num repositório privado, e valem só como verificação do pipeline. Rust 1.98.1. Cada lote tem o seu relatório e um registro de tempo por job.
Cada célula é a mediana de 2 a 6 amostras, com chaves de cache separadas por experimento e por lote, depois que um lote piloto contaminou o seguinte com caches ainda válidos. O tempo de parede é o do tauri build, o do cargo vem do --timings, e o empacotamento é o resto, incluindo a sobrecarga da CLI do Tauri.
O que não medimos: toolchain nightly e frontend paralelo, runners maiores, contêineres prontos, compilação cruzada, e onde começa o limite de taxa do sccache com 1 ou 2 jobs. O app de teste é pequeno e o frontend é trivial; um SPA grande põe minutos na linha do frontend.
O repositório com os workflows, os registros e o livro de evidências é o tauri-build. Uma versão em inglês desse material está em rascunho para a documentação do Tauri, à qual já contribuímos com tutoriais executáveis.
O mesmo cuidado em medir antes de decidir aparece no post sobre as capas do blog, geradas no build, e o GitHub Actions sem servidor nenhum é também o que publica as filas da ANVISA como feeds. Se a sua empresa mantém um app desktop em Tauri, é esse o trabalho que fazemos em código aberto.
Perguntas
- Quanto demora um build do Tauri no GitHub Actions?
- Um app pequeno, num runner de 4 núcleos e sem cache: 5m03s no Linux, 5m25s no Windows e 3m04s no macOS. Num repositório privado, com 2 núcleos, cerca de 9 minutos no Linux e no Windows.
- Quanto o cache economiza num build do Tauri?
- Com o rust-cache, um commit comum caiu de 55 a 65%: 2m17s no Linux, 2m06s no Windows e 1m17s no macOS. O actions/cache simples empata em tempo.
- O sccache ajuda num build do Tauri no GitHub Actions?
- Com o backend do GitHub Actions, não. Sozinho foi a pior opção com cache, 3m55s no Linux, e em cima do rust-cache ficou dentro da variação. Numa matriz de jobs ele perde mais da metade das escritas por limite de taxa.
- Qual opção do perfil de release mais pesa no build?
- codegen-units = 1: mais 26% no Linux, 33% no Windows e 54% no macOS no tempo do cargo. O LTO fat custa bem menos e encolhe o binário quase igual.
- O que mais economiza num build Linux do Tauri?
- Não gerar AppImage e rpm. O empacotamento cai de 1m18s para 4 segundos e o diretório de bundles de 339 MB para 18 MB. Mais que qualquer flag de compilador.