Use StatelyDB with Python
Python developers value pragmatism, clarity, and speed. Yet when it comes to databases, the landscape is often a mix of cumbersome abstractions or unstructured chaos. You’re either navigating the heavy machinery of an ORM like SQLAlchemy, or juggling raw dictionaries from a NoSQL driver and sacrificing the structure that keeps apps robust.
StatelyDB offers a more Pythonic path. Our schema-first workflow generates clean, typed data classes so you interact with data using an elegant async API. Less boilerplate, more shipping.
The Python Data Disconnect
Common pain points you may recognize:
- ORM Complexity: Sessions, unit-of-work patterns, hidden performance traps. The abstraction meant to help adds cognitive load.
- Dict Soup: Flexible NoSQL backends leave you passing around
dict[str, Any]
and sprinkling validation everywhere. Misspell a key; get a runtime error. - Migration Risk: Alembic scripts + production changes = stress. Small iterations feel heavyweight.
- Boilerplate Glue: Hand-written DTOs, validators, serializers—time not spent on product value.
The StatelyDB Developer Experience
Designed to feel natural in modern Python: simple, explicit, productive.
1. Define Your Schema Once
Your single source of truth is a TypeScript-based Elastic Schema™ file that describes your data model.
// schema/schema.ts
import { itemType, string, uuid } from "@stately-cloud/schema";
/** A user of our new application. */
itemType("User", {
keyPath: "/user-:id",
fields: {
id: { type: uuid, initialValue: "uuid" },
name: { type: string },
email: { type: string },
},
});
2. Generate Native Python Data Classes
Run one command to produce a typed client package (works beautifully with MyPy + IDEs):
stately schema generate \
--language python \
--schema-id <your-schema-id> \
./your_app/stately_client
This yields data classes and a lightweight client you can import directly.
3. Interact with a Clean, Asynchronous API
Compare StatelyDB with raw Boto3 DynamoDB usage.
StatelyDB: Clean and Pythonic
# your_app/user_service.py
from your_app.stately_client import Client, User
async def create_user(client: Client, name: str, email: str) -> User:
# Instantiate a typed data class.
user_to_create = User(name=name, email=email)
# Put returns a fully typed object.
created_user = await client.put(user_to_create)
print(f"Created user with ID: {created_user.id}")
return created_user
Typical Boto3 for DynamoDB: Verbose and Untyped
import boto3, uuid
dynamodb = boto3.resource("dynamodb")
table = dynamodb.Table("my-table")
def create_user(name: str, email: str) -> dict:
user_id = str(uuid.uuid4())
# Manually craft the item.
item = {
"PK": f"USER#{user_id}",
"SK": "METADATA",
"id": user_id,
"name": name,
"email": email,
}
table.put_item(Item=item)
return {"id": user_id, "name": name, "email": email}
With StatelyDB you write less, it’s clearer, and it’s type-safe end‑to‑end.
4. Evolve Fearlessly
Need to change a field? Update schema.ts
, add a migration command, regenerate, and deploy. Elastic Schema ensures forward + backward compatibility—no brittle manual SQL or risky downtime migrations.
Get Started with Python
Ready to use a database that feels built for Python?
- Follow our Getting Started Guide to create your account, store, and schema.
- Install the SDK:
pip install statelydb
- Generate your Python client code (see step 2 above).
- Initialize the client and start building.
import asyncio, os
from your_app.stately_client import Client # Generated client
from your_app.user_service import create_user
async def main():
store_id = os.environ["STATELY_STORE_ID"] # Provided via environment
# You can also pass region=... if needed.
async with Client(store_id=store_id) as client:
_ = await create_user(client, "Ada Lovelace", "ada@example.com")
if __name__ == "__main__":
asyncio.run(main())
It’s that simple.