Axum Modular Project Structure
Multi-crate workspace for large projects. Separate crates for domain, API, and infrastructure.
Project Directory
myproject/
Cargo.toml
Workspace manifest
Cargo.lock
.gitignore
README.md
.env
.env.example
Dockerfile
Multi-stage build
docker-compose.yml
crates/
Workspace members
api/
HTTP layer
Cargo.toml
src/
lib.rs
routes/
handlers/
middleware/
extractors/
domain/
Business logic (no deps)
Cargo.toml
src/
lib.rs
user/
User aggregate
order/
Order aggregate
error.rs
Domain errors
infrastructure/
External services
Cargo.toml
src/
lib.rs
db/
Database repos
cache/
Redis or in-memory
queue/
Message queue
shared/
Common types
Cargo.toml
src/
lib.rs
config.rs
telemetry.rs
Tracing setup
migrations/
001_initial.sql
bin/
Entry points
server.rs
Main API server
worker.rs
Background jobs
migrate.rs
DB migrations CLI
Why This Structure?
Cargo workspaces let you split a project into multiple crates with shared dependencies. The domain crate has zero external dependencies—pure Rust types and logic. The api crate handles HTTP, infrastructure implements storage. This enforces boundaries at compile time.
Key Directories
- crates/api/-Axum server, routes, handlers, middleware
- crates/domain/-Pure business logic, no framework deps
- crates/infrastructure/-Database, cache, queue implementations
- crates/shared/-Config, telemetry, common utilities
- bin/-Binary entry points for different services
Workspace Configuration
# Cargo.toml (workspace root)
[workspace]
members = ["crates/*"]
resolver = "2"
[workspace.dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
sqlx = { version = "0.8", features = ["postgres"] }
Getting Started
mkdir myproject && cd myproject- Create workspace
Cargo.toml cargo new crates/api --libcargo new crates/domain --libcargo run --bin server
When To Use This
- Large codebases with multiple domains
- Team of 5+ developers
- Need compile-time boundary enforcement
- Multiple binaries (server, worker, CLI)
- Long-lived projects (2+ years)
Trade-offs
- Complex setup-Workspace config and crate dependencies take time
- More ceremony-Cross-crate imports require careful planning
- Slower iteration-Changes may rebuild multiple crates
- Overkill for small projects-Single-crate is faster for prototypes
Best Practices
- Domain crate should never import api or infrastructure
- Use traits in domain, implement in infrastructure
- Shared crate for cross-cutting concerns only
- Keep bin/ files minimal—just wire and run
- Use workspace.dependencies for version consistency