---
title: "Rust vs Elixir: Concorrência e BEAM vs Tokio | Rust Brasil"
url: "https://rustlang.com.br/artigos/rust-vs-elixir/"
markdown_url: "https://rustlang.com.br/artigos/rust-vs-elixir.MD"
description: "Rust vs Elixir: BEAM vs OS threads, Phoenix vs Axum, tolerância a falhas e quando combinar as duas linguagens em 2026."
date: "2026-02-23"
author: "Equipe Rust Brasil"
---

# Rust vs Elixir: Concorrência e BEAM vs Tokio | Rust Brasil

Rust vs Elixir: BEAM vs OS threads, Phoenix vs Axum, tolerância a falhas e quando combinar as duas linguagens em 2026.


## Introdução

Rust e Elixir são duas linguagens que atraem desenvolvedores apaixonados, mas por razões completamente opostas. **Elixir**, criada pelo brasileiro José Valim em 2011, roda sobre a BEAM (a máquina virtual do Erlang) e é projetada para sistemas concorrentes, distribuídos e tolerantes a falhas. **Rust** compila para código nativo e foca em performance máxima com segurança de memória.

Enquanto Rust pergunta "como extrair o máximo de performance com segurança?", Elixir pergunta "como construir sistemas que nunca param de funcionar?". Essa diferença de filosofia torna a comparação especialmente interessante.

Este artigo é para desenvolvedores web que estão decidindo entre Phoenix e Axum, engenheiros de sistemas que precisam de concorrência pesada e qualquer pessoa que queira entender quando cada linguagem brilha.

Se você veio do Google procurando **actix vs elixir**, **Rust vs Elixir**, **Phoenix vs Axum** ou **BEAM vs Tokio**, o ponto central é este: não compare apenas benchmark. Compare o modelo operacional. Rust entrega binários previsíveis, custo baixo por requisição e controle fino de CPU/memória. Elixir entrega uma plataforma de runtime para manter sistemas vivos, reiniciar partes quebradas e sustentar milhões de interações concorrentes com menos cola manual.

## Resumo rápido: Rust vs Elixir em 2026

| Pergunta | Melhor resposta curta |
|---|---|
| Quero API HTTP muito rápida e barata de hospedar | Rust com [Axum](/ecossistema/axum/) ou [Actix Web](/ecossistema/actix-web/) |
| Quero chat, notificações, presença, LiveView e tempo real | Elixir com Phoenix |
| Quero processar imagem, criptografia, parsing ou compressão | Rust puro, ou Rust dentro de Elixir via Rustler |
| Quero sistema que se recupere automaticamente de falhas parciais | Elixir/BEAM leva vantagem |
| Quero binário pequeno para edge, CLI, sidecar ou serviço interno | Rust leva vantagem |
| Quero produtividade full-stack com uma equipe pequena | Phoenix/Elixir pode ser mais direto |

A escolha madura raramente é "qual linguagem é melhor?". A pergunta de engenharia é: **onde o gargalo real do produto mora?** Se mora em CPU, latência, memória, distribuição de binário ou segurança de tipos, Rust costuma pagar. Se mora em fluxo de produto, presença em tempo real, supervisão, filas internas e resiliência de runtime, Elixir costuma pagar.

## Tabela Comparativa

| Aspecto | Rust | Elixir |
|---|---|---|
| **Runtime** | Código nativo (sem VM) | BEAM (máquina virtual do Erlang) |
| **Paradigma** | Multi-paradigma (imperativo + funcional) | Funcional (imutabilidade por padrão) |
| **Concorrência** | async/await + OS threads | Processos leves BEAM (~2KB cada) |
| **Tolerância a falhas** | Não nativa (Result + panic) | Supervisors + "let it crash" |
| **Hot code reload** | Não suportado | Nativo na BEAM |
| **Performance CPU** | Máxima (código nativo) | 5-20x mais lenta (BEAM interpretada) |
| **Latência** | Ultra-baixa, previsível | Baixa e consistente (preemptive scheduling) |
| **Tipagem** | Estática, forte | Dinâmica, forte (dialyzer para análise estática) |
| **Distribuição** | Manual (gRPC, HTTP) | Nativa (distributed Erlang) |
| **Ecossistema web** | Axum, Actix Web | Phoenix (com LiveView) |
| **Imutabilidade** | Opt-in (`let mut`) | Por padrão (tudo é imutável) |

## Modelos de Concorrência: Filosofias Opostas

### Elixir: Processos BEAM

Elixir usa **processos leves da BEAM** — não confunda com processos do sistema operacional. Cada processo BEAM consome apenas ~2KB de memória, e você pode criar **milhões** deles em uma única máquina:

```elixir
defmodule ProcessadorPedidos do
  def processar(pedido_id) do
    # Cada pedido é processado em seu próprio processo BEAM
    IO.puts("Processando pedido #{pedido_id}...")
    :timer.sleep(100)  # simula trabalho
    {:ok, pedido_id * 10}
  end
end

defmodule App do
  def executar do
    # Cria 10.000 processos concorrentes trivialmente
    tarefas =
      1..10_000
      |> Enum.map(fn id ->
        Task.async(fn -> ProcessadorPedidos.processar(id) end)
      end)

    resultados =
      tarefas
      |> Enum.map(&Task.await(&1, 5000))

    total =
      resultados
      |> Enum.map(fn {:ok, valor} -> valor end)
      |> Enum.sum()

    IO.puts("Total processado: #{total}")
  end
end

App.executar()
```

### Rust: Async/Await com Tokio

```rust
use tokio::task;

async fn processar(pedido_id: u64) -> u64 {
    println!("Processando pedido {pedido_id}...");
    tokio::time::sleep(tokio::time::Duration::from_millis(100)).await;
    pedido_id * 10
}

#[tokio::main]
async fn main() {
    let mut handles = Vec::new();
    for id in 1..=10_000 {
        handles.push(task::spawn(processar(id)));
    }

    let mut total: u64 = 0;
    for handle in handles {
        total += handle.await.unwrap();
    }

    println!("Total processado: {total}");
}
```

Ambas as abordagens lidam bem com 10.000 tarefas concorrentes. A diferença:

- **Elixir**: processos são **preemptivos** — a BEAM garante que nenhum processo monopoliza a CPU. Ideal para latência consistente.
- **Rust**: tasks são **cooperativas** — cada task precisa fazer `await` para devolver controle ao scheduler. Ideal para throughput máximo.

Para se aprofundar em concorrência no Rust, veja nosso [tutorial de concorrência](/tutoriais/concorrencia/).

## Tolerância a Falhas: "Let It Crash"

O recurso mais distintivo do Elixir (herdado do Erlang) é a tolerância a falhas via **supervisors**.

### Elixir: Supervisor Trees

```elixir
defmodule Conexao do
  use GenServer

  def start_link(opts) do
    GenServer.start_link(__MODULE__, opts, name: opts[:nome])
  end

  @impl true
  def init(opts) do
    IO.puts("Conexão #{opts[:nome]} iniciada")
    {:ok, %{tentativas: 0}}
  end

  @impl true
  def handle_call(:consultar, _from, estado) do
    # Simula falha intermitente
    if :rand.uniform(10) == 1 do
      raise "Erro de conexão!"
    end
    {:reply, {:ok, "dados"}, estado}
  end
end

defmodule App.Supervisor do
  use Supervisor

  def start_link(_) do
    Supervisor.start_link(__MODULE__, [], name: __MODULE__)
  end

  @impl true
  def init(_) do
    filhos = [
      {Conexao, nome: :db_principal},
      {Conexao, nome: :db_replica},
      {Conexao, nome: :cache},
    ]

    # Se um processo crashar, é reiniciado automaticamente!
    Supervisor.init(filhos, strategy: :one_for_one)
  end
end
```

Se a conexão do banco crashar, o supervisor reinicia automaticamente apenas aquele processo — o resto do sistema continua funcionando. Esse modelo de "let it crash" torna sistemas Elixir extraordinariamente resilientes.

### Rust: Tratamento Explícito de Erros

```rust
use std::fmt;

#[derive(Debug)]
struct ErroConexao(String);

impl fmt::Display for ErroConexao {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Erro de conexão: {}", self.0)
    }
}

impl std::error::Error for ErroConexao {}

async fn consultar_com_retry(
    nome: &str,
    tentativas: u32,
) -> Result<String, ErroConexao> {
    for tentativa in 1..=tentativas {
        match consultar_banco(nome).await {
            Ok(dados) => return Ok(dados),
            Err(e) => {
                eprintln!(
                    "[{nome}] Tentativa {tentativa}/{tentativas} falhou: {e}"
                );
                if tentativa < tentativas {
                    tokio::time::sleep(
                        tokio::time::Duration::from_millis(100 * tentativa as u64)
                    ).await;
                }
            }
        }
    }
    Err(ErroConexao(format!("{nome}: todas as tentativas falharam")))
}

async fn consultar_banco(nome: &str) -> Result<String, ErroConexao> {
    // Simula falha intermitente
    if rand::random::<u32>() % 10 == 0 {
        return Err(ErroConexao(format!("timeout em {nome}")));
    }
    Ok("dados".to_string())
}

#[tokio::main]
async fn main() {
    match consultar_com_retry("db_principal", 3).await {
        Ok(dados) => println!("Sucesso: {dados}"),
        Err(e) => eprintln!("Falha final: {e}"),
    }
}
```

Em Rust, a resiliência é construída manualmente com `Result`, retries e circuit breakers. Funciona bem, mas requer mais código e disciplina do que o modelo de supervisors do Elixir.

## Exemplo Prático: Aplicação Web

### Elixir com Phoenix

```elixir
defmodule AppWeb.TarefaController do
  use AppWeb, :controller

  alias App.Tarefas

  def index(conn, _params) do
    tarefas = Tarefas.listar()
    json(conn, %{tarefas: tarefas})
  end

  def create(conn, %{"titulo" => titulo, "prioridade" => prioridade}) do
    case Tarefas.criar(%{titulo: titulo, prioridade: prioridade}) do
      {:ok, tarefa} ->
        conn
        |> put_status(:created)
        |> json(%{tarefa: tarefa})

      {:error, changeset} ->
        conn
        |> put_status(:unprocessable_entity)
        |> json(%{erros: traduzir_erros(changeset)})
    end
  end

  defp traduzir_erros(changeset) do
    Ecto.Changeset.traverse_errors(changeset, fn {msg, _opts} -> msg end)
  end
end
```

### Rust com Axum

```rust
use axum::{
    extract::State,
    http::StatusCode,
    routing::{get, post},
    Json, Router,
};
use serde::{Deserialize, Serialize};
use std::sync::{Arc, Mutex};

#[derive(Clone, Serialize)]
struct Tarefa {
    id: u64,
    titulo: String,
    prioridade: String,
}

#[derive(Deserialize)]
struct CriarTarefa {
    titulo: String,
    prioridade: String,
}

type Db = Arc<Mutex<Vec<Tarefa>>>;

async fn listar(State(db): State<Db>) -> Json<Vec<Tarefa>> {
    let tarefas = db.lock().unwrap();
    Json(tarefas.clone())
}

async fn criar(
    State(db): State<Db>,
    Json(dto): Json<CriarTarefa>,
) -> (StatusCode, Json<Tarefa>) {
    let mut tarefas = db.lock().unwrap();
    let id = tarefas.len() as u64 + 1;
    let tarefa = Tarefa {
        id,
        titulo: dto.titulo,
        prioridade: dto.prioridade,
    };
    tarefas.push(tarefa.clone());
    (StatusCode::CREATED, Json(tarefa))
}

#[tokio::main]
async fn main() {
    let db: Db = Arc::new(Mutex::new(Vec::new()));
    let app = Router::new()
        .route("/tarefas", get(listar).post(criar))
        .with_state(db);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:4000")
        .await
        .unwrap();
    axum::serve(listener, app).await.unwrap();
}
```

Phoenix oferece uma experiência mais "batteries included" com Ecto (ORM), Phoenix LiveView (interfaces reativas sem JavaScript) e PubSub integrado. Axum é mais minimalista, mas significativamente mais rápido.

## Comparação de Performance

### Benchmarks de Servidor Web

Benchmarks públicos variam conforme hardware, payload, banco, TLS, middleware e versão do framework. Use a tabela como **ordem de grandeza**, não como promessa absoluta de produção.

| Métrica | Rust (Axum/Actix) | Elixir (Phoenix) | Tendência prática |
|---|---|---|---|
| **Requisições/s (JSON simples)** | Centenas de milhares a milhões | Dezenas a centenas de milhares | Rust costuma vencer em throughput bruto |
| **Latência p50** | Muito baixa | Baixa | Rust tende a ter vantagem em serviços pequenos |
| **Latência p99** | Excelente se não houver blocking no runtime | Muito consistente por causa do scheduler preemptivo | Depende do tipo de carga |
| **Memória idle** | Poucos MB | Dezenas de MB | Rust vence em footprint |
| **Memória sob carga** | Baixa e previsível | Maior, mas com ótimo isolamento de processos | Rust vence em custo por instância |
| **Startup** | Milissegundos | Segundos | Rust vence para serverless, CLI e edge |

### Actix vs Elixir: por que essa busca aparece

A consulta **actix vs elixir** normalmente mistura duas comparações diferentes: Actix Web contra Phoenix, e Rust contra a BEAM. Actix Web é um framework HTTP extremamente rápido dentro do ecossistema Rust. Elixir é uma linguagem e um runtime completo; Phoenix é o framework web mais famoso em cima dele.

Se a decisão é apenas "quero uma API REST que responda JSON com baixa latência", compare [Actix Web](/ecossistema/actix-web/), [Axum](/ecossistema/axum/) e Phoenix. Rust provavelmente entrega menor custo por requisição. Mas se a decisão envolve workers supervisionados, canais em tempo real, PubSub, presença, LiveView e recuperação automática de falhas, comparar só Actix com Phoenix fica injusto: Phoenix vem com mais plataforma embutida.

Para times que já usam Rust, a pergunta prática é se Actix ainda vale frente a Axum. Para projetos novos, Axum ganhou força por se alinhar melhor com Tokio/Tower e composição explícita; Actix segue muito maduro e rápido. Se você está decidindo dentro de Rust, veja [Axum vs Actix Web em 2026](/artigos/axum-vs-actix/) e depois volte para esta comparação contra Elixir.

### Onde Elixir Compensa

Apesar de ser 7x mais lenta em throughput bruto, Elixir tem vantagens práticas:

- **Latência consistente**: o scheduler preemptivo da BEAM garante que nenhuma requisição espere muito. Rust pode ter picos de latência se uma task bloquear o scheduler.
- **Hot code reload**: atualizar código em produção sem derrubar conexões. Impossível em Rust.
- **Distribuição nativa**: conectar nós em cluster é trivial. Em Rust, você precisa implementar manualmente com gRPC ou similar.
- **Concorrência massiva**: gerenciar 1 milhão de WebSockets é mais natural com processos BEAM.

## Quando Combinar Rust e Elixir

Uma abordagem cada vez mais popular é usar **Elixir como orquestrador e Rust nos pontos quentes**, via NIFs (Native Implemented Functions) com a biblioteca **Rustler**:

```rust
// native/meu_nif/src/lib.rs
use rustler::{Encoder, Env, NifResult, Term};

#[rustler::nif]
fn processar_imagem(dados: Vec<u8>, largura: u32) -> NifResult<Vec<u8>> {
    // Processamento pesado de imagem em Rust
    let resultado: Vec<u8> = dados
        .chunks(3)
        .flat_map(|pixel| {
            let cinza = (pixel[0] as u32 + pixel[1] as u32 + pixel[2] as u32) / 3;
            vec![cinza as u8; 3]
        })
        .collect();
    Ok(resultado)
}

rustler::init!("Elixir.MeuNif");
```

```elixir
defmodule MeuNif do
  use Rustler, otp_app: :minha_app, crate: "meu_nif"

  # Funções implementadas em Rust para performance
  def processar_imagem(_dados, _largura), do: :erlang.nif_error(:not_loaded)
end

# Uso: o melhor dos dois mundos
defmodule ImagemController do
  def processar(conn, %{"imagem" => upload}) do
    dados = File.read!(upload.path)

    # Processamento pesado em Rust, orquestração em Elixir
    resultado = MeuNif.processar_imagem(dados, 1920)

    send_download(conn, {:binary, resultado}, filename: "processada.rgb")
  end
end
```

Essa combinação é usada em produção por empresas como Discord (que migrou componentes de Elixir para Rust) e pela própria comunidade Elixir com projetos como **Explorer** (dataframes com Polars/Rust por baixo).

## Quando Usar Elixir

Escolha Elixir quando:

- **Sistemas de tempo real**: chat, notificações, WebSockets em massa (Phoenix LiveView)
- **Tolerância a falhas é prioridade**: sistemas financeiros, telecoms, IoT
- **Distribuição é necessária**: clusters de servidores com comunicação nativa
- **Hot code reload importa**: sistemas que não podem ter downtime
- **Equipe de tamanho médio**: Elixir é produtiva e a comunidade é excelente

## Quando Usar Rust

Escolha Rust quando:

- **Throughput bruto é prioridade**: processamento de dados em massa, proxies, CDNs
- **Recursos são limitados**: serverless, edge computing, containers pequenos
- **Latência ultra-baixa**: trading, gaming, processamento de áudio/vídeo
- **CPU-bound**: compiladores, compressão, criptografia, processamento de imagem
- **Binários autossuficientes**: CLIs e ferramentas sem dependências de runtime

## Impacto na carreira no Brasil

Para carreira, Rust e Elixir ocupam nichos diferentes. Elixir aparece muito em produtos web, fintechs, educação, SaaS, healthtechs e empresas que valorizam Phoenix/LiveView para construir rápido com alta disponibilidade. Rust aparece mais em infraestrutura, segurança, blockchain, performance, sistemas embarcados, ferramentas internas, edge, observabilidade e backend de baixa latência.

No Brasil, Rust ainda é menor, mas a combinação com backend moderno aumenta o valor do perfil. Um desenvolvedor que sabe [Tokio](/ecossistema/tokio/), [Axum](/ecossistema/axum/), [SQLx](/ecossistema/sqlx/), [Tracing](/ecossistema/tracing/), deploy e observabilidade consegue se posicionar para vagas de plataforma e sistemas. Veja também as [vagas Rust](/vagas/), a página de [empresas usando Rust](/empresas/) e o guia de [salário Rust no Brasil](/blog/salario-rust-brasil-2026/).

Elixir costuma ser mais imediatamente produtivo para web product engineering. Rust costuma ser mais diferenciado para infraestrutura e performance. Se você já trabalha com Elixir, aprender Rust para NIFs, serviços críticos e ferramentas de plataforma é uma expansão natural. Se você já trabalha com Rust, estudar Elixir ajuda a enxergar supervisão, mensagens e tolerância a falhas como propriedades de arquitetura, não apenas bibliotecas.

## FAQ rápido

### Rust substitui Elixir?

Não em todos os casos. Rust substitui bem componentes onde performance, footprint e segurança de tipos importam mais. Elixir continua excelente para sistemas vivos, distribuídos, com comunicação em tempo real e alta tolerância a falhas.

### Phoenix é mais lento que Axum?

Em throughput bruto, geralmente sim. Mas Phoenix entrega LiveView, PubSub, supervisão e produtividade full-stack. Em produto real, uma stack mais lenta no benchmark pode vencer se entregar mais rápido e operar com menos incidentes.

### Rustler é seguro para NIFs?

Rustler reduz bastante o risco de NIFs escritos em C, porque Rust evita classes inteiras de erros de memória. Ainda assim, NIF mal desenhada pode bloquear schedulers da BEAM. Use para trabalho CPU-bound bem isolado e meça.

### Qual estudar primeiro?

Se você quer backend web produtivo e tempo real, Elixir/Phoenix é um ótimo primeiro foco. Se você quer sistemas, performance, infraestrutura, WebAssembly, segurança ou edge, Rust é o melhor foco. Para mercado premium, saber os dois abre conversas raras.

## Conclusão e Recomendação

**Para aplicações web com requisitos de tempo real e alta disponibilidade**, como chat, plataformas de streaming, IoT e sistemas financeiros, Elixir com Phoenix é a escolha ideal. O modelo de concorrência da BEAM, supervisors e hot code reload oferecem uma fundação incomparável para sistemas que não podem parar.

**Para serviços de alta performance, processamento de dados e infraestrutura**, Rust é claramente superior. A diferença de 7x em throughput e 10x em consumo de memória se traduz em custos de infraestrutura significativamente menores.

**A melhor estratégia para muitos projetos** é combinar as duas: Elixir para a lógica de aplicação, orquestração e comunicação em tempo real, com Rust via Rustler/NIFs para os componentes CPU-bound. Essa abordagem oferece produtividade, resiliência e performance onde cada uma importa mais.

---

## Veja Também

- [Tutorial de Concorrência em Rust](/tutoriais/concorrencia/) — Async/await, threads e canais
- [Rust vs Go: Qual Escolher em 2026](/artigos/rust-vs-go/) — Outra linguagem popular para concorrência
- [Rust vs Python: Quando Usar Cada Um](/artigos/rust-vs-python/) — Combinando Rust com outra linguagem via FFI
- [Tutorial: API REST com Axum](/tutoriais/api-rest-axum/) — Construa APIs de alta performance
- [Receita: Async/Await Básico](/receitas/async-await-basico/) — Fundamentos de código assíncrono em Rust
- [Instalação do Rust](/instalacao/) — Configure seu ambiente de desenvolvimento

---

Se você está comparando modelos de concorrência entre linguagens, veja também:

- <a href="https://golang.com.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'golang.com.br' })">Concorrência em Go: goroutines e channels para paralelismo simples</a>
- <a href="https://kotlin.dev.br/" target="_blank" rel="noopener" onclick="umami.track('portfolio-site-click', { destination: 'kotlin.dev.br' })">Kotlin Coroutines: concorrência estruturada e leve na JVM</a>
