Architecture


  • CQRS
  • Hexagonal
  • Microservice
  • ...

CQRS

Kacper Walczak · 06-05-2024

Lets learn how to use CQRS in your project.

What is CQRS?

CQRS stands for Command Query Responsibility Segregation.

It is a design pattern that separates the read and write operations of a data source.

Additionally, it allows to use separate Database for reading and writing(what can improve scaling by a lot).

CQRS schema with events and database for writing and reading

When to use?

  • Your business logic is going to evolve/change often
  • Your model requires to be read with multiple data projections
  • It is required to optimize reads over writes and vice-versa

When to avoid?

  • You are building CRUD, don't use there CQRS
  • You are starting new project and you are lacking domain experts
  • You don't want to introduce any reactive patterns(events/commands/queries needs to be handled and emited by some bus)

Examples

COMMAND

  • ApplySalaryIncrease:
    class ApplySalaryIncreaseAt extends Command {
        data: {employeeID: string, increasedSalaryValue: number}
        validAt: Date
        timestamp = new Date()
        version = 1
     
        constructor(employeeID: string, increasedSalaryValue: number, validAt: Date) {
            super({employeeID, increasedSalaryValue})
            this.validAt = validAt
        }
    }
    And handler for this command:
    @CommandHandler(ApplySalaryIncreaseAt)
    class ApplySalaryIncreaseAtHandler implements ICommandHandler<ApplySalaryIncreaseAt> {
        constructor(private repository: SalariesRepository, private politic: SalariesPolitic) {}
     
        async execute(command: ApplySalaryIncreaseAt): Promise<void> {
            await this.politic.isValidSalaryIncreaseOrThrow({...command.data, validAt: command.validAt})
            const accountant = this.repository.getEmployeeAccountant(command.data.employeeID)
            await accountant.increaseSalaryAt({
                newValue: command.data.increasedSalaryValue,
                validSince: command.validAt
            })
        }
    }

QUERY

  • GetLastEmployeeSalaryIncrease:
    class GetLastEmployeeSalaryIncrease extends Query {
        data: {employeeID: string}
     
        constructor(employeeID: string) {
            super({ employeeID })
        }
    }
    And handler for this query:
    @CommandHandler(GetLastEmployeeSalaryIncrease)
    class GetLastEmployeeSalaryIncreaseHandler implements IQueryHandler<GetLastEmployeeSalaryIncrease> {
        constructor(private repository: SalariesRepository) {}
     
        async execute(query: GetLastEmployeeSalaryIncrease): Promise<any[]> {
            return this.repository.getEmployeeLastSalaryIncrease(query.data.employeeID)
        }
    }

EVENT

  • SalaryIncreased:
    class SalaryIncreasedEvent {
        constructor(public readonly employeeID: string) {}
    }
    Call this event after some logic with:
    this.eventBus.publish(new SalaryIncreasedEvent(employeeID));
    And handler for this event:
    @EventsHandler(SalaryIncreasedEvent)
    class SalaryIncreasedEventHandler implements IEventHandler<SalaryIncreasedEvent> {
        constructor(private repository: SalariesRepository, private email: EmailSender) {}
     
        async handle(event: SalaryIncreasedEvent): Promise<void> {
            // do job here, like: 
            //   const {employee, accountant, changes} = await repository.fetchLastEmployeeChanges(event.employeeID)
            //   await email.notify(accountant, {employee, changes})
        }
    }

Next

In this article we have learned how to and when utilize CQRS architecture.

Check Web Architectures to learn more about different architectures.

Check next:

READ

Latest readings

  • Readings are sites which will help you with detailed

  • information about given topic. Read latest ones from Learn.

AI

06-03-2026

Local Voice Assistant with Ollama
  • Build your own local voice assistant powered by Ollama.

AI

06-03-2026

AI YouTube Thumbnail Generator
  • Generate YouTube thumbnails with FastAPI and Ollama.

Architecture

05-09-2024

Graph DB usage comparison
  • Compare Neo4j and Tigergraph databases, which is easier to work with, etc.