A compile-time SQL type generator written in Rust that generates type-safe code for TypeScript and Python.
- Introduction
- Core Features
- Why Stratus
- Performance Comparison
- Installation & Building
- Quick Start
- Schema Definition
- TypeSQL Query Syntax
- Code Generation
- Command-Line Tools
- Project Structure
- Supported Databases
- Advanced Features
- Best Practices
- Contributing
- FAQ
Stratus is a compile-time SQL type generator inspired by sqlc, but with multi-language support (TypeScript and Python). By analyzing database schema and SQL queries at compile time, it generates precise TypeScript/Python type definitions, eliminating runtime type errors.
- 🎯 Compile-time Type Generation: Analyzes SQL at compile time to generate precise type definitions
- 🔄 JOIN Type Inference: Automatically infers result types for JOIN queries, handling column name conflicts
- 🌐 Multi-language Support: Supports both TypeScript and Python
- 📦 Database-agnostic: Uses JSON Schema to define database structure
- ⚡ Zero Runtime Overhead: Generated types are pure static types with no runtime dependencies
- 🔧 Flexible Configuration: Customize generation behavior via CLI or config file
- 🚀 Database Sync: Supports
db pushanddb pullto sync database schema - 📋 Migration Management: Built-in Prisma-style migration commands
| Feature | Stratus | Traditional ORM |
|---|---|---|
| Type Precision | Compile-time exact generation | Runtime inference, may be inaccurate |
| Performance | Zero overhead, direct SQL execution | Additional query building overhead |
| SQL Control | Full control, generated types only provide type safety | ORM may generate non-optimal SQL |
| Learning Curve | Simple, just write SQL | Need to learn ORM API |
| Migration Complexity | No query modifications needed | May need to rewrite queries |
- Type Safety: Catch type errors at compile time, not runtime
- Developer Efficiency: IDE autocomplete and type checking
- Maintainability: Types synchronized with actual database structure
- Simplicity: Just write SQL, no need to learn complex ORM APIs
| Metric | Stratus | Prisma ORM | Drizzle ORM | TypeORM |
|---|---|---|---|---|
| Runtime Overhead | Zero | Medium | Low | Variable |
| Bundle Size | ~0KB (types only) | Large | ~7.4KB | Medium |
| Cold Start Time | Extremely fast | 9x improvement after optimization | Extremely fast | Medium |
| Type Check Speed | Fast (compile-time) | Fast | Slower | Medium |
| Query Execution | Native SQL | Runtime engine | Lightweight build | Runtime build |
PostgreSQL Query Performance (Median, 500 iterations)
| Query Type | Prisma ORM | Drizzle ORM | TypeORM |
|---|---|---|---|
| Find All | 8.00ms | 23.09ms | 5.24ms |
Source: https://benchmarks.prisma.io/
┌─────────────────────────────────────────────────────────────────────────────┐
│ Performance Comparison Matrix │
├─────────────────┬──────────────┬──────────────┬──────────────┬──────────────┤
│ Metric │ Stratus │ Prisma │ Drizzle │ TypeORM │
├─────────────────┼──────────────┼──────────────┼──────────────┼──────────────┤
│ Runtime Overhead│ ★★★★★ │ ★★☆☆☆ │ ★★★☆☆ │ ★★☆☆☆ │
│ Bundle Size │ ★★★★★ │ ★☆☆☆☆ │ ★★★★☆ │ ★★★☆☆ │
│ Cold Start │ ★★★★★ │ ★★★☆☆ │ ★★★★★ │ ★★★☆☆ │
│ Type Safety │ ★★★★★ │ ★★★★★ │ ★★★★☆ │ ★★★☆☆ │
│ SQL Control │ ★★★★★ │ ★★☆☆☆ │ ★★★★☆ │ ★★★☆☆ │
│ DX │ ★★★★☆ │ ★★★★★ │ ★★★★☆ │ ★★★☆☆ │
└─────────────────┴──────────────┴──────────────┴──────────────┴──────────────┘
★ = 5 stars maximum
-
Compile-time Code Generation
- SQL executes directly, no runtime parsing
- No ORM query building overhead
- Type information determined at compile time
-
Zero Runtime Dependencies
// Stratus: Generated code const result = await pool.query('SELECT * FROM users WHERE id = $1', [1]); // ORM: Runtime query building const result = await prisma.user.findMany({ where: { id: 1 }, select: { id: true, email: true } });
-
Minimal Bundle Size
- Stratus only generates type definitions
- Prisma includes runtime engine (~several MB)
- Drizzle core ~7.4KB
-
Optimal SQL Execution
- Developers write SQL with precise control
- ORM may generate non-optimal SQL
- No ORM query transformation overhead
| Tool | Cold Start | Reason |
|---|---|---|
| Stratus | Extremely fast | No runtime dependencies, just load DB driver |
| Prisma | Medium | 9x optimized, still needs query engine |
| Drizzle | Extremely fast | Small core bundle |
- Prisma Official Benchmarks: https://benchmarks.prisma.io/
- Drizzle Official Benchmarks: https://orm.drizzle.team/benchmarks
- GitHub Comparison Repo: https://github.com/prisma/orm-benchmarks
# 1. Ensure connection pooling
export DATABASE_URL="postgresql://user:pass@host:5432/db?pool_size=10"
# 2. Use compilation optimization
cargo build --release
# 3. Enable zero-copy (if supported)| Scenario | ORM Overhead | Stratus Overhead | Improvement |
|---|---|---|---|
| Simple Query | ~5-10ms | ~0.5-1ms | ~10x |
| Complex JOIN | ~10-20ms | ~1-2ms | ~10x |
| Batch Insert | ~20-50ms | ~2-5ms | ~10x |
# Run Stratus benchmarks
stratus benchmark --iterations=500
# Compare with other ORMs (requires separate installation)
npm install prisma @prisma/client
node prisma-benchmark.jsStratus generates pure SQL and can be monitored with standard tools:
-- Use EXPLAIN ANALYZE to analyze query plans
EXPLAIN ANALYZE SELECT * FROM users WHERE id = $1;
-- PostgreSQL pg_stat_statements
SELECT query, calls, mean_time FROM pg_stat_statements
ORDER BY mean_time DESC LIMIT 10;- Rust: 1.70.0 or higher
- Cargo: Rust package manager
- OS: macOS, Linux, Windows
# Clone the repository
git clone https://github.com/yourusername/stratus.git
cd stratus
# Debug build
cargo build
# Release build (recommended for production)
cargo build --release
# Run tests
cargo test
# Install to system
cargo install --path .# Check version
stratus --version
# View help
stratus --helpCreate schema.json:
{
"version": "1",
"dialect": "postgresql",
"tables": {
"users": {
"columns": {
"id": {
"name": "id",
"type": "bigint",
"isPrimaryKey": true,
"isNotNull": true,
"identity": { "always": true }
},
"email": {
"name": "email",
"type": "varchar",
"size": 255,
"isNotNull": true
},
"username": {
"name": "username",
"type": "varchar",
"size": 50,
"isNotNull": true
}
}
},
"orders": {
"columns": {
"id": {
"name": "id",
"type": "bigint",
"isPrimaryKey": true,
"isNotNull": true,
"identity": { "always": true }
},
"user_id": {
"name": "user_id",
"type": "bigint",
"isNotNull": true
},
"order_number": {
"name": "order_number",
"type": "varchar",
"size": 50,
"isNotNull": true
},
"total_amount": {
"name": "total_amount",
"type": "decimal",
"size": 10,
"scale": 2
}
}
}
}
}Create queries.sql:
# name: GetUser :one id: number
SELECT * FROM users WHERE id = $1;
# name: ListUsers :many
SELECT * FROM users ORDER BY created_at DESC;
# name: GetUserWithOrders :many id: number
SELECT users.*, orders.* FROM users JOIN orders ON users.id = orders.user_id WHERE users.id = $1;
# name: CreateUser :one email: string username: string
INSERT INTO users (email, username) VALUES ($1, $2) RETURNING id;# Generate TypeScript types
stratus compile --input queries.sql --schema schema.json --language ts
# Generate Python types
stratus compile --input queries.sql --schema schema.json --language py
# Generate types only (without query functions)
stratus gen-types --schema schema.json --language tsTypeScript Example:
import { getUser, listUsers, getUserWithOrders } from './types';
// Type-safe call
const user = await getUser({ id: 1 });
console.log(user.email); // Autocomplete, type-safe
console.log(user.username); // Autocomplete
// JOIN query result type
const orders = await getUserWithOrders({ id: 1 });
for (const order of orders) {
// Automatically handles column name conflicts
console.log(order.email); // email from users table
console.log(order.order_number); // order_number from orders table
console.log(order.orders_id_1); // Conflict resolved, renamed to orders_id_1
}Python Example:
from types import get_user, list_users, GetUserWithOrdersResult
import asyncio
async def main():
# Type-safe call
user = await get_user(id=1)
print(user.email) # Type checking
print(user.username)
# JOIN query results
orders = await get_user_with_orders(id=1)
for order in orders:
print(order.email)
print(order.order_number)
asyncio.run(main()){
"version": "1",
"dialect": "postgresql",
"tables": { ... },
"enums": { ... }
}| Field | Required | Description |
|---|---|---|
version |
Yes | Schema version number, currently "1" |
dialect |
No | Database dialect: postgresql, mysql, sqlite |
tables |
Yes | Table definitions object |
enums |
No | Enum type definitions |
{
"table_name": {
"columns": { ... },
"indexes": [ ... ],
"constraints": [ ... ],
"options": { ... },
"partitions": [ ... ],
"inherits": [ ... ]
}
}{
"column_name": {
"name": "column_name",
"type": "varchar",
"size": 255,
"scale": 2,
"isPrimaryKey": false,
"isNotNull": false,
"isUnique": false,
"identity": null,
"generated": null,
"collation": null,
"default": null,
"arrayDimensions": null
}
}PostgreSQL → TypeScript:
| PostgreSQL Type | TypeScript Type |
|---|---|
| serial, integer, bigint | number |
| float, double precision | number |
| varchar, char, text | string |
| boolean | boolean |
| date, timestamp, timestamptz | Date |
| json, jsonb | Record<string, unknown> |
| uuid | string |
| bytea | Uint8Array |
| array[] | T[] |
PostgreSQL → Python:
| PostgreSQL Type | Python Type |
|---|---|
| serial, integer, bigint | int |
| float, double precision | float |
| varchar, char, text | str |
| boolean | bool |
| date | date |
| timestamp, timestamptz | datetime |
| json, jsonb | Any |
| uuid | uuid.UUID |
| bytea | bytes |
# name: QueryName :returnType param1:type param2:type
SELECT ... FROM ... WHERE ...;
| Part | Required | Description |
|---|---|---|
# |
Yes | TypeSQL comment marker |
name: |
Yes | Query name, used for function generation |
:returnType |
No | Return type: one, many. Default: one |
param:type |
No | Query parameters, types: number, string, boolean |
# name: GetUser :one id: number
SELECT * FROM users WHERE id = $1;# name: GetUserByEmailAndUsername :one email: string username: string
SELECT * FROM users WHERE email = $1 AND username = $2;# name: ListUsers :many
SELECT * FROM users ORDER BY created_at DESC;# name: GetUserWithOrders :many id: number
SELECT users.*, orders.* FROM users JOIN orders ON users.id = orders.user_id WHERE users.id = $1;// Auto-generated TypeScript types and functions
// Generated by Stratus TypeSQL Compiler (PostgreSQL)
// ==================== Schema Types ====================
export interface Users {
id: number;
email: string;
username: string;
}
// ==================== Query Parameters ====================
export interface GetUserParams {
id: number;
}
// ==================== Query Results ====================
export type GetUserResult = {
id: number;
email: string;
};
// ==================== Type-Safe Query Functions ====================
export async function getUser(params: GetUserParams): Promise<GetUserResult> {
const sql = `SELECT * FROM users WHERE id = $1`;
const paramsList = [params.id];
return execute(sql, paramsList);
}# Auto-generated Python types and functions
# Generated by Stratus TypeSQL Compiler (PostgreSQL)
from dataclasses import dataclass
from datetime import datetime
# ==================== Schema Types ====================
@dataclass
class Users:
id: int
email: str
username: str
# ==================== Query Parameters ====================
@dataclass
class GetUserParams:
id: int
# ==================== Query Results ====================
@dataclass
class GetUserResult:
id: int
email: str
# ==================== Type-Safe Query Functions ====================
async def get_user(params: GetUserParams) -> GetUserResult:
sql = "SELECT * FROM users WHERE id = $1"
params_list = [params.id]
return await execute(sql, params_list)stratus generate --input <file.sql> --schema <schema.json> [options]stratus sync --schema schema.json --datasource primary
stratus sync --schema schema.json --datasource analytics --url "postgresql://..."stratus deploy --datasource primary --env production --yesstratus db push --schema schema.json --url "postgresql://..."stratus db pull --output schema.json --url "postgresql://..."stratus/
├── Cargo.toml # Rust project config
├── README.md # English documentation
├── README_CN.md # Chinese documentation
├── logo/ # Logo assets
│ └── stratus-logo.svg # Project logo
├── docker-compose.test.yml # Test PostgreSQL container
├── examples/ # Example files
├── schema/ # Schema templates
├── sdk/ # Language SDKs
│ ├── ts/ # TypeScript SDK (@stratusdb/sdk)
│ ├── py/ # Python SDK (stratus-db)
│ ├── pg/ # pg SDK (@stratusdb/pg)
│ └── wasm/ # WASM Parser (@stratusdb/wasm)
├── src/ # Source code
│ ├── main.rs # CLI entry
│ ├── lib.rs # Library entry
│ ├── ast.rs # AST definitions
│ ├── parser.rs # TypeSQL parser (Rust)
│ ├── schema.rs # JSON Schema structures
│ ├── db.rs # Database operations
│ ├── migrate.rs # Migration management
│ ├── config.rs # Configuration module
│ ├── codegen/ # Code generators
│ └── wasm.rs # WASM interface
└── target/ # Build output
- PostgreSQL: Full support
- MySQL: In development
- SQLite: In development
my-project/
├── schema/
│ └── schema.json # Database Schema
├── queries/
│ ├── users.sql
│ ├── orders.sql
│ └── products.sql
├── src/
│ ├── types.ts # Generated types
│ └── db.ts # Database connection
└── stratus.json # Optional configuration
{
"stratus": {
"version": 1,
"datasources": {
"primary": {
"url": "postgresql://user:pass@localhost:5432/mydb",
"schemas": ["public"]
}
},
"schema": {
"path": "schema/schema.json"
},
"migrations": {
"path": "migrations",
"auto_create": true
}
}
}# Initialize configuration
stratus init --url "postgresql://user:pass@localhost:5432/mydb"
# Sync using configuration
stratus sync --datasource primary
# Deploy using configuration
stratus deploy --datasource primary --env production --yesStratus is inspired by sqlc with these differences:
- Multi-language Support: Stratus supports both TypeScript and Python
- Architecture: Stratus doesn't generate ORM layer, only type definitions
- Simpler: Just write SQL, no special query syntax to learn
Stratus doesn't handle transactions itself - it only generates types. Transaction management is handled by your database connection code.
Yes! Stratus has built-in migration support:
# Development: auto-compare and create migrations
stratus sync --schema schema.json
# Deploy migrations to production
stratus deploy --datasource primary --env production --yes
# Check migration status
stratus migrate status
# Reset database
stratus migrate reset --schema schema.json --forceTypeScript SDK (@stratusdb/sdk):
cd sdk/ts && npm installimport { StratusPool } from '@stratusdb/sdk';
const pool = new StratusPool({
connectionString: process.env.DATABASE_URL,
});
const users = await pool.query('SELECT * FROM users WHERE id = $1', [1]);pg SDK (@stratusdb/pg) - High-performance runtime with WASM parser:
cd sdk/pg && npm installimport { Pool } from 'pg';
import { TypeSQLExecutor } from '@stratusdb/pg';
// Optional: Load WASM parser for 10x faster parsing
import('@stratusdb/wasm').then(wasm => {
wasm.init();
globalThis.stratus = { parseTypesql: wasm.parse_typesql };
});
const executor = new TypeSQLExecutor();
const user = await executor.query(pool)`
# name: GetUser :one id: number
SELECT * FROM users WHERE id = ${1}
`({ id: 1 });WASM Parser (@stratusdb/wasm) - Standalone high-performance parser:
cd sdk/wasm && npm installimport init, { parse_typesql, validate_typesql } from '@stratusdb/wasm';
await init();
const result = parse_typesql(`
# name: GetUser :one id: number
SELECT * FROM users WHERE id = $1;
`);
console.log(JSON.parse(result.val));Python SDK:
pip install stratus-dbfrom stratus import StratusPool
async def main():
pool = StratusPool("postgresql://user:pass@localhost/db")
users = await pool.query("SELECT * FROM users WHERE id = $1", [1])This project is licensed under the MIT License - see LICENSE for details.
Made with ❤️, use Stratus to make database operations safer