CQRS é um padrão de arquitetura cada vez mais utilizado em sistemas backend modernos, especialmente onde desempenho e escalabilidade são cruciais. Em essência, o CQRS propõe separar as operações de escrita e leitura de dados, ao contrário do modelo CRUD tradicional, onde ambas são tratadas de maneira igual.
O que é CQRS em termos simples
CQRS (Command Query Responsibility Segregation) divide o sistema em duas partes:
- Command (comandos): responsáveis por alterar dados
- Query (consultas): responsáveis por obter dados
A ideia central é: operações de leitura e escrita não devem usar o mesmo modelo de dados.
No modelo CRUD clássico, uma única camada/modelo trata criação, atualização e leitura. Isso é conveniente, mas com o tempo gera limitações.
O CQRS propõe que:
- comandos não retornam dados (apenas alteram o estado)
- consultas apenas leem dados, sem alterá-los
Exemplo:
- criação de pedido → Command
- listar pedidos → Query
Esse tipo de separação traz benefícios como:
- simplificação da lógica de negócio na escrita
- maior velocidade de leitura
- escalabilidade flexível
A partir disso, surgem dois modelos:
- write model (para escrita)
- read model (para leitura)
Esses modelos podem ser estruturados de formas totalmente diferentes, de acordo com as necessidades do sistema.
Como funciona o CQRS
No núcleo do CQRS está a ideia de que operações de alteração e obtenção de dados são separadas logicamente e arquiteturalmente. Assim, o sistema processa comandos e consultas de maneiras distintas.
Comandos (Command) - alteração de dados
Comandos são ações que modificam o estado do sistema, como:
- criar usuário
- realizar pedido
- atualizar perfil
- remover dados
Características:
- não retornam dados (ou apenas status)
- passam pela lógica de negócio
- podem envolver validações e verificações
Por exemplo: CreateOrderCommand é um comando para criar um pedido. Comandos não servem para buscar dados, apenas para alterar o estado.
Consultas (Query) - obtenção de dados
Consultas são operações de leitura:
- não alteram dados
- retornam resultados (lista, objeto, estatísticas)
- são otimizadas para velocidade
No CQRS, consultas podem usar um modelo de dados separado, ajustado para performance, como bases denormalizadas, cache ou réplicas dedicadas para leitura.
Separação de modelos: write model e read model
No CQRS há dois modelos principais:
- Write Model: usado para comandos
- Read Model: usado para consultas
O Write Model concentra lógica de negócio complexa, é normalizado e foca na integridade dos dados. O Read Model é simplificado, pode ser denormalizado e otimizado para consultas rápidas.
Exemplo em um e-commerce:
- Write Model armazena pedidos, produtos e usuários de forma normalizada
- Read Model pode armazenar visões prontas: "pedidos com nome do usuário e valor total"
Fluxo de dados no sistema
- O usuário envia um comando (ex: criar pedido)
- O sistema processa e salva as alterações
- A Read Model é atualizada (às vezes de forma assíncrona)
- Na próxima consulta, o usuário já recebe os dados atualizados
Devido à natureza assíncrona, pode haver atraso na atualização da Read Model (eventual consistency).
CQRS vs CRUD: qual a diferença?
Para entender o valor do CQRS, é importante compará-lo ao modelo CRUD (Create, Read, Update, Delete), comum na maioria das aplicações.
Como funciona o CRUD
- Modelo único de dados para todas as operações (criar, ler, atualizar, deletar)
- Normalmente: um banco de dados, uma estrutura de modelos, uma camada de lógica
- Exemplo: tabela Users usada tanto para escrita quanto leitura e atualização
É simples e ágil, especialmente no início de um projeto.
Limitações do CRUD
- Lógica de negócio complexa: o modelo fica sobrecarregado com validações e regras
- Problemas de performance: mesmas estruturas para leitura e escrita, mesmo que as demandas sejam diferentes
- Dificuldade para escalar: não é possível otimizar leitura e escrita separadamente
- Consultas complexas: consultas exigem JOINs pesados
Como o CQRS resolve esses problemas
- Escrita via comandos e Write Model
- Leitura via consultas e Read Model
Isso permite:
- usar bancos de dados diferentes
- leitura mais rápida (dados já preparados)
- escrita limpa e lógica
- escalabilidade facilitada
Exemplo: gravar pedido é uma operação complexa e validada, enquanto ler pedidos é rápido (dados já agregados).
Quando a diferença é crítica
- Sistemas de alta carga
- Serviços com muitos acessos de leitura (analytics, dashboards)
- Aplicações de negócio complexas (finanças, e-commerce)
Resumindo:
- CRUD: fácil de implementar, ideal para projetos pequenos
- CQRS: mais complexo, mas mais escalável e adequado para crescimento
CQRS não substitui totalmente o CRUD - é um próximo nível arquitetural, recomendado quando a abordagem simples já não basta.
CQRS na prática: arquitetura e implementação
Separação de bancos de dados
No CQRS simples, pode-se usar um único banco de dados, mas modelos distintos. Em casos avançados, os dados são separados fisicamente:
- Banco de escrita (write database)
- Banco de leitura (read database)
Assim, é possível:
- Otimizar escrita para transações e consistência
- Otimizar leitura para velocidade e escalabilidade
Exemplo:
- Write DB: PostgreSQL
- Read DB: Elasticsearch ou Redis
Diferentes modelos de dados
No CQRS, os modelos de leitura e escrita podem ser muito diferentes:
- Write Model: tabelas normalizadas, estrutura rígida, lógica de negócio
- Read Model: dados agregados, poucas ligações, visões prontas
Assim, a Read Model pode armazenar diretamente o nome do usuário, a lista de pedidos e o valor total, evitando consultas complexas.
Assincronia e "eventual consistency"
Uma das marcas do CQRS é que a sincronização entre modelos não é instantânea:
- O comando altera o Write Model
- O sistema gera um evento
- A Read Model é atualizada (geralmente de forma assíncrona)
Isso resulta em consistência eventual: os dados podem demorar um pouco para serem atualizados nas consultas. O sistema deve estar preparado para possíveis atrasos temporários.
Exemplo de arquitetura CQRS
- API recebe comandos e consultas
- Comandos processados por um Command Handler
- Consultas acessam diretamente a Read Model
- Eventos atualizam a Read Model
Em sistemas mais avançados, podem ser usados brokers de mensagens (Kafka, RabbitMQ), serviços separados para leitura/escrita e cache.
CQRS pode ser implementado parcialmente - muitas vezes, basta separar leitura e escrita na lógica sem envolver múltiplos bancos.
CQRS e Event Sourcing: como se relacionam
O CQRS é frequentemente associado ao Event Sourcing, pois se complementam bem em sistemas complexos.
O que é Event Sourcing
No modelo tradicional, armazena-se apenas o estado atual dos dados. No Event Sourcing, são armazenados eventos que levaram a esse estado:
- usuário depositou R$500
- usuário pagou pedido de R$200
- usuário recebeu bônus de R$700
O estado atual é calculado a partir de todos esses eventos.
Como CQRS funciona com Event Sourcing
- CQRS: separa comandos (alteram dados) e consultas (leem dados)
- Event Sourcing: cada comando gera um evento, que é armazenado em um log
Fluxo típico:
- O comando chega ao sistema
- Um evento é gerado (ex: OrderCreated)
- O evento é armazenado
- A Read Model é atualizada com base nos eventos
Por que usar juntos?
- Histórico de alterações: é possível recuperar qualquer estado anterior
- Auditoria: o que aconteceu e quando
- Flexibilidade nas Read Models: é possível reconstruí-las a partir dos eventos
- Escalabilidade: eventos podem ser distribuídos facilmente entre serviços
Quando faz sentido
- sistemas que exigem histórico detalhado (finanças, logística)
- sistemas distribuídos e complexos
- alta escalabilidade
Mas atenção: isso complexifica bastante a arquitetura e exige experiência.
Nem todo projeto precisa dessa combinação - muitas vezes, só o CQRS já é suficiente.
Vantagens e desvantagens do CQRS
Vantagens
- Escalabilidade: leitura e escrita podem ser escaladas separadamente
- Alta performance: a Read Model pode ser otimizada para consultas (cache, denormalização, visões prontas)
- Flexibilidade arquitetural: uso de tecnologias distintas (SQL para escrita, NoSQL para leitura)
- Lógica de negócio limpa: Write Model focada apenas na integridade dos dados
Desvantagens
- Complexidade de implementação: mais componentes (comandos, handlers, eventos, modelos distintos)
- Consistência eventual: dados podem se atualizar com atraso
- Dificuldade de depuração: assincronia dificulta encontrar erros
- Excesso para projetos simples: pode complicar desnecessariamente sistemas pequenos
CQRS não é "melhor" ou "pior" que CRUD - é uma ferramenta para necessidades específicas.
Quando faz sentido usar CQRS?
Sistemas de alta carga
- dashboards
- analytics
- marketplaces
- redes sociais
O CQRS permite separar a leitura e otimizá-la para velocidade, reduzindo a sobrecarga na base principal.
Lógica de negócio complexa
Se as operações de escrita incluem muitas validações, regras de negócio e dependências, separar via CQRS ajuda a isolar e tornar a lógica mais clara.
Diferentes requisitos para leitura e escrita
- Escrita exige consistência rigorosa
- Leitura exige agilidade e flexibilidade
O CQRS permite que cada necessidade seja atendida da melhor forma.
Sistemas distribuídos e microsserviços
O CQRS se encaixa muito bem em arquiteturas modernas. Para aprofundar o tema, confira o artigo Microsserviços vs Monolito: como escolher a melhor arquitetura em 2025.
- Serviços distintos para escrita e leitura
- Dados disseminados via eventos
- Escalabilidade de partes específicas
Quando CQRS não é necessário
- Projetos pequenos
- Lógica simples
- Baixa carga
- Equipe enxuta
Nesses cenários, o CQRS só aumentaria a complexidade.
Regra de ouro: se o CRUD começa a mostrar limitações por causa da carga ou da complexidade, então é hora de considerar o CQRS.
Como adotar CQRS em um projeto
Implementação gradual
O ideal é não reescrever tudo de uma vez. Comece por:
- separar a lógica de comandos e consultas
- criar handlers (processadores) específicos
- otimizar leitura com DTOs ou visões dedicadas
Mesmo sem infraestrutura avançada, isso já traz resultados.
Separação de lógica sem grandes mudanças
CQRS pode ser adotado apenas no código:
- comandos → classes/métodos separados
- consultas → serviços distintos
Exemplo:
- CreateOrderCommandHandler
- GetOrdersQueryHandler
Isso ajuda a estruturar o código, segmentar responsabilidades e simplificar a manutenção.
Evolução da arquitetura
Com o crescimento do sistema, inclua gradualmente:
- Read Model separada
- Cache
- Processamento assíncrono de eventos
- Message brokers (Kafka, RabbitMQ)
Importante: só adicione camadas se houver necessidade real.
Erros comuns na adoção
- Complexidade prematura: implementar CQRS "por precaução" em sistemas ainda simples
- Ignorar a consistência eventual: não prever atrasos pode causar bugs
- Arquitetura excessiva: adicionar Event Sourcing e brokers sem motivo
- Falta de separação clara entre Command e Query
CQRS é um passo evolutivo, não um ponto de partida. O ideal é adotá-lo em partes.
Conclusão
CQRS é um padrão arquitetural que separa leitura e escrita de dados, tornando o sistema mais ágil, flexível e escalável. É especialmente útil em projetos com alta demanda e lógica de negócio complexa, onde o CRUD tradicional começa a apresentar limites.
No entanto, CQRS não é uma solução universal: para sistemas simples, pode apenas aumentar a complexidade. Use-o de maneira consciente, quando houver problemas reais que esse padrão resolve.
Resumo prático:
- Projeto pequeno → fique com CRUD
- Sistema crescendo em carga e complexidade → considere CQRS
A melhor abordagem é não ter pressa: implemente CQRS gradualmente, começando pelas áreas do sistema onde ele realmente faz diferença.