Por que falar de Rust no Cloudflare Workers
Cloudflare Workers é uma plataforma serverless de edge computing: em vez de rodar um container em uma região fixa, você publica funções pequenas que respondem perto do usuário. Para muitos times, isso resolve páginas dinâmicas leves, APIs de borda, proxies, autenticação, webhooks, redirecionamentos, cache inteligente e integrações com KV, R2, Queues e Durable Objects.
Rust entra nesse cenário por meio de WebAssembly. O objetivo não é substituir todo backend por Rust no edge. O uso mais forte é mover partes específicas do sistema para uma camada rápida, portável e com tipos fortes: validação de payload, parsing, roteamento, regras de negócio pequenas, normalização de dados, geração de respostas, filtros de segurança e trechos compartilhados com serviços Rust maiores.
Para quem acompanha vagas Rust e trilhas de carreira Rust, esse tema é interessante porque junta três sinais de mercado: WebAssembly, edge/serverless e backend de alta confiabilidade. Saber explicar quando usar Workers, quando ficar em um serviço Axum tradicional e quais limites aparecem no wasm mostra maturidade técnica além do entusiasmo pela linguagem.
O modelo mental: não é um servidor Linux
O primeiro erro é pensar em Cloudflare Workers como uma VPS pequena. Workers não são processos longos ouvindo porta TCP. Você escreve handlers que recebem uma requisição, executam rapidamente e devolvem uma resposta. O runtime é restrito de propósito: inicialização rápida, isolamento, APIs controladas e integração com recursos da própria plataforma.
Isso muda decisões comuns em Rust. Um projeto com Tokio completo, acesso direto a filesystem, threads, chamadas bloqueantes e dependências nativas pode não compilar ou não fazer sentido no Workers. Em vez de trazer a arquitetura inteira, você separa uma unidade menor: uma função de validação, uma API de consulta, um roteador edge, um transformador de JSON ou uma camada de autorização.
Pense no Workers como uma borda especializada. Se você precisa de processamento pesado, filas longas, banco relacional com transações complexas, jobs demorados ou sockets customizados, talvez um serviço Rust normal em container continue sendo a melhor base. Se você precisa responder rápido a requisições HTTP globais e usar APIs de edge, Workers vira uma opção forte.
worker-rs em poucas palavras
O projeto mais usado para escrever Workers em Rust é o worker-rs. Ele fornece bindings e uma experiência parecida com frameworks web: você define rotas, recebe Request, monta Response, lê variáveis de ambiente e acessa bindings como KV. Por baixo, o Rust compila para wasm e conversa com o ambiente JavaScript do Workers.
Um esqueleto conceitual fica assim:
use worker::*;
#[event(fetch)]
async fn fetch(req: Request, env: Env, _ctx: Context) -> Result<Response> {
let router = Router::new();
router
.get("/health", |_, _| Response::ok("ok"))
.get_async("/api/slug/:slug", |_, ctx| async move {
let slug = ctx.param("slug").unwrap_or("sem-slug");
Response::ok(format!("slug: {slug}"))
})
.run(req, env)
.await
}
O exemplo é pequeno, mas já mostra a diferença para um servidor tradicional. Você não inicia um listener. O runtime chama sua função fetch para cada requisição. O roteador organiza a resposta, e o ambiente entrega bindings configurados no wrangler.toml.
Quando Rust faz sentido no edge
Rust no Workers faz sentido quando a lógica tem algum peso de domínio ou precisa ser compartilhada. Um exemplo comum é validação de payload em webhook: regras de assinatura, normalização de campos, parsing cuidadoso, retorno de erro consistente e testes unitários. Outro caso é transformar dados antes de cachear: reduzir JSON, validar schema, gerar chaves canônicas e evitar inconsistências entre serviços.
Também faz sentido quando você já tem uma base Rust. Se a empresa usa Rust em microsserviços, CLI interna, pipelines ou bibliotecas de domínio, compilar uma parte para wasm pode evitar duplicação. A mesma função que valida um identificador, calcula uma política ou serializa um formato pode ser usada em backend e edge com adaptações pequenas.
Por outro lado, se a função é apenas colar duas APIs com meia dúzia de linhas, TypeScript pode ser mais barato de manter. Rust tem curva de compilação, toolchain wasm, tamanhos de bundle e ergonomia própria. A escolha boa é pragmática: use Rust onde tipos, testes, performance previsível ou compartilhamento de código pagam a complexidade.
Limites importantes antes de escolher
O ambiente wasm impõe limites. Nem toda crate funciona fora de um sistema operacional completo. Bibliotecas com C bindings, dependências de OpenSSL, acesso a arquivos locais, threads nativas ou chamadas de rede fora das APIs suportadas podem falhar. Antes de apostar uma arquitetura, crie um protótipo mínimo e rode o deploy real.
Outro ponto é observabilidade. Em um serviço Rust tradicional você pode controlar logs, métricas, tracing, exporters e sidecars. No edge, você depende das integrações da plataforma e precisa manter logs úteis sem vazar dados sensíveis. Se o Worker valida tokens ou processa payloads privados, registre categorias de erro e IDs de correlação, não corpos completos de requisição.
Custo também importa. Edge computing é ótimo para latência e distribuição, mas não transforma toda operação em algo grátis. Requisições, storage, CPU time, Durable Objects, R2 e filas têm modelos próprios. Uma regra de cache ruim pode multiplicar custo; uma resposta cacheável bem desenhada pode reduzir carga no backend principal.
KV, Durable Objects e estado
Muitos Workers começam stateless, mas logo precisam de estado. Cloudflare KV serve bem para leitura distribuída, feature flags, redirects, configurações, caches e dados que toleram consistência eventual. Em Rust, você acessa o binding pelo ambiente e lê/escreve chaves conforme a API disponível no worker-rs.
Durable Objects resolvem outro problema: coordenação com estado único por objeto. Eles são úteis para sessões, rate limiting, presença, salas, locks leves e fluxos que precisam de serialização por chave. O desenho muda: em vez de consultar um banco global a cada chamada, você roteia eventos para um objeto responsável por um subconjunto do estado.
A decisão prática é separar dados por necessidade de consistência. Configuração e cache combinam com KV. Coordenação por usuário, sala ou recurso combina melhor com Durable Objects. Dados relacionais complexos, relatórios e transações longas provavelmente continuam melhor em banco fora do Worker, acessado por API ou serviço intermediário.
Deploy com Wrangler
O deploy normalmente passa pelo Wrangler, a CLI da Cloudflare. Um projeto real terá wrangler.toml, nome do Worker, compatibilidade de runtime, bindings e comandos de build. A parte Rust compila para wasm; a parte de empacotamento publica o Worker.
Um fluxo típico inclui:
- criar o projeto worker-rs;
- implementar rotas pequenas;
- rodar testes Rust para lógica pura;
- executar o Worker localmente com Wrangler;
- configurar bindings de KV, R2 ou Durable Objects;
- publicar em ambiente de staging;
- medir logs, latência, erros e cache hit rate antes de promover.
Não pule staging. Bugs de runtime wasm costumam aparecer em detalhes: serialização, headers, limites de API, dependência incompatível ou variável de ambiente ausente. Teste local é necessário, mas o deploy real é a validação mais honesta.
Estrutura recomendada de projeto
Uma boa estrutura separa lógica pura da borda. Em vez de colocar tudo dentro do handler, crie módulos testáveis:
src/
lib.rs # handler do Worker e rotas
domain.rs # regras puras, sem dependência do runtime
errors.rs # erros de domínio e respostas HTTP
cache.rs # composição de chaves e TTLs
telemetry.rs # logs estruturados permitidos no edge
Essa separação permite testar domain.rs com cargo test sem subir o runtime. Também facilita reaproveitar código em um serviço Axum ou CLI com Clap se a lógica crescer. O handler do Worker deve orquestrar: ler requisição, chamar domínio, montar resposta e registrar evento.
Essa disciplina é especialmente importante em equipes. Sem separação, o projeto vira uma mistura de bindings, strings de rota, JSON manual e regras de negócio difíceis de testar. Com separação, Rust mostra seu valor: tipos explícitos, erros controlados e refatoração segura.
Segurança: cuidado com headers, tokens e cache
Workers frequentemente ficam na frente de sistemas internos. Isso aumenta a responsabilidade. Valide origem, método HTTP, content type, tamanho de payload, assinatura de webhook e headers esperados. Não confie em dados enviados pelo cliente apenas porque a função roda perto do usuário.
Cache também pode vazar dados. Antes de cachear uma resposta, confirme se ela não depende de cookie, token, autorização ou informação pessoal. Para APIs autenticadas, prefira respostas explicitamente privadas. Para páginas públicas, normalize chaves de cache e remova parâmetros irrelevantes para evitar explosão de variantes.
Rust ajuda porque obriga você a modelar erros e estados, mas não decide política de segurança sozinho. A regra operacional é simples: logs mínimos, validação explícita, cache conservador e testes para casos negativos.
Relação com WebAssembly no navegador
Rust no Workers e Rust no navegador compartilham WebAssembly, mas têm objetivos diferentes. No navegador, wasm acelera trechos de interface, visualização, editor, jogo, processamento local ou biblioteca compartilhada. No Workers, wasm roda no servidor de borda e responde HTTP antes de chegar ao usuário.
Se você está estudando o tema do zero, comece pelo nosso guia de Rust para WebAssembly e depois avance para Workers. O conhecimento de ownership, Result, serialização com Serde e async continua útil, mas o ambiente muda bastante.
A vantagem de aprender os dois lados é enxergar Rust como linguagem de produto multiplataforma: CLI, backend, edge, browser e sistemas. Essa visão aparece cada vez mais em times que querem reduzir duplicação entre cliente, servidor e automações internas.
Checklist antes de colocar em produção
Antes de promover um Worker Rust para produção, revise:
- a crate principal compila para
wasm32-unknown-unknownsem dependências nativas problemáticas; - regras de domínio têm testes unitários fora do runtime;
- headers e métodos aceitos são explícitos;
- erros não vazam segredo ou stack trace;
- logs não incluem token, cookie, payload sensível ou PII;
- cache só guarda respostas públicas ou corretamente segmentadas;
- bindings de KV, R2, Queues e Durable Objects estão documentados;
- staging recebeu tráfego real ou replay controlado;
- rollback está claro no Wrangler ou pipeline;
- métricas mínimas de erro e latência estão visíveis.
Esse checklist evita o erro mais comum: tratar edge como playground sem maturidade operacional. Um Worker pequeno pode ficar no caminho crítico de login, checkout, webhook ou API pública. Pequeno não significa irrelevante.
O que estudar para trabalhar com Rust no edge
Se a meta é carreira, não estude apenas worker-rs. Monte um repertório:
- fundamentos de ownership e borrowing;
- async Rust com Tokio mesmo sabendo que o runtime do Worker é diferente;
- serialização com Serde;
- tratamento de erros com
Result, thiserror e anyhow; - WebAssembly e limitações de crates;
- HTTP, cache, headers, CORS e segurança básica;
- deploy com Wrangler e leitura de logs;
- desenho de APIs pequenas e testáveis.
Depois, crie um projeto de portfólio: um Worker que recebe webhooks, valida assinatura, normaliza payload, grava uma versão reduzida em KV e expõe uma rota pública cacheada. Documente trade-offs no README. Isso vale mais do que um hello world porque mostra raciocínio de produção.
Conclusão
Rust no Cloudflare Workers é uma ferramenta específica, não uma religião. Ele brilha quando você precisa levar lógica segura, testável e portável para a borda, especialmente em projetos que já usam Rust ou WebAssembly. Ele perde força quando a integração é trivial, quando o ecossistema TypeScript resolve com menos custo ou quando dependências nativas impedem um build wasm limpo.
A decisão profissional é escolher o menor componente que se beneficia de Rust: validação, transformação, segurança, roteamento ou lógica compartilhada. Publique pequeno, meça, aprenda os limites do runtime e só então expanda. Esse caminho entrega valor real e ainda constrói uma habilidade rara: unir Rust, WebAssembly e infraestrutura de edge sem romantizar nenhuma das três partes.