SQLAlchemy
Drop-in SQLAlchemy wrapper that routes queries through Gold Lapel. Covers the SQLAlchemy Core engine, the ORM, and async apps like FastAPI.
Install
pip install goldlapel sqlalchemy
# Plus a Postgres driver of your choice:
pip install psycopg2-binary # sync
pip install psycopg # psycopg3 (sync or async)
pip install asyncpg # async The SQLAlchemy glue ships inside the goldlapel package at goldlapel.sqlalchemy — no extra install step. Install SQLAlchemy separately with regular pip.
Quick Start (sync)
Import from goldlapel.sqlalchemy instead of sqlalchemy — everything else stays the same. The L1 native cache activates automatically — repeated reads serve in microseconds.
from sqlalchemy import create_engine
engine = create_engine("postgresql://user:pass@host:5432/mydb") from goldlapel.sqlalchemy import create_engine
engine = create_engine("postgresql://user:pass@host:5432/mydb") Full sync example:
from goldlapel.sqlalchemy import create_engine
from sqlalchemy import text
engine = create_engine("postgresql://user:pass@host:5432/mydb")
# That's it — queries now route through Gold Lapel
with engine.connect() as conn:
result = conn.execute(text("SELECT * FROM users")) Quick Start (async)
Use create_async_engine for async applications. Dialect suffixes like +asyncpg are handled automatically:
from goldlapel.sqlalchemy import create_async_engine
from sqlalchemy import text
engine = create_async_engine("postgresql+asyncpg://user:pass@host:5432/mydb")
async with engine.connect() as conn:
result = await conn.execute(text("SELECT * FROM users")) The sync Engine path uses the in-process L1 native cache (microsecond reads). AsyncEngine queries still route through the Gold Lapel proxy for L2 caching and optimization — native L1 cache for async engines lands in a follow-up release.
SQLAlchemy ORM
The ORM sits on top of the engine, so once the engine is wired through Gold Lapel, everything above it — Session, declarative models, Query, select(), relationships — flows through automatically:
from goldlapel.sqlalchemy import create_engine
from sqlalchemy.orm import DeclarativeBase, Session, Mapped, mapped_column
class Base(DeclarativeBase): ...
class User(Base):
__tablename__ = "users"
id: Mapped[int] = mapped_column(primary_key=True)
email: Mapped[str]
engine = create_engine("postgresql://user:pass@host:5432/mydb")
with Session(engine) as session:
users = session.query(User).filter(User.email.like("%@example.com")).all() FastAPI Example
A complete async setup with session management:
from fastapi import FastAPI
from goldlapel.sqlalchemy import create_async_engine
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy import text
engine = create_async_engine("postgresql+asyncpg://user:pass@host:5432/mydb")
SessionLocal = async_sessionmaker(engine)
app = FastAPI()
@app.get("/users")
async def list_users():
async with SessionLocal() as session:
result = await session.execute(text("SELECT * FROM users"))
return result.mappings().all() Alternative: init()
Rewrites DATABASE_URL to route through the proxy, so you can create your own engine as usual:
import goldlapel.sqlalchemy
import os
goldlapel.sqlalchemy.init()
# Now create your engine as usual — it connects through Gold Lapel
from sqlalchemy import create_engine
engine = create_engine(os.environ["DATABASE_URL"]) Options
Optional proxy settings via keyword arguments on create_engine / create_async_engine:
engine = create_engine(
"postgresql://user:pass@host:5432/mydb",
goldlapel_port=9000,
goldlapel_config={"mode": "waiter", "pool_size": 50},
goldlapel_extra_args=["--threshold-duration-ms", "200"],
) | Key | Default | Description |
|---|---|---|
goldlapel_port | 7932 | Local proxy port |
goldlapel_config | None | Full Gold Lapel config dict (same keys as goldlapel.start(config=...)) |
goldlapel_extra_args | [] | Extra CLI flags passed to the Gold Lapel binary |
The same options are available on init() with shorter names:
goldlapel.sqlalchemy.init(
port=9000,
config={"mode": "waiter", "pool_size": 50},
extra_args=["--threshold-duration-ms", "200"],
) | Key | Default | Description |
|---|---|---|
port | 7932 | Local proxy port |
config | None | Full Gold Lapel config dict |
extra_args | [] | Extra CLI flags passed to the Gold Lapel binary |
Dialect Suffixes
SQLAlchemy dialect suffixes (+asyncpg, +psycopg, +pg8000) are handled automatically. Pass your normal SQLAlchemy connection URL — Gold Lapel strips the suffix when building the upstream connection and preserves it for the local proxy connection.
Advanced Tuning
goldlapel_config takes the same dict as goldlapel.start(config=...) — see the configuration reference for every setting. goldlapel_extra_args and GOLDLAPEL_* environment variables both work as secondary escape hatches.
Requirements
- Python 3.9+
- SQLAlchemy 1.4+
goldlapel0.2+- PostgreSQL (TCP connections only)
Upgrading from v0.1
The goldlapel[sqlalchemy] install extra was removed in v0.2. SQLAlchemy is now installed separately, and the glue code always ships inside the main goldlapel package:
# v0.1.x (old) — single pinned install extra
pip install goldlapel[sqlalchemy]
# v0.2 (new) — install goldlapel and sqlalchemy separately
pip install goldlapel sqlalchemy - Install command changed —
pip install goldlapel[sqlalchemy]is gone. Installgoldlapelandsqlalchemyseparately. - Import path is unchanged —
from goldlapel.sqlalchemy import create_enginestill works. - Keyword arguments on
create_engine(goldlapel_port,goldlapel_extra_args) are unchanged.goldlapel_configis the newly exposed full-config passthrough. - Internally the wrapper now calls the new
goldlapel.start()factory — behaviour is identical to v0.1 from SQLAlchemy's perspective.
How It Works
goldlapel.sqlalchemy wraps SQLAlchemy's create_engine and create_async_engine functions. When you create an engine, it extracts the database connection details from your URL, calls goldlapel.start() to spawn the proxy, and wires a connection with the L1 native cache into the engine (sync path). All subsequent queries — via Core or the ORM — flow through Gold Lapel automatically.
The init() alternative takes a different approach — it rewrites DATABASE_URL in your environment so that any engine you create afterward connects through the proxy without needing the wrapper import.