A working tutorial for building a REST API with:
- Axum (web framework)
- SeaORM (type-safe ORM)
- PostgreSQL (database)
- Docker & Compose (local dev + deployment)
A complete, working example that you can run and modify.
For a comprehensive guide with detailed explanations, code walkthroughs, and best practices, check out the full Medium article.
- What You'll Build
- Prerequisites
- Quick Start
- Project Structure
- How It Works
- Development
- Production Deployment
- API Usage
A CRUD API for Users with:
- Axum routes and handlers
- SeaORM entities & queries
- PostgreSQL database
- Docker setup with hot reload
- Docker and Docker Compose
- Git (to clone the repository)
git clone https://github.com/scraiber/axum-seaorm-tutorial.git
cd axum-seaorm-tutorial
docker-compose up --buildThis will:
- Start PostgreSQL database
- Run the initial migration (creates the
userstable) - Build and start the Axum API
- Expose the API at http://localhost:3000 (this may take a few minutes due to compilation, you can check via
docker-compose logs app)
curl http://localhost:3000/
# {"status":"ok"}The API is ready! π
axum-seaorm-tutorial/
βββ src/
β βββ entities/ # SeaORM entity definitions
β β βββ mod.rs
β β βββ user.rs
β βββ handlers.rs # HTTP handlers (business logic)
β βββ main.rs # App entry: router, DB, tracing, server
βββ migrations/
β βββ init.sql # Initial schema (users table, indexes)
βββ Dockerfile # Production image
βββ Dockerfile.dev # Dev image with hot-reload
βββ docker-compose.yml # App + DB orchestration
βββ Cargo.toml # Rust dependencies + metadata
βββ manual.txt # Manual testing commands
βββ README.md # This tutorial
Key files:
src/main.rs- App setup: database connection, routes, middlewaresrc/handlers.rs- HTTP handlers for CRUD operationssrc/entities/user.rs- SeaORM model for theuserstablemigrations/init.sql- Database schemadocker-compose.yml- Development environment setup
- Request hits Axum route (e.g.,
POST /users) - Axum extractors parse JSON and path parameters
- Handler calls SeaORM Entity/ActiveModel functions
- SeaORM generates SQL and talks to PostgreSQL via the DB pool
- Result is serialized to JSON and returned with proper status codes
- tracing logs request/response metadata
The development setup includes hot reload - when you edit files in the src/ directory, the application automatically recompiles and restarts. This is powered by cargo-watch in the Dockerfile.dev.
How it works:
- Edit any file in
src/(likehandlers.rsormain.rs) - Save the file
- The container detects the change and recompiles
- The API restarts with your changes
- No need to manually restart Docker
Example - Test hot reload:
- Edit
src/handlers.rsand change line 53 from:to:status: "ok".to_string(),
status: "ok after hot reload".to_string(),
- Save the file
- Wait a few seconds for recompilation
- Test:
curl http://localhost:3000/ - You should see:
{"status":"ok after hot reload"}
# Start with hot reload
docker-compose up --build
# Stop everything
docker-compose down
# Clean volumes (start fresh DB)
docker-compose down -v# App logs (live)
docker-compose logs -f app
# DB logs
docker-compose logs -f db# Connect to the database
docker-compose exec db psql -U postgres -d axum_seaormPro tip: Keep the app logs open in a terminal while coding. You'll see recompilation messages when you save changes, and any compilation errors will be displayed immediately.
This project includes an optimized production Dockerfile that creates an extremely small and secure container:
Key Features:
- ~10MB total size (vs hundreds of MB for typical containers!)
- Scratch-based: No OS, no shell, no package manager
- Static linking: Self-contained binary with no runtime dependencies
- Maximum security: Minimal attack surface
- Fast startup: Minimal overhead
# Build the production image
docker build -t axum-seaorm:prod -f Dockerfile .
# Check the image size (should be ~10MB!)
docker images axum-seaorm:prod# Start your database first
docker-compose up -d db
# Run the production container
docker run -d \
--name axum-seaorm-prod \
--network axum-seaorm-tutorial_default \
-p 3000:3000 \
-e DATABASE_URL="postgres://postgres:postgres@axum-seaorm-db:5432/axum_seaorm" \
-e RUST_LOG="axum_seaorm=info,tower_http=info" \
axum-seaorm:prodThe API usage is the same as the development environment, see API Usage.
# View logs
docker logs axum-seaorm-prod
# Stop container
docker stop axum-seaorm-prod
# Remove container
docker rm axum-seaorm-prodBase URL: http://localhost:3000
| Method | Endpoint | Description |
|---|---|---|
| GET | / |
Health check |
| POST | /users |
Create user |
| GET | /users |
List users |
| GET | /users/{id} |
Get user by ID |
| PUT | /users/{id} |
Update user |
| DELETE | /users/{id} |
Delete user |
curl http://localhost:3000/
# {"status":"ok"}curl -X POST http://localhost:3000/users \
-H "Content-Type: application/json" \
-d '{"name":"John Doe","email":"[email protected]"}'curl http://localhost:3000/userscurl http://localhost:3000/users/1curl -X PUT http://localhost:3000/users/1 \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe"}'curl -X DELETE http://localhost:3000/users/1 -i
# HTTP/1.1 204 No Content