O que e CQRS?

Command Query Responsibility Segregation: separar quem escreve de quem le.

CQRS, que vem de Command Query Responsibility Segregation, e um padrão arquitetural que propoe usar modelos diferentes para operações de leitura e operações de escrita em um sistema. A ideia, popularizada por Greg Young e Udi Dahan, parte de uma observação simples: as necessidades de quem escreve dados e de quem le dados são fundamentalmente diferentes. Quem escreve precisa validar regras de negócio, manter consistência e garantir integridade. Quem le precisa de velocidade, flexibilidade de consulta e formato adequado para exibição. Tentar usar o mesmo modelo para as duas responsabilidades frequentemente resulta em compromissos que prejudicam ambos os lados. O CQRS resolve isso usando modelos otimizados para cada finalidade.

Como funciona na prática

Commands alteram estado. Queries apenas consultam. Modelos separados para cada lado.

Em uma aplicação com CQRS, as operações se dividem em dois tipos. Commands são instruções para alterar o estado do sistema, como CriarPedido, AtualizarEndereco ou CancelarAssinatura. Eles passam pela lógica de negócio completa, validam regras, aplicam mudancas e geralmente não retornam dados, apenas confirmação de sucesso ou falha. Queries são consultas puras que não alteram estado algum. Elas podem usar um modelo de dados completamente diferente, otimizado para leitura, com tabelas denormalizadas, caches pre-calculados ou até um banco de dados separado. A aplicação não precisa mapear o mesmo objeto para as duas operações. O modelo de escrita pode ser um Aggregate rico com comportamento. O modelo de leitura pode ser um DTO simples com exatamente os campos que a interface precisa.

Exemplo prático em sistema de pedidos

Escrita com modelo de dominio rico. Leitura com visao otimizada para o dashboard.

Em um sistema de pedidos, o Command CriarPedido passa por toda a lógica de negócio: verificação de estoque, cálculo de frete, validação de pagamento e criação do Aggregate Pedido com suas invariantes de negócio. Esse processo prioriza consistência e corretude. Ja o lado de leitura, como a Query ListarPedidosDashboard, pode usar uma tabela separada ja preparada com o join de todas as informações necessárias para o painel: nome do cliente, itens, total, status, tudo em uma única linha denormalizada. Essa tabela e atualizada de forma assíncrona quando um Command e processado. O resultado e que a tela do dashboard carrega muito mais rápido porque não precisa fazer joins complexos em tempo real, e o processamento de novos pedidos não e afetado pela complexidade das consultas.

Exemplo prático em sistema financeiro

Saldo calculado de forma diferente para operações críticas e para relatorios.

Em um sistema financeiro, o modelo de escrita pode ser baseado em lançamentos imutáveis, onde cada transação e um evento e o saldo e sempre calculado a partir do histórico. Isso garante auditabilidade e consistência. O modelo de leitura pode ter o saldo pre-calculado e disponível em cache para consultas rápidas no app. Quando o usuário consulta o saldo, le do modelo de leitura. Quando faz uma transferência, o Command passa pelo modelo de escrita com todas as validações. Esse padrão e muito comum em sistemas bancários onde as necessidades de consistência e de performance são igualmente críticas e, sem CQRS, estariam constantemente em conflito.

CQRS com Event Sourcing

Os dois padrões se complementam naturalmente mas são independentes.

CQRS e Event Sourcing frequentemente aparecem juntos, mas são conceitos independentes. No Event Sourcing, em vez de armazenar o estado atual de um objeto, o sistema armazena a sequência de eventos que levaram a esse estado. O estado atual e reconstruido reproduzindo os eventos em ordem. Quando combinado com CQRS, os eventos do lado de escrita servem como fonte da verdade, e o lado de leitura e reconstruido a partir desses eventos em um formato otimizado para consulta. Essa combinação e muito poderosa para sistemas que precisam de auditoria completa, reprodução de estado em qualquer ponto no tempo e flexibilidade para criar novas visões dos dados sem alterar o histórico. Porém, adiciona complexidade considerável e deve ser adotada somente quando os beneficios justificam o investimento.

Quando usar CQRS

Onde as necessidades de leitura e escrita são suficientemente diferentes para justificar a separação.

O CQRS faz mais sentido quando o volume de leituras e muito maior que o de escritas, o que e comum na maioria dos sistemas. Também e uma boa escolha quando as consultas exigem dados de múltiplas fontes que seriam caros de calcular em tempo real, quando a lógica de negócio do lado de escrita e complexa e precisa ser bem isolada, ou quando o sistema precisa escalar leituras e escritas de forma independente. Sistemas de e-commerce, plataformas financeiras, sistemas de reservas e plataformas de conteúdo são exemplos clássicos onde o CQRS traz beneficios significativos. O padrão também facilita a transição para microservicos, pois o modelo de leitura pode ser facilmente externalizado como um serviço dedicado.

Quando não usar CQRS

Sistemas simples com baixa complexidade não se beneficiam do overhead do padrão.

Para sistemas com lógica de negócio simples, onde a mesma entidade e usada para leitura e escrita sem grandes diferenças de necessidade, o CQRS adiciona complexidade desnecessária. Ter dois modelos, dois pipelines e possivelmente dois bancos de dados para um CRUD básico e um exagero claro. Outro cenário onde o CQRS não ajuda e quando a consistência imediata e um requisito absoluto para todas as operações. O modelo de leitura do CQRS tipicamente e atualizado de forma assíncrona, o que significa que pode haver um breve período onde leitura e escrita estão desincronizadas, isso e chamado de consistência eventual. Para sistemas onde o usuário precisa ver imediatamente o resultado de sua ação, essa inconsistência temporária pode ser problematica.

Vantagens do CQRS

Performance de leitura, escalabilidade independente e lógica de negócio protegida.

A principal vantagem do CQRS e a otimização independente de cada lado. O modelo de leitura pode ser completamente denormalizado, pre-calculado e indexado para maxima performance de consulta. O modelo de escrita pode ser estruturado para maxima consistência e expressividade de negócio sem compromisso com a velocidade de leitura. Além disso, a separação torna o código de negócio mais limpo e testável. Commands com nome expressivo como RealizarPagamento ou CancelarPedido tornam o código mais fácil de entender. Os Command Handlers podem ser testados de forma isolada, sem necessidade de verificar como os dados são lidos ou exibidos.

Cuidados ao aplicar CQRS

Consistência eventual, sincronização e complexidade operacional precisam de atenção.

O principal desafio do CQRS e gerenciar a sincronização entre o modelo de escrita e o modelo de leitura. Se a atualização do modelo de leitura falhar, o usuário pode ver dados desatualizados por mais tempo que o esperado. Isso exige um mecanismo robusto de propagação de eventos e de retry em caso de falha. Outro cuidado e a consistência eventual, que pode ser confusa para usuários acostumados a ver o resultado de suas ações imediatamente. Estrategias como otimistic UI (atualizar a interface antecipadamente, antes da confirmação do servidor) ou mensagens claras sobre o processamento em andamento ajudam a gerenciar essa expectativa. O aumento de complexidade também exige que o time tenha maturidade para manter dois modelos sincronizados ao longo do tempo.

Resumo final

Separar leitura e escrita resolve conflitos fundamentais entre performance e consistência.

CQRS e um padrão que resolve um conflito real: as necessidades de quem escreve e de quem le dados são diferentes, e tentar atender as duas com o mesmo modelo sempre resulta em compromissos. Ao separar os modelos, o sistema pode otimizar cada lado de forma independente, tornando a lógica de negócio mais clara e a performance de leitura muito superior. Não e para todo projeto, mas para sistemas com alta carga de leitura, lógica de negócio complexa e necessidade de escalar de forma independente, o CQRS e uma das ferramentas mais poderosas disponível. O investimento em entender o padrão e implementa-lo corretamente se paga rapidamente em sistemas que crescem.

Tutoriais em Video

Conceitos-chave

Command

Instrução para alterar o estado do sistema, valida regras de negócio, não retorna dados

Query

Consulta pura que não altera estado, retorna dados otimizados para exibição

Command Handler

Processa o Command, aplica lógica de negócio, persiste mudancas e dispara eventos

Query Handler

Consulta o modelo de leitura e retorna o DTO otimizado para a interface

Consistência Eventual

O modelo de leitura e atualizado de forma assíncrona, pode haver breve dessincronia após uma escrita

Read Model

Banco ou tabela denormalizada, otimizada para consultas rápidas, não tem lógica de negócio

CQRS no Instagram

@bytebytego

Reels, CQRS

@bytebytego

CQRS no Facebook

CQRS no X (Twitter)

@mjovanovictech

CQRS na prática: quando separar leitura e escrita

Ver post completo no X →
@mjovanovictech

Command Handlers vs Query Handlers

Ver post completo no X →
@mjovanovictech

CQRS e Event Sourcing: a combinação certa

Ver post completo no X →
@mjovanovictech

Read Model vs Write Model no CQRS

Ver post completo no X →
@mjovanovictech

Consistência eventual no CQRS

Ver post completo no X →
@mjovanovictech

Como implementar CQRS com .NET

Ver post completo no X →

O que devs dizem

Bruno S. ★★★★★

Aplicamos CQRS no sistema de reservas do hotel. As queries do dashboard que antes levavam 3 segundos passaram para menos de 100ms com o modelo de leitura denormalizado. A separação clara entre Commands e Queries também tornou o código muito mais fácil de entender para novos devs.

Carla M. ★★★★☆

O CQRS resolve muito problema mas cria outros. A sincronização dos modelos e a parte mais crítica. Tivemos bugs sutis onde o modelo de leitura ficou desatualizado por mais tempo que o esperado. Precisamos de bom monitoramento e retry robusto para garantir consistência.

Pedro N. ★★★★★

No sistema financeiro que trabalho, o CQRS foi essencial. O modelo de escrita garante integridade dos lançamentos. O modelo de leitura otimizado suporta os relatorios complexos sem afetar as transações críticas. Não consigo imaginar o sistema sem essa separação hoje.