Skip to content

n1nj4t4nuk1/rust-ddd-skeleton

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

15 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Rust DDD Template

A production-ready Rust workspace template for building microservices following Domain-Driven Design (DDD), CQRS, and Domain Events patterns.

What is this?

This template gives you a working skeleton -- shared infrastructure libraries plus a fully implemented example application (config_api) -- so you can start a new service without spending time on architectural boilerplate.

The project follows Domain-Driven Design with Hexagonal Architecture (Ports and Adapters). In practice, this means the core business logic has zero knowledge of databases, HTTP frameworks, or external services. All coupling flows inward through repository traits and bus abstractions, so you can swap an in-memory store for PostgreSQL (or Actix-Web for another framework) without touching a single line of domain code. This separation makes the codebase easier to test in isolation, reason about under pressure, and extend without fear of breaking unrelated parts.

Everything compiles, all tests pass, and the CI pipeline is already wired. Clone it, rename things, and start writing your domain logic.

Stack

Component Technology
Language Rust 2021
HTTP framework Actix-Web 4
Persistence In-memory (ready to swap for PostgreSQL, Redis, etc.)
Logging tracing + tracing-subscriber
Architecture DDD + Hexagonal (Ports & Adapters)

Architecture overview

The project is organized as a Cargo workspace with two main directories: apps/ contains HTTP services built with Actix-Web, and libs/ contains the business logic organized into bounded contexts. Each bounded context is a self-contained Rust crate with its own domain model, application services, and infrastructure adapters. The shared infrastructure (CQRS buses, event bus, value objects) lives in libs/shared/ and is used by all contexts.

Dependency rule

Domain -> Application -> Infrastructure. Domain never imports infrastructure; coupling is via repository traits only.

Bounded context layout

<context>/
  domain/
    entities/         # Aggregate roots
    value_objects/    # Typed wrappers with validation
    repositories/     # Trait definitions only
    events/           # Domain events + factory functions
    errors/           # Error enums (NotFound, AlreadyExists, Unexpected)
  application/
    <verb>_<noun>/    # One folder per use case
      <noun>_<verb>er.rs              # Domain service
      <verb>_<noun>_command.rs        # Command struct (writes)
      <verb>_<noun>_query.rs          # Query struct (reads)
      <verb>_<noun>_response.rs       # Response envelope: { data?, error? }
      <verb>_<noun>_command_handler.rs / _query_handler.rs
  infrastructure/
    persistence/
      in_memory/      # HashMap-based implementations

Project structure

rust-ddd-skeleton/
β”œβ”€β”€ apps/
β”‚   └── config_api/          # Example REST API β€” key/value config store (port 8080)
β”‚
β”œβ”€β”€ libs/
β”‚   β”œβ”€β”€ config/              # Example bounded context (config_entry CRUD)
β”‚   β”‚   └── src/config_entry/
β”‚   β”‚       β”œβ”€β”€ domain/      # entities, value_objects, repositories, events, errors
β”‚   β”‚       β”œβ”€β”€ application/ # create, find, update, delete use cases
β”‚   β”‚       └── infrastructure/persistence/in_memory/
β”‚   └── shared/
β”‚       β”œβ”€β”€ cqrs/            # CommandBus + QueryBus (TypeId-based dispatch)
β”‚       β”œβ”€β”€ domain-events/   # EventBus + DomainEventSubscriber
β”‚       └── valueobject/     # StringValueObject, ValidationError, typed primitives
β”‚
β”œβ”€β”€ tests/
β”‚   β”œβ”€β”€ apps/config_api/     # E2E tests (HTTP -> bus -> repo)
β”‚   └── libs/config/         # Unit tests (mocks, mothers, domain services)
β”‚
β”œβ”€β”€ docs/                    # Architecture documentation
β”œβ”€β”€ docker-compose.yml
β”œβ”€β”€ Makefile                 # Root Makefile (delegates to per-app Makefiles)
└── Cargo.toml               # Workspace root

Quick start

Prerequisites: Rust stable (2021 edition), Docker (optional)

Build

make build               # Release build (all apps)
make dev/build            # Dev build
make config_api/build     # Release build for config_api only

Test

make test                 # All tests (unit + e2e)
make test/unit            # Unit tests only
make test/e2e             # All e2e suites
make config_api/test/e2e  # E2E tests for config_api

Tests do not require a running database -- the e2e suites use the in-memory repository by default.

Run

make config_api/run       # Start config_api on port 8080

Log level defaults to info. Override with RUST_LOG:

RUST_LOG=debug make config_api/run

Creating a new bounded context

  1. Copy libs/config/ as libs/my_domain/
  2. Rename every occurrence of config_entry -> my_entity and ConfigEntry -> MyEntity
  3. Add libs/my_domain to [workspace] members in the root Cargo.toml
  4. Add the lib as a dependency in your app's Cargo.toml

See docs/ADDING_A_BOUNDED_CONTEXT.md for a step-by-step guide.

Creating a new app

  1. Copy apps/config_api/ as apps/my_api/
  2. Update the Cargo.toml package name and dependencies
  3. Add apps/my_api to the workspace
  4. Add Makefile targets and CI jobs

See docs/ADDING_AN_APP.md for details.

Documentation

The docs/ directory contains detailed guides for understanding and extending the system. Start with ARCHITECTURE.md for the big picture, then explore specific topics as needed.

Document Description
ARCHITECTURE.md System design, layer diagram, key patterns, and conventions
PROJECT_STRUCTURE.md Full annotated file tree with the purpose of every directory
CQRS.md How commands and queries flow through the system
DOMAIN_EVENTS.md Event-driven communication between bounded contexts
TESTING.md Test strategy, mocks, Object Mother pattern, CI pipeline
ADDING_A_BOUNDED_CONTEXT.md Step-by-step guide to adding a new domain module
ADDING_AN_APP.md Step-by-step guide to adding a new HTTP service

Make targets

Target Description
make build Release build (all apps)
make dev/build Dev build
make config_api/build Release build for config_api
make test Run all tests
make test/unit Unit tests only
make test/e2e All e2e tests
make config_api/test/e2e E2E tests for config_api
make config_api/run Run config_api locally
make format Run cargo fmt
make audit Security audit via cargo-audit
make docker/up Start containers via Docker Compose
make docker/down Stop containers

License

MIT

About

πŸ¦€ Template of a Rust application using Domain-Driven Design and Command Query Response Segregation principles.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors