Up to 9× faster than Pydantic v2. Drop-in replacement. Powered by Rust.
Raw validation: 19.4M ops/sec (8.85× faster than Pydantic v2)
Geometric mean: 1.17× faster (across all benchmarks)
model_dump(): 1.60× faster
model_dump_json: 1.30× faster
pip install satyafrom satya import Model, Field
class User(Model):
name: str = Field(min_length=2)
age: int = Field(ge=0, le=150)
email: str = Field(email=True)
user = User(name="Alice", age=30, email="alice@example.com")
user.model_dump() # dict output — 1.6× faster
user.model_dump_json() # JSON string — 1.3× fasterSame API as Pydantic. Change the import, get the speed.
class Address(Model):
city: str
zip_code: str
class UserProfile(Model):
name: str
address: Address
profile = UserProfile(name="Alice", address={"city": "NYC", "zip_code": "10001"})
print(profile.address.city) # "NYC"Rust writes directly into nested instance __dict__s — zero intermediate dicts.
Head-to-head vs Pydantic 2.12.0 on Python 3.13 (free-threaded):
| Benchmark | Satya | Pydantic | Ratio |
|---|---|---|---|
| Simple model (3 fields) | 2.0M ops/s | 2.2M ops/s | 0.94× |
| Constrained (3 fields) | 2.0M ops/s | 2.1M ops/s | 0.95× |
| Complex (10 fields) | 946K ops/s | 993K ops/s | 0.95× |
| model_dump (simple) | 2.8M ops/s | 1.7M ops/s | 1.60× |
| model_dump (complex) | 1.7M ops/s | 1.0M ops/s | 1.63× |
| JSON serialize (simple) | 2.1M ops/s | 1.7M ops/s | 1.21× |
| JSON serialize (complex) | 1.3M ops/s | 1.0M ops/s | 1.30× |
| Raw Rust validate_check | 19.4M ops/s | 2.2M ops/s | 8.85× |
Run it yourself: python tests/benchmark_vs_pydantic.py
TurboValidator — a Rust validation engine that eliminates Python overhead:
- Pre-interned keys —
PyString::intern()at compile time, directdict.get_item()with no HashMap lookup - Return-based errors — no try/except, no string parsing. Rust returns
(field, message)tuples - Zero-allocation type checks —
is_instance_ofwithout value extraction for unconstrained fields - u64 bitmap — field tracking without Vec allocation (up to 64 fields)
- Nested dict injection — Rust writes validated fields directly into pre-created
__dict__s - apply_default — replaces
copy.deepcopywith efficient shallow copy for mutable defaults - BLAZE ordering — cheapest validations first for fail-fast on invalid data
from satya import Model, Field, ModelValidationError
class User(Model):
name: str = Field(min_length=2)
age: int = Field(ge=0)
try:
User(name="A", age=-1)
except ModelValidationError as e:
print(e.errors) # Lazy — only created when accessedfrom satya import Model, Field
class Product(Model):
name: str = Field(min_length=1, max_length=100)
price: float = Field(gt=0, le=1_000_000)
sku: str = Field(pattern=r'^[A-Z]{2}\d{6}$')
tags: list = Field(min_items=1, max_items=10)
email: str = Field(email=True)
url: str = Field(url=True)- Python 3.9+
- No runtime dependencies
Apache 2.0
