strawberry-alchemy
Batteries-included toolkit for building Strawberry GraphQL APIs backed by SQLAlchemy
Source Code: https://github.com/Alteian/strawberry-alchemy
Documentation: docs/index.md · API reference
What is it?
strawberry-alchemy turns Strawberry GraphQL selection sets into a single optimized
SQLAlchemy query — automatic selectinload for relationships, column deferral, and
SQL EXISTS/COUNT annotations — and ships the supporting cast: filter inputs,
Relay pagination, CRUD repositories, row-level security, permissions, and mapping
helpers.
- No N+1 queries: nested selections become eager loads automatically
- Unrequested columns are deferred — you only fetch what the client asked for
- Declarative computed fields (
hasComments,coverThumbUrl, counts) resolved by SQL subqueries AND/ORfilters, relationship joins, and custom per-model filters from Strawberry inputs- Relay
Connectionpagination withtotalCount - Async repositories with lifecycle hooks and cascade deletes
- Row-level access filters applied to every query — and to
totalCount
Installation
pip install strawberry-alchemy
# or
uv add strawberry-alchemy
Requires Python >= 3.13, Strawberry GraphQL >= 0.220, SQLAlchemy, Pydantic v2.
Quick example
# models.py
import uuid
from sqlalchemy import ForeignKey
from sqlalchemy.dialects.postgresql import UUID
from sqlalchemy.orm import Mapped, mapped_column
from strawberry_alchemy.models import Base
class Post(Base):
user_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("user.id"))
title: Mapped[str]
body: Mapped[str]
# access_filters.py
from typing import Any
from models import Post
from strawberry_alchemy.filtering import AccessControlFilter
class PostAccessFilter(AccessControlFilter):
model_class = Post
@staticmethod
async def apply_filter(query: Any, model: type[Any], context_user: Any) -> Any:
return query.where(model.user_id == context_user.id)
# types.py
import strawberry
from typing import ClassVar
from strawberry_alchemy import BaseNodeType
@strawberry.type
class PostType(BaseNodeType):
access_filter: ClassVar = PostAccessFilter()
title: str | None = strawberry.UNSET
body: str | None = strawberry.UNSET
# queries.py
import strawberry
from strawberry.types import Info
from strawberry_alchemy import ListResult
@strawberry.type
class Query:
@strawberry.field
async def posts(self, info: Info, limit: int | None = None) -> ListResult[PostType]:
return await PostType.resolve_list(info=info, limit=limit)
# schema.py
import strawberry
from strawberry.schema.config import StrawberryConfig
schema = strawberry.Schema(
query=Query,
config=StrawberryConfig(auto_camel_case=True, relay_max_results=100),
)
query {
posts(limit: 10) {
items { id title body }
totalCount
}
}
Your request context needs three things: get_session(), an identity/user
attribute, and a db_execution_lock (see
docs/getting-started.md#context-contract).
Documentation
| Page | Topic |
|---|---|
| docs/index.md | Overview, features, architecture |
| docs/getting-started.md | Full walkthrough: models, types, filters, queries, mutations |
| docs/types-and-models.md | Base, BaseNodeType, ListResult, connections, ordering |
| docs/queries.md | resolve_node / resolve_list / resolve_connection, pagination |
| docs/query-optimizer.md | Load strategies, @optimize_field hints, QueryAnalyzer |
| docs/filtering.md | Filter inputs, operators, AND/OR, custom & access-control filters |
| docs/repository.md | CRUD, relations, deletion handlers |
| docs/mapping-and-schema.md | BaseSchema, SQLAlchemy → Strawberry mapping |
| docs/permissions.md | Permission classes, resource checks |
| docs/api-reference.md | Every public export with signatures |
Development
git clone https://github.com/Alteian/strawberry-alchemy.git
cd strawberry-alchemy
uv sync
# Lint & test
uv run ruff check .
uv run pytest -v
# Build
uv build
Contributing
See CONTRIBUTING.md for guidelines.
License
Release files for strawberry-alchemy 0.1.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| strawberry_alchemy-0.1.4.tar.gz | 28.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| strawberry_alchemy-0.1.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 69.6 kB
Release files / strawberry_alchemy-0.1.4.tar.gz
| Download URL | strawberry_alchemy-0.1.4.tar.gz |
|---|---|
| Size | 28.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
d132fa50489b223848b70de52761faf821136adae122cd5699e1e4c23a9cc5ca
|
|
BLAKE2b-256 checksum How to use checksums |
e2681b7538e1f22e4b44314611c8ea2fc76b81b40822bb5c124a5488043f6a54
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency logRelease files / strawberry_alchemy-0.1.4-py3-none-any.whl
| Download URL | strawberry_alchemy-0.1.4-py3-none-any.whl |
|---|---|
| Size | 40.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8c87a3c0db783f0023e90dd65993c989b9cae933730f6222530cf72fbc8ed262
|
|
BLAKE2b-256 checksum How to use checksums |
cf901c69b5e8fe49c0d02d4bae65072529dce2f3504a07b13dfde26240caef31
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 16, 2026.
Transparency log