Tideway
Tideway is a batteries-included Rust web framework built on Axum and Tokio. It provides opinionated defaults for building SaaS applications quickly while maintaining the performance and flexibility you expect from Rust. The primary CLI path and tested scaffolds target backend/API workflows; frontend helpers are advanced and currently Vue-focused.
Features
- Fast & Reliable: Built on Axum and Tokio for maximum performance
- Batteries Included: Pre-configured logging, tracing, error handling, and health checks
- Modular Architecture: Organize your application into reusable route modules
- Trait-Based Extensibility: Swap database, cache, session, and email implementations easily
- Production Middleware: Compression, security headers, timeouts, and Prometheus metrics
- Request Validation: Type-safe validation with custom validators and extractors
- Enhanced Error Handling: Rich error responses with context, IDs, and dev-mode stack traces
- Background Jobs: In-memory and Redis-backed job queues with retry logic
- Email: SMTP and console mailers with support for Resend, SendGrid, and more
- Developer Experience: Alba-style testing, test fixtures, dev request dumping, and richer dev errors
- WebSocket Support: Real-time communication with connection management and broadcasting
- Type-Safe: Full Rust type safety with excellent error messages
- Production Ready: Graceful shutdown, request IDs, and structured logging out of the box
- Developer Friendly: Simple, intuitive API with sensible defaults
Feature Matrix
Feature flags are opt-in unless marked Default.
| Feature | Module | Docs | Example | Notes |
|---|---|---|---|---|
feature-gate-errors |
— | — | — | Optional compile-time errors for missing features |
feature-gate-warnings |
— | — | — | Optional warnings for missing features |
macros |
tideway-macros / openapi |
docs/openapi.md |
examples/api_macro_example.rs |
Default |
database |
database |
docs/database_traits.md |
examples/custom_database.rs |
Default (SeaORM) |
database-sqlx |
database |
docs/database_traits.md |
— | Experimental placeholder only; not implemented yet |
openapi |
openapi |
docs/openapi.md |
examples/api_macro_example.rs |
Default |
validation |
validation |
docs/validation.md |
examples/validation_example.rs |
— |
metrics |
metrics |
README.md#built-in-middleware |
tests/metrics_integration_test.rs |
— |
cache |
cache |
docs/caching.md |
examples/redis_cache.rs |
— |
cache-redis |
cache |
docs/caching.md |
examples/redis_cache.rs |
— |
sessions |
session |
docs/sessions.md |
examples/sessions_example.rs |
— |
jobs |
jobs |
docs/background_jobs.md |
examples/background_jobs.rs |
— |
jobs-redis |
jobs |
docs/background_jobs.md |
— | — |
websocket |
websocket |
docs/websockets.md |
examples/websocket_chat.rs |
— |
email |
email |
docs/email.md |
examples/email_example.rs |
— |
auth |
auth |
docs/auth.md |
examples/seaorm_auth.rs |
— |
auth-mfa |
auth::mfa |
docs/auth.md |
examples/seaorm_auth.rs |
— |
auth-breach |
auth::breach |
docs/auth.md |
— | — |
test-auth-bypass |
auth |
docs/auth.md |
tests/auth_integration_test.rs |
Tests only |
billing |
billing |
docs/billing.md |
— | — |
billing-seaorm |
billing |
docs/billing.md |
— | — |
test-billing |
billing |
docs/billing.md |
tests/ |
Tests only |
organizations |
organizations |
docs/organizations.md |
— | — |
organizations-seaorm |
organizations |
docs/organizations.md |
— | — |
organizations-billing |
organizations |
docs/organizations.md |
— | — |
test-organizations |
organizations |
docs/organizations.md |
tests/ |
Tests only |
test-containers |
testing |
docs/testing.md |
docs/testing.md |
Optional container-backed postgres for integration tests |
admin |
admin |
docs/admin.md |
— | — |
Quick Start
CLI (Fastest Start)
Use the CLI to scaffold the recommended API-first Tideway app:
Then visit http://localhost:8000/health.
If OpenAPI is enabled, visit http://localhost:8000/swagger-ui.
The default API-first scaffold uses SQLite for local development.
If you want local Postgres instead, add --with-docker and start it with docker compose up -d.
It also seeds a sample todo resource that already follows the recommended entity -> repository -> service path, with pagination and q search on the list route.
Canonical next step: add your first DB-backed resource with
tideway resource <name> --wire --db --repo --service --paginate --search,
then run tideway migrate.
Optional sanity check: run tideway doctor if you want a project/setup audit before you keep building.
When no flags are provided, the CLI will prompt you interactively (similar to Vite).
The first interactive screen promotes api, saas, and worker; advanced paths like minimal, backend presets, and custom feature picking are still available, but one step deeper.
Use --no-prompt for the same API-first defaults in CI/non-interactive runs.
Use --preset minimal only when you explicitly want the lightweight starter.
For preset variants (api, saas, worker), see docs/cli.md.
Frontend generate / setup helpers are advanced and currently intended for existing Vue apps, not the primary onboarding path.
Agent Quickstart
If you're using coding agents (Codex, Claude Code, OpenCode), start here:
- Use
tideway new my_appand follow the wizard (fastest path). - Add resources with
tideway resource <name> --wire --db --repo --service --paginate --search. - Run
tideway dev --fix-envto boot with env + migrations.
Agent-friendly flags:
--jsonemits machine-readable JSON lines.--planshows planned file operations without writing.
Project-specific guidance lives in SKILLS.md.
Getting Started Guide
Read the full walkthrough at docs/getting_started.md.
For module composition contracts, see docs/module_contracts.md.
For recovery from common CLI failures, see docs/error_recovery.md.
CLI Reference
See docs/cli.md for command examples.
Maintainers: see docs/maintainer_verify.md for scripts/verify.sh troubleshooting.
Common tideway new flags:
| Flag | Example | Purpose |
|---|---|---|
--preset |
--preset api |
Apply a preset scaffold |
--features |
--features auth,database |
Enable crate features |
--with-config |
--with-config |
Generate config.rs / error.rs |
--with-docker |
--with-docker |
Add docker-compose.yml |
--with-ci |
--with-ci |
Add GitHub Actions workflow |
--with-env |
--with-env |
Generate .env.example |
--no-prompt |
--no-prompt |
Disable interactive prompts |
Library Usage (Optional Advanced)
If you prefer integrating Tideway directly as a dependency (without CLI scaffolding):
Installation
Add Tideway to your Cargo.toml:
[]
= "0.7.19"
= { = "1.48", = ["full"] }
Hello World
use ;
async
Manual Serving
If you want to serve Tideway with axum::serve, use the middleware-aware router:
use App;
use TcpListener;
async
Note: into_router() does not apply the full middleware stack. Use
into_router_with_middleware() when you need the raw router, and
into_make_service_with_connect_info() when you want manual serving to match
serve() including client address wiring.
Run your app:
Visit http://localhost:8000/health to see the built-in health check.
Core Concepts
Canonical onboarding path:
tideway new my_apptideway devtideway resource <name> --wire --db --repo --service --paginate --searchtideway migrate
For advanced/manual composition patterns, see docs/module_contracts.md.
1. Application Structure
Tideway applications are organized into layers:
src/
├── main.rs # Application entry point
├── lib.rs # Library exports
└── routes/ # Your application routes
└── ...
When using Tideway as a dependency, import from the tideway crate:
use ;
For onboarding, prefer one composition style:
- define modules with
module! - register them with
App::register_module(...) - let the scaffold own
main.rswiring unless you intentionally need an advanced/manual setup
For advanced composition variants, manual OpenAPI composition, or trait-based module contracts,
see docs/advanced_composition.md, docs/module_contracts.md, and docs/openapi.md.
Quick guards with ensure!:
use ensure;
ensure!;
ensure!;
See docs/error_handling.md for more examples.
Testing helpers (HTTP):
use get as test_get;
use ;
let app = new.register_module.into_router;
test_get
.execute
.await
.assert_ok;
See docs/testing.md for more helpers.
2. Configuration
Configure your application with environment variables or code:
use ConfigBuilder;
let config = new
.with_host
.with_port
.with_log_level
.with_max_body_size // 50MB global limit
.from_env // Override with TIDEWAY_* env vars
.build?; // Returns Result<Config> - validates configuration
Environment Variables:
TIDEWAY_HOST- Server host (default: 0.0.0.0)TIDEWAY_PORT- Server port (default: 8000)TIDEWAY_LOG_LEVEL- Log level (default: info)TIDEWAY_LOG_JSON- Enable JSON logging (default: false)TIDEWAY_MAX_BODY_SIZE- Maximum request body size in bytes (default: 10MB)RUST_LOG- Standard Rust log filter
3. Route Modules
Canonical module style:
module!;
let app = new.register_module;
Use this style for onboarding and examples.
For trait-based RouteModule implementations, grouped route syntax, mixed module lists, optional modules,
or iterator registration, see docs/module_contracts.md and docs/advanced_composition.md.
4. Error Handling
Use TidewayError for consistent error responses:
use ;
use Json;
async
Error Types:
TidewayError::not_found(msg)- 404 Not FoundTidewayError::bad_request(msg)- 400 Bad RequestTidewayError::unauthorized(msg)- 401 UnauthorizedTidewayError::forbidden(msg)- 403 ForbiddenTidewayError::internal(msg)- 500 Internal Server ErrorTidewayError::service_unavailable(msg)- 503 Service Unavailable
Quick Guards with ensure!:
use ;
Enhanced Error Responses: All errors automatically return JSON responses with:
- Error message
- Unique error ID for tracking
- Optional details and context
- Field-specific validation errors
- Stack traces (in dev mode when enabled)
5. Request Validation
Validate request data with type-safe extractors:
use ;
use Validate;
use Deserialize;
async
async
Custom Validators:
validate_uuid()- UUID v4 validationvalidate_slug()- Slug format validationvalidate_phone()- Phone number validationvalidate_json_string()- JSON string validationvalidate_duration()- Duration format (30s, 5m, 1h, 2d)
6. Response Helpers
Use ApiResponse for standardized JSON responses:
use ;
use Json;
async
async
Response Formats:
// Success response
// Paginated response
// Created response (201)
7. Health Checks
The built-in /health endpoint is automatically available. Customize health checks:
use ;
use Pin;
;
8. Testing
Tideway provides Alba-style testing utilities for easy HTTP endpoint testing:
use ;
use fake;
async
async
9. Development Mode
Enable development mode for request dumping and richer debugging responses:
use ;
let config = new
.with_dev_config
.build?; // Returns Result<Config> - validates configuration
with_request_dumper(true) is applied by Tideway's middleware stack.
with_stack_traces(true) adds stack traces to normal TidewayError responses during dev-mode requests.
Environment Variables:
TIDEWAY_DEV_MODE- Enable dev mode (default: false)TIDEWAY_DEV_STACK_TRACES- Include stack traces (default: false)TIDEWAY_DEV_DUMP_REQUESTS- Enable request dumper (default: false)TIDEWAY_DEV_DUMP_PATH- Path pattern to dump (default: all)
10. Logging & Tracing
Structured logging is enabled by default:
async
All HTTP requests are automatically logged with:
- Request ID (x-request-id header)
- Method and URI
- Response status
- Response time in milliseconds
Examples
Tideway includes comprehensive examples demonstrating real-world usage:
Complete SaaS Application
examples/saas_app.rs - Full-featured SaaS app with:
- Database integration
- JWT authentication
- Rate limiting
- CORS configuration
- OpenAPI documentation
- Health checks
Custom Database Implementation
examples/custom_database.rs - Implementing a custom DatabasePool:
Redis Caching
examples/redis_cache.rs - Using Redis for caching:
Session Management
examples/sessions_example.rs - Session management examples:
Authentication Flow
examples/auth_flow.rs - Complete auth implementation:
- User registration
- Login with JWT
- Protected routes
- Public endpoints
Testing Guide
examples/testing_example.rs - Testing patterns:
- Alba-style HTTP testing
- Database testing with TestDb
- Error case testing
Validation Example
examples/validation_example.rs - Request validation:
- ValidatedJson extractor
- ValidatedQuery extractor
- Custom validators
- Field-level error handling
Development Mode
examples/dev_mode.rs - Development tools:
- Enhanced error responses
- Request/response dumper
- Stack trace debugging
Production Configuration
examples/production_config.rs - Production setup:
- Environment-based config
- Logging setup
- Graceful shutdown
- Health monitoring
WebSocket Chat
examples/websocket_chat.rs - Real-time chat with rooms:
- WebSocket connection handling
- Room management
- Broadcasting messages
- User join/leave notifications
WebSocket Notifications
examples/websocket_notifications.rs - Real-time notifications:
- Server-to-client push notifications
- User-specific channels
- Integration with background jobs
Architecture
Tideway follows a layered architecture:
┌─────────────────────────────────┐
│ HTTP Layer │
│ (Routes, Middleware, Handlers) │
├─────────────────────────────────┤
│ Application Core │
│ (Business Logic, Services) │
├─────────────────────────────────┤
│ Infrastructure │
│ (Database, Cache, External APIs)│
└─────────────────────────────────┘
Key Components:
- App: Main application structure with routing and middleware
- AppContext: Dependency injection container for shared state (database, cache, sessions)
- RouteModule: Trait for modular route organization
- Config: Environment-aware configuration
- TidewayError: Unified error handling
- ApiResponse: Standardized JSON responses
Trait-Based Components:
- DatabasePool: Abstract database connection pooling (SeaORM, SQLx placeholder)
- Cache: Key-value caching abstraction (in-memory, Redis)
- SessionStore: Session management abstraction (in-memory, cookie-based)
- JobQueue: Background job processing (in-memory, Redis)
- ConnectionManager: WebSocket connection management (rooms, broadcasting)
Built-in Middleware
All requests automatically include:
- Request ID: Unique UUID for request tracking
- Body Size Limit: Global default limit (10MB) to prevent DoS attacks
- Tracing: Structured logging with request/response details
- Error Handling: Automatic error to JSON response conversion
- CORS: Configurable CORS support (disabled by default for security)
- Rate Limiting: Per-IP and global rate limiting (health endpoints excluded)
- Compression: Gzip/Brotli response compression
- Security Headers: HSTS, CSP, X-Frame-Options, and more
- Timeout: Configurable request timeouts
- Request Logging: Structured request/response logging
- Metrics: Prometheus metrics collection (optional, uses route templates when available)
Dependency Injection
Tideway provides AppContext for dependency injection:
use ;
use Arc;
let db_pool = new;
let cache = new;
let sessions = new;
let context = builder
.with_database
.with_cache
.with_sessions
.build;
Use in your handlers:
use State;
use AppContext;
async
Database, Cache & Sessions
Database
Tideway exposes a database abstraction through the DatabasePool trait, but the built-in production path today is SeaORM:
- SeaORM (default): Full-featured ORM with migrations
- SQLx (
database-sqlx): Experimental placeholder only (not implemented yet)
use ;
let pool = from_config.await?;
let pool: = new;
Cache
Multiple cache backends supported:
- In-Memory: Fast HashMap-based cache (default)
- Redis: Distributed caching with
cache-redisfeature
use ;
use CacheExt; // Provides get<T>() and set<T>()
let cache: = new;
// Type-safe operations
cache.set.await?;
let user: = cache.get.await?;
Sessions
Session management with multiple storage backends:
- In-Memory: For development/testing
- Cookie-Based: Encrypted cookie sessions
use ;
use ;
let store: = new;
let mut session = new;
session.set;
store.save.await?;
See docs/database_traits.md, docs/caching.md, and docs/sessions.md for detailed documentation.
Testing
Tideway applications are easy to test, and include Alba-style helpers:
use ;
use fake;
async
For Alba-style host bootstrapping and dependency overrides, prefer
TestHost::builder(app) for prebuilt apps and TestHost::bootstrap() when the
spec needs config or environment overrides; see docs/testing.md.
See docs/testing.md and examples/testing_example.rs for more patterns.
Run tests:
Roadmap
Completed ✅
- Rate limiting middleware
- CORS configuration
- OpenAPI/Swagger generation
- Request validation support
- Compression middleware
- Security headers middleware
- Request/response logging
- Timeout middleware
- Prometheus metrics
- Global request body size limit (DoS protection)
- Trait-based database abstraction (SeaORM)
- Trait-based caching (in-memory, Redis)
- Trait-based session management (in-memory, cookies)
- Dependency injection with AppContext
- Custom validators (UUID, slug, phone, JSON, duration)
- ValidatedQuery and ValidatedForm extractors
- Enhanced error handling (context, IDs, dev-mode stack traces)
- Alba-style testing utilities
- Test fixtures and fake data helpers
- Database testing improvements (seed, reset, transactions)
- Development mode configuration, richer error responses, and request dumper
- Response helpers (paginated, created, no_content)
- WebSocket support (connection management, rooms, broadcasting)
In Progress 🚧
- SQLx database backend implementation
Planned 📋
- CLI tool for scaffolding
- Deployment guides
- Additional cache backends (Memcached)
- Additional session backends (database-backed)
Performance
Tideway adds minimal overhead compared to raw Axum. Benchmarks are available in the benches/ directory.
Run benchmarks:
See benches/README.md for detailed performance metrics.
Contributing
Contributions are welcome! This is currently in early development.
License
MIT
Acknowledgments
Built with:
Start building your SaaS with Tideway today!