NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
PyPI · #1727 most downloaded on PyPI
A library for creating GraphQL APIs
Last release 10 days ago
07 Sep 2026
Ships fairly regularly
a new release about every 2 weeks
Nearly every release is documented
notes for 60 of the last 60 stable releases
Nothing withdrawn
no release was ever pulled
8 years old
1114 releases · first in 2019
Fix sync execution crash with graphql-core 3.3 where execute_sync() would return a coroutine instead of an ExecutionResult, causing RuntimeError: Ther
Fix sync execution crash with graphql-core 3.3 where execute_sync() would return a coroutine
instead of an ExecutionResult, causing RuntimeError: There is no current event loop,
because graphql-core 3.3's is_async_iterable default treats objects with __aiter__
(like Django QuerySets) as async iterables.
Now passes is_async_iterable=lambda _x: False during sync execution to prevent this.
Note: graphql-core >= 3.3.0a12 is now the minimum required version for the 3.3.x series.
Releases contributed by @bellini666 via #4267
Fix two NameError issues in schema-codegen output when types are referenced before they are defined.
Fix two NameError issues in schema-codegen output when types are referenced before they are defined.
First, forward references in field annotations (e.g. foo: Foo appearing before Foo is defined) are now handled by emitting from __future__ import annotations at the top of the generated file. Per PEP 563, this stores all annotations as strings instead of evaluating them at class definition time, so the referenced names don't need to exist yet.
Second, union definitions like FooOrBar = Annotated[Foo | Bar, strawberry.union(...)] are runtime expressions that from __future__ import annotations cannot defer. These are now correctly ordered by declaring union member types as dependencies, so unions are always emitted after their members.
Changes:
from __future__ import annotations in generated code to handle forward references in field annotations.Releases contributed by @sanlil via #4192
One column per quarter.
Add query property to Info class, allowing resolvers to access the full GraphQL document string sent in the request via info.query.
Add query property to Info class, allowing resolvers to access the full GraphQL document string sent in the request via info.query.
Example usage:
import strawberry
@strawberry.type
class Query:
@strawberry.field
def hello(self, info: strawberry.Info, name: str) -> str:
print(info.query)
return f"Hello {name}"
When executing this query:
query Hello($name: String!) {
hello(name: $name)
}
info.query returns the full query string:
"query Hello($name: String!) {\n hello(name: $name)\n}"
Releases contributed by @Ckk3 via #4289
Fix compatibility with Python 3.14 when using the Pydantic integration with Pydantic V2. Previously, importing strawberry.experimental.pydantic on Pyt
Fix compatibility with Python 3.14 when using the Pydantic integration with Pydantic V2. Previously, importing strawberry.experimental.pydantic on Python 3.14 would trigger:
UserWarning: Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater.
This is now fixed by avoiding pydantic.v1 imports on Python 3.14+.
Releases contributed by @zshuzh via #4283
Fix from __future__ import annotations breaking lazy types inside generic wrappers like Optional[], tuple[], dict[], Sequence[], etc. Previously only
Fix from __future__ import annotations breaking lazy types inside generic wrappers like Optional[], tuple[], dict[], Sequence[], etc. Previously only Union[], list[]/List[], and Annotated[] were handled during AST namespace resolution, causing _eval_type to fail when lazy types were nested inside other generic subscripts.
Releases contributed by @bellini666 via #4270
Fix from __future__ import annotations breaking lazy types inside generic wrappers like Optional[], tuple[], dict[], Sequence[], etc. Previously only Union[], list[]/List[], and Annotated[] were handled during AST namespace resolution, causing _eval_type to fail when lazy types were nested inside other generic subscripts.
Contributed by Thiago Bellini Ribeiro via PR #4270
Fix ApolloTracingExtension crashing with AttributeError when executing invalid queries (e.g., { node() }). All timing attributes are now initialized i
Fix ApolloTracingExtension crashing with AttributeError when executing invalid queries (e.g., { node() }). All timing attributes are now initialized in __init__ and lifecycle hooks use try/finally to ensure proper cleanup.
Releases contributed by @Br1an67 via #4271
Fix ApolloTracingExtension crashing with AttributeError when executing invalid queries (e.g., { node() }). All timing attributes are now initialized in __init__ and lifecycle hooks use try/finally to ensure proper cleanup.
…name")] age: Annotated[int, strawberry.field(deprecation_reason="Use birthDate instead")]
This release adds support for defining fields using the Annotated syntax. This provides an
alternative way to specify field metadata alongside the type annotation.
Example usage:
from typing import Annotated
import strawberry
@strawberry.type
class Query:
name: Annotated[str, strawberry.field(description="The name")]
age: Annotated[int, strawberry.field(deprecation_reason="Use birthDate instead")]
@strawberry.input
class CreateUserInput:
name: Annotated[str, strawberry.field(description="User's name")]
email: Annotated[str, strawberry.field(description="User's email")]
This syntax works alongside the existing assignment syntax:
@strawberry.type
class Query:
# Both styles work
field1: Annotated[str, strawberry.field(description="Using Annotated")]
field2: str = strawberry.field(description="Using assignment")
All strawberry.field() options are supported including description, name,
deprecation_reason, directives, metadata, and permission_classes.
Releases contributed by @patrick91 via #4059
This release fixes issues with explicit field definitions in experimental pydantic types:
This release fixes issues with explicit field definitions in experimental pydantic types:
all_fields=True now respects explicit field definitions: Previously, using all_fields=True would override any explicitly defined fields in the strawberry type. Now, explicit definitions take precedence, allowing you to:
strawberry.Private to hide them from the GraphQL schemaThe warning "Using all_fields overrides any explicitly defined fields" has been removed since combining all_fields=True with explicit definitions is now a valid and useful pattern.
Private fields are auto-populated from pydantic models: When a strawberry.Private field has the same name as a pydantic model field, from_pydantic() will automatically populate it from the model (can be overridden via the extra dict).
Example:
from pydantic import BaseModel
import strawberry
from strawberry.experimental.pydantic import type as pyd_type
from strawberry.extensions.field_extension import FieldExtension
class MaskExtension(FieldExtension):
def resolve(self, next_, source, info, **kwargs):
result = next_(source, info, **kwargs)
return result[:3] + "****" if result else result
class UserModel(BaseModel):
name: str
email: str
password: str
@pyd_type(model=UserModel, all_fields=True)
class User:
# Add extension to mask email in responses
email: str = strawberry.field(extensions=[MaskExtension()])
# Hide password from GraphQL schema entirely
password: strawberry.Private[str]
# name and email are exposed in schema, password is not
# email will be masked by the extension
pydantic_user = UserModel(name="Alice", email="alice@example.com", password="secret")
strawberry_user = User.from_pydantic(pydantic_user)
# Private field is still accessible internally
print(strawberry_user.password) # "secret"
Releases contributed by @XChikuX via #4179
Remove deprecated _type_definition and _enum_definition aliases, deprecated since 0.187.0.
Remove deprecated _type_definition and _enum_definition aliases, deprecated since 0.187.0.
Before (deprecated):
type_def = MyType._type_definition
enum_def = MyEnum._enum_definition
After:
type_def = MyType.__strawberry_definition__
enum_def = MyEnum.__strawberry_definition__
Releases contributed by @Ckk3 via #4219
Remove deprecated _type_definition and _enum_definition aliases, deprecated since 0.187.0.
Before (deprecated):
type_def = MyType._type_definition
enum_def = MyEnum._enum_definition
After:
type_def = MyType.__strawberry_definition__
enum_def = MyEnum.__strawberry_definition__
Contributed by Luis Gustavo via PR #4219
Remove deprecated fields parameter from Pydantic decorators, deprecated since 0.82.0.
Remove deprecated fields parameter from Pydantic decorators, deprecated since 0.82.0.
Before (deprecated):
@strawberry.experimental.pydantic.type(model=UserModel, fields=["name", "age"])
class User:
pass
After:
@strawberry.experimental.pydantic.type(model=UserModel)
class User:
name: strawberry.auto
age: strawberry.auto
Releases contributed by @Ckk3 via #4223
Remove deprecated fields parameter from Pydantic decorators, deprecated since 0.82.0.
Before (deprecated):
@strawberry.experimental.pydantic.type(model=UserModel, fields=["name", "age"])
class User:
pass
After:
@strawberry.experimental.pydantic.type(model=UserModel)
class User:
name: strawberry.auto
age: strawberry.auto
Contributed by Luis Gustavo via PR #4223
Remove deprecated is_unset() function and deprecated UNSET import from strawberry.arguments, deprecated since 0.109.0.
Remove deprecated is_unset() function and deprecated UNSET import from strawberry.arguments, deprecated since 0.109.0.
Before (deprecated):
from strawberry.types.unset import is_unset
from strawberry.types.arguments import UNSET
if is_unset(value):
...
After:
from strawberry import UNSET
if value is UNSET:
...
Releases contributed by @Ckk3 via #4212
Remove deprecated is_unset() function and deprecated UNSET import from strawberry.arguments, deprecated since 0.109.0.
Before (deprecated):
from strawberry.types.unset import is_unset
from strawberry.types.arguments import UNSET
if is_unset(value):
...
After:
from strawberry import UNSET
if value is UNSET:
...
Contributed by Luis Gustavo via PR #4212
Remove deprecated LazyType["Name", "module"] syntax, deprecated since 0.129.0.
Remove deprecated LazyType["Name", "module"] syntax, deprecated since 0.129.0.
Before (deprecated):
from strawberry.lazy_type import LazyType
@strawberry.type
class Query:
user: LazyType["User", "myapp.types"]
After:
from typing import Annotated
import strawberry
@strawberry.type
class Query:
user: Annotated["User", strawberry.lazy("myapp.types")]
Releases contributed by @Ckk3 via #4218
Remove deprecated LazyType["Name", "module"] syntax, deprecated since 0.129.0.
Before (deprecated):
from strawberry.lazy_type import LazyType
@strawberry.type
class Query:
user: LazyType["User", "myapp.types"]
After:
from typing import Annotated
import strawberry
@strawberry.type
class Query:
user: Annotated["User", strawberry.lazy("myapp.types")]
Contributed by Luis Gustavo via PR #4218
Fix Annotated[Union[A, B], strawberry.union("Name")] raising TypeError when used as a type parameter in a generic subclass (e.g., class Items(Listing[
Fix Annotated[Union[A, B], strawberry.union("Name")] raising TypeError when
used as a type parameter in a generic subclass (e.g., class Items(Listing[ItemResponse])).
Fix Annotated[Union[A, B], strawberry.union("Name")] raising TypeError when
used as a type parameter in a generic subclass (e.g., class Items(Listing[ItemResponse])).
Contributed by Thiago Bellini Ribeiro via PR #4235
Add strawberry.federation.params module with shared TypedDicts (FederationFieldParams, FederationInterfaceParams, FederationTypeParams) and processing
Add strawberry.federation.params module with shared TypedDicts (FederationFieldParams, FederationInterfaceParams, FederationTypeParams) and processing functions (process_federation_field_directives, process_federation_type_directives) for federation directives.
These TypedDicts can be consumed via Unpack[...] to avoid duplicating federation parameter lists across packages. The processing functions are extracted from inline logic previously in field.py and object_type.py.
Also fixes a bug where inaccessible=False incorrectly added the Inaccessible directive on types/interfaces.
If you still have strawberry.ext.mypy_plugin in your mypy configuration, it will emit a DeprecationWarning and can be safely removed. Pydantic users o…
The strawberry mypy plugin has been removed. It is no longer needed thanks to
@dataclass_transform, overloaded signatures, and the StrawberryTypeFromPydantic
protocol.
If you still have strawberry.ext.mypy_plugin in your mypy configuration, it will
emit a DeprecationWarning and can be safely removed. Pydantic users only need
the pydantic.mypy plugin.
Releases contributed by @bellini666 via #4258
The strawberry mypy plugin has been removed. It is no longer needed thanks to
@dataclass_transform, overloaded signatures, and the StrawberryTypeFromPydantic
protocol.
If you still have strawberry.ext.mypy_plugin in your mypy configuration, it will
emit a DeprecationWarning and can be safely removed. Pydantic users only need
the pydantic.mypy plugin.
Contributed by Thiago Bellini Ribeiro via PR #4258
Remove deprecated strawberry server CLI command, deprecated since 0.283.0.
Remove deprecated strawberry server CLI command, deprecated since 0.283.0.
Before (deprecated):
strawberry server myapp:schema
After:
strawberry dev myapp:schema
Releases contributed by @Ckk3 via #4215
Remove deprecated strawberry server CLI command, deprecated since 0.283.0.
Before (deprecated):
strawberry server myapp:schema
After:
strawberry dev myapp:schema
Contributed by Luis Gustavo via PR #4215
Remove deprecated strawberry server CLI command, deprecated since 0.283.0 .
Before (deprecated):
Terminal window
strawberry server myapp:schema
After:
Terminal window
strawberry dev myapp:schema
Contributed by Luis Gustavo via PR #4215
Remove deprecated asserts_errors parameter from test clients, deprecated since 0.246.0.
Remove deprecated asserts_errors parameter from test clients, deprecated since 0.246.0.
Before (deprecated):
result = client.query(query, asserts_errors=False)
After:
result = client.query(query, assert_no_errors=False)
Releases contributed by @Ckk3 via #4217
Remove deprecated asserts_errors parameter from test clients, deprecated since 0.246.0.
Before (deprecated):
result = client.query(query, asserts_errors=False)
After:
result = client.query(query, assert_no_errors=False)
Contributed by Luis Gustavo via PR #4217
Remove deprecated debug-server extra from pyproject.toml, deprecated since 0.283.0.
Remove deprecated debug-server extra from pyproject.toml, deprecated since 0.283.0.
Before (deprecated):
pip install strawberry-graphql[debug-server]
After:
pip install strawberry-graphql[cli]
Releases contributed by @Ckk3 via #4228
Remove deprecated debug-server extra from pyproject.toml, deprecated since 0.283.0.
Before (deprecated):
pip install strawberry-graphql[debug-server]
After:
pip install strawberry-graphql[cli]
Contributed by Luis Gustavo via PR #4228
Remove deprecated debug-server extra from pyproject.toml , deprecated since 0.283.0 .
Before (deprecated):
Terminal window
pip install strawberry-graphql[debug-server]
After:
Terminal window
pip install strawberry-graphql[cli]
Contributed by Luis Gustavo via PR #4228
Fix execution_context.result being None or belonging to a wrong request when multiple async requests execute concurrently (e.g. via asyncio.gather). S
Fix execution_context.result being None or belonging to a wrong request when multiple async requests execute concurrently (e.g. via asyncio.gather). Shared cached extension instances are no longer reused across concurrent async requests.
Releases contributed by @bellini666 via #4256
Fix execution_context.result being None or belonging to a wrong request when multiple async requests execute concurrently (e.g. via asyncio.gather). Shared cached extension instances are no longer reused across concurrent async requests.
Contributed by Thiago Bellini Ribeiro via PR #4256
Remove deprecated types parameter from strawberry.union(), deprecated since 0.191.0.
Remove deprecated types parameter from strawberry.union(), deprecated since 0.191.0.
You can run strawberry upgrade annotated-union <path> to automatically migrate your code.
Before (deprecated):
import strawberry
MyUnion = strawberry.union("MyUnion", types=(TypeA, TypeB))
After:
from typing import Annotated
import strawberry
MyUnion = Annotated[TypeA | TypeB, strawberry.union("MyUnion")]
Releases contributed by @Ckk3 via #4220
Remove deprecated types parameter from strawberry.union(), deprecated since 0.191.0.
You can run strawberry upgrade annotated-union <path> to automatically migrate your code.
Before (deprecated):
import strawberry
MyUnion = strawberry.union("MyUnion", types=(TypeA, TypeB))
After:
from typing import Annotated
import strawberry
MyUnion = Annotated[TypeA | TypeB, strawberry.union("MyUnion")]
Contributed by Luis Gustavo via PR #4220
Remove the ExecutionContext.errors property, deprecated since 0.276.2.
Remove the ExecutionContext.errors property, deprecated since 0.276.2.
Before (deprecated):
class MyExtension(SchemaExtension):
def on_execute(self):
yield
errors = self.execution_context.errors
After:
class MyExtension(SchemaExtension):
def on_execute(self):
yield
errors = self.execution_context.pre_execution_errors
Releases contributed by @Ckk3 via #4214
Remove the ExecutionContext.errors property, deprecated since 0.276.2.
Before (deprecated):
class MyExtension(SchemaExtension):
def on_execute(self):
yield
errors = self.execution_context.errors
After:
class MyExtension(SchemaExtension):
def on_execute(self):
yield
errors = self.execution_context.pre_execution_errors
Contributed by Luis Gustavo via PR #4214
Fix false-positive DuplicatedTypeName error when two different StrawberryObjectDefinition instances share the same origin class. This can happen when
Fix false-positive DuplicatedTypeName error when two different StrawberryObjectDefinition instances share the same origin class. This can happen when third-party decorators (e.g. strawberry-django's filter_type) re-process a type, creating a new definition while keeping the same Python class as origin.
Releases contributed by @bellini666 via #4193
Fix false-positive DuplicatedTypeName error when two different StrawberryObjectDefinition instances share the same origin class. This can happen when third-party decorators (e.g. strawberry-django's filter_type) re-process a type, creating a new definition while keeping the same Python class as origin.
Contributed by Thiago Bellini Ribeiro via PR #4193
Fix strawberry.experimental.pydantic to correctly handle nested pydantic.v1 models when running on Pydantic 2 (for example, list[LegacyModel] fields w
Fix strawberry.experimental.pydantic to correctly handle nested pydantic.v1
models when running on Pydantic 2 (for example, list[LegacyModel] fields with
all_fields=True), and add a regression test for this case.
Releases contributed by @patrick91 via #4246
Fix strawberry.experimental.pydantic to correctly handle nested pydantic.v1
models when running on Pydantic 2 (for example, list[LegacyModel] fields with
all_fields=True), and add a regression test for this case.
Contributed by Patrick Arminio via PR #4246
Remove deprecated argument name-based matching for info and directive_value parameters, deprecated since 0.159.0.
Remove deprecated argument name-based matching for info and directive_value parameters, deprecated since 0.159.0.
Parameters named info or directive_value are no longer automatically recognized by name. You must use explicit type annotations.
Before (deprecated):
@strawberry.type
class Query:
@strawberry.field
def example(self, info) -> str:
return info.context["key"]
After:
@strawberry.type
class Query:
@strawberry.field
def example(self, info: strawberry.Info) -> str:
return info.context["key"]
Releases contributed by @Ckk3 via #4224
Remove deprecated legacy extension hooks (on_request_start, on_request_end, on_validation_start, on_validation_end, on_parsing_start, on_parsing_end),…
Remove deprecated legacy extension hooks (on_request_start, on_request_end, on_validation_start, on_validation_end, on_parsing_start, on_parsing_end), deprecated since 0.159.0.
Before (deprecated):
class MyExtension(SchemaExtension):
def on_request_start(self): ...
def on_request_end(self): ...
After:
class MyExtension(SchemaExtension):
def on_operation(self):
# on_request_start logic
yield
# on_request_end logic
Releases contributed by @Ckk3 via #4226
Remove deprecated legacy extension hooks (on_request_start, on_request_end, on_validation_start, on_validation_end, on_parsing_start, on_parsing_end), deprecated since 0.159.0.
Before (deprecated):
class MyExtension(SchemaExtension):
def on_request_start(self): ...
def on_request_end(self): ...
After:
class MyExtension(SchemaExtension):
def on_operation(self):
# on_request_start logic
yield
# on_request_end logic
Contributed by Luis Gustavo via PR #4226
Remove deprecated Sanic-specific features: json_encoder parameter (deprecated since 0.147.0), json_dumps_params parameter (deprecated since 0.147.0),…
Remove deprecated Sanic-specific features: json_encoder parameter (deprecated since 0.147.0), json_dumps_params parameter (deprecated since 0.147.0), and context dot notation (deprecated since 0.146.0).
json_encoder / json_dumps_params — Before (deprecated):
class MyView(GraphQLView):
def __init__(self):
super().__init__(json_encoder=MyEncoder, json_dumps_params={"indent": 2})
After:
class MyView(GraphQLView):
def encode_json(self, data):
return json.dumps(data, cls=MyEncoder, indent=2)
Context dot notation — Before (deprecated):
request = info.context.request
After:
request = info.context["request"]
Releases contributed by @Ckk3 via #4221
Remove deprecated channel_listen method from the Channels integration, deprecated since 0.193.0.
Remove deprecated channel_listen method from the Channels integration, deprecated since 0.193.0.
Before (deprecated):
async for message in info.context["ws"].channel_listen("my_channel"):
yield Message(message=message["text"])
After:
async with info.context["ws"].listen_to_channel("my_channel") as listener:
async for message in listener:
yield Message(message=message["text"])
Releases contributed by @Ckk3 via #4216
Remove deprecated channel_listen method from the Channels integration, deprecated since 0.193.0.
Before (deprecated):
async for message in info.context["ws"].channel_listen("my_channel"):
yield Message(message=message["text"])
After:
async with info.context["ws"].listen_to_channel("my_channel") as listener:
async for message in listener:
yield Message(message=message["text"])
Contributed by Luis Gustavo via PR #4216
Remove deprecated graphiql parameter from all HTTP integrations (ASGI, Flask, FastAPI, Quart, Sanic, Chalice, Django, Aiohttp, Channels, and Litestar)…
Remove deprecated graphiql parameter from all HTTP integrations (ASGI, Flask, FastAPI, Quart, Sanic, Chalice, Django, Aiohttp, Channels, and Litestar), deprecated since 0.213.0.
Before (deprecated):
app = GraphQL(schema, graphiql=True)
After:
app = GraphQL(schema, graphql_ide="graphiql")
# or to disable:
app = GraphQL(schema, graphql_ide=None)
Releases contributed by @Ckk3 via #4222
Remove deprecated graphiql parameter from all HTTP integrations (ASGI, Flask, FastAPI, Quart, Sanic, Chalice, Django, Aiohttp, Channels, and Litestar), deprecated since 0.213.0.
Before (deprecated):
app = GraphQL(schema, graphiql=True)
After:
app = GraphQL(schema, graphql_ide="graphiql")
# or to disable:
app = GraphQL(schema, graphql_ide=None)
Contributed by Luis Gustavo via PR #4222
This release fixes a bug where the async execute method was creating new extension instances on every request (via get_extensions()), instead of reusi
This release fixes a bug where the async execute method was creating
new extension instances on every request (via get_extensions()),
instead of reusing cached instances like the sync execute_sync method
already did. This caused extensions that accumulate state across the
execution lifecycle (such as ApolloTracingExtension) to lose their
state between requests when using async execution.
Releases contributed by @bellini666 via #4181
This release fixes a bug where the async execute method was creating
new extension instances on every request (via get_extensions()),
instead of reusing cached instances like the sync execute_sync method
already did. This caused extensions that accumulate state across the
execution lifecycle (such as ApolloTracingExtension) to lose their
state between requests when using async execution.
Contributed by Thiago Bellini Ribeiro via PR #4181
Update type annotations for Response.data and Response.extensions in the test client to Any, instead of JsonValue, to allow nested subscript access in
Update type annotations for Response.data and Response.extensions in the test client to Any, instead of JsonValue, to allow nested subscript access in test assertions without type errors.
Releases contributed by @millar via #4195
Update type annotations for Response.data and Response.extensions in the test client to Any, instead of JsonValue, to allow nested subscript access in test assertions without type errors.
Contributed by Sam Millar via PR #4195
Nothing published for this version
Nothing published for this version
This update relaxes type annotations for Response.data and Response.extensions from dict[str, JsonValue] to dict[str, JsonValue] in the test client, m
This update relaxes type annotations for Response.data and Response.extensions from dict[str, JsonValue] to dict[str, JsonValue] in the test client, making assertions in tests easier to write.
Releases contributed by @millar via #4186
This update relaxes type annotations for Response.data and Response.extensions from dict[str, JsonValue] to dict[str, JsonValue] in the test client, making assertions in tests easier to write.
Contributed by Sam Millar via PR #4186
Adds a graphql_type parameter to strawberry.argument that allows you to explicitly override the GraphQL type of an argument, useful for static typing
Adds a graphql_type parameter to strawberry.argument that allows you
to explicitly override the GraphQL type of an argument, useful for static typing
when the Python type differs from the desired GraphQL type.
For example:
BigInt = strawberry.scalar(
int, name="BigInt", serialize=lambda v: str(v), parse_value=lambda v: int(v)
)
@strawberry.type
class Query:
@strawberry.field()
def username(
self, user_id: Annotated[int, strawberry.argument(graphql_type=BigInt)]
) -> str:
return "foobar"
schema = strawberry.Schema(Query)
str(
schema
) == """
scalar BigInt
type Query {
username(userId: BigInt!): String!
}
"""
Releases contributed by @thearchitector via #4067
This release improves schema-codegen for input types in two ways:
This release improves schema-codegen for input types in two ways:
Nullable input fields now use strawberry.Maybe[T | None], allowing them to
be omitted when constructing the input type.
GraphQL default values on input fields are now generated as Python defaults.
Supported value types: integers, floats, strings, booleans, null, enums, and
lists. When a field also has a description (or other metadata), the default is
passed via strawberry.field(description=..., default=...).
Before:
@strawberry.input
class CreateUserInput:
name: str
role: int | None # required – TypeError with {}
# default value "42" from schema was lost
After:
@strawberry.input
class CreateUserInput:
name: str
role: strawberry.Maybe[int | None] = 42
Releases contributed by @patrick91 via #4178
This release adds UploadDefinition to strawberry.file_uploads, which can be used with scalar_overrides to map framework-specific upload types to the U
This release adds UploadDefinition to strawberry.file_uploads, which can be
used with scalar_overrides to map framework-specific upload types to the
Upload scalar. This enables proper type checking with mypy/pyright when using
file uploads.
Example usage with Starlette/FastAPI:
from starlette.datastructures import UploadFile
from strawberry.file_uploads import UploadDefinition
schema = strawberry.Schema(
query=Query, mutation=Mutation, scalar_overrides={UploadFile: UploadDefinition}
)
@strawberry.type
class Mutation:
@strawberry.mutation
async def read_file(self, file: UploadFile) -> str:
return (await file.read()).decode("utf-8")
With this configuration, the file parameter is correctly typed as UploadFile,
giving you proper IDE autocomplete and type checking.
Releases contributed by @patrick91 via #4175
Fix nested generics with resolver-backed fields to avoid duplicate type names.
Fix nested generics with resolver-backed fields to avoid duplicate type names.
Example (previously raised DuplicatedTypeName):
import strawberry
@strawberry.type
class Collection[T]:
field1: list[T] = strawberry.field(resolver=lambda: [])
@strawberry.type
class Container[T]:
items: list[T]
@strawberry.type
class TypeA: ...
@strawberry.type
class TypeB: ...
@strawberry.type
class Query:
@strawberry.field
def a(self) -> Container[Collection[TypeA]]: ...
@strawberry.field
def b(self) -> Container[Collection[TypeB]]: ...
strawberry.Schema(query=Query)
Releases contributed by @bellini666 via #4162
Fix nested generics with resolver-backed fields to avoid duplicate type names.
Example (previously raised DuplicatedTypeName):
import strawberry
@strawberry.type
class Collection[T]:
field1: list[T] = strawberry.field(resolver=lambda: [])
@strawberry.type
class Container[T]:
items: list[T]
@strawberry.type
class TypeA: ...
@strawberry.type
class TypeB: ...
@strawberry.type
class Query:
@strawberry.field
def a(self) -> Container[Collection[TypeA]]: ...
@strawberry.field
def b(self) -> Container[Collection[TypeB]]: ...
strawberry.Schema(query=Query)
Contributed by Thiago Bellini Ribeiro via PR #4162
This release adds support for field extensions in experimental pydantic types.
This release adds support for field extensions in experimental pydantic types.
Previously, when using @strawberry.experimental.pydantic.type() decorator, field extensions defined with strawberry.field(extensions=[...]) were not being propagated to the generated Strawberry fields. This meant extensions like authentication, caching, or result transformation couldn't be used with pydantic-based types.
This fix ensures that extensions are properly preserved when converting pydantic fields to Strawberry fields, enabling the full power of field extensions across the pydantic integration.
Examples:
Permission-based field masking:
from pydantic import BaseModel
from typing import Optional
import strawberry
from strawberry.experimental.pydantic import type as pyd_type
from strawberry.extensions.field_extension import FieldExtension
class PermissionExtension(FieldExtension):
def resolve(self, next_, source, info, **kwargs):
# Check permission, return None if denied
if not check_field_access(info.context.user, info.field_name, source.id):
return None
return next_(source, info, **kwargs)
class UserModel(BaseModel):
id: int
fname: str
email: str
phone: str
perm_ext = PermissionExtension()
@pyd_type(model=UserModel)
class UserGQL:
# Public fields - just use auto
id: strawberry.auto
fname: strawberry.auto
# Protected fields - attach extension
email: Optional[str] = strawberry.field(extensions=[perm_ext])
phone: Optional[str] = strawberry.field(extensions=[perm_ext])
Basic transformation extension:
class UpperCaseExtension(FieldExtension):
def resolve(self, next_, source, info, **kwargs):
result = next_(source, info, **kwargs)
return str(result).upper()
class ProductModel(BaseModel):
name: str
@pyd_type(model=ProductModel)
class Product:
name: str = strawberry.field(extensions=[UpperCaseExtension()])
Releases contributed by @XChikuX via #4171
Fix union type resolution to fall back to is_type_of for generic unions when type matching fails. This allows returning domain/ORM objects from generi
Fix union type resolution to fall back to is_type_of for generic unions when
type matching fails. This allows returning domain/ORM objects from generic union
fields without spurious union type errors.
Releases contributed by @bellini666 via #4163
Fix union type resolution to fall back to is_type_of for generic unions when
type matching fails. This allows returning domain/ORM objects from generic union
fields without spurious union type errors.
Contributed by Thiago Bellini Ribeiro via PR #4163
This release fixes an issue where relay.node() fields on nested types required explicit initialization, even though the field values are resolved dyna
This release fixes an issue where relay.node() fields on nested types required
explicit initialization, even though the field values are resolved dynamically.
Previously, this code would fail at runtime:
@strawberry.type
class Sub:
node: relay.Node = relay.node()
@strawberry.type
class Query:
@strawberry.field
def sub(self) -> Sub:
return Sub() # Error: missing required argument 'node'
Now relay.node() provides a default value, allowing nested types with relay
node fields to be instantiated without explicit initialization.
Releases contributed by @devkral via #3331
This release fixes an issue where lazy union types using the new Annotated syntax were not being resolved correctly.
This release fixes an issue where lazy union types using the new Annotated syntax were not being resolved correctly.
Example that now works:
from typing import Annotated
import strawberry
@strawberry.type
class Query:
@strawberry.field
def example(self) -> Annotated["SomeUnion", strawberry.lazy("module")]: ...
Releases contributed by @patrick91 via #4156
This release fixes an issue where lazy union types using the new Annotated syntax were not being resolved correctly.
Example that now works:
from typing import Annotated
import strawberry
@strawberry.type
class Query:
@strawberry.field
def example(self) -> Annotated["SomeUnion", strawberry.lazy("module")]: ...
Contributed by Patrick Arminio via PR #4156
Fix lazy type resolution with relative imports
Fix lazy type resolution with relative imports
This fixes an issue where lazy types using relative imports (e.g., strawberry.lazy(".module")) would fail to resolve correctly when comparing with the __main__ module, potentially causing "Type X is defined multiple times in the schema" errors during test isolation.
This ensures that the fully resolved module name is used when comparing with __main__.__spec__.name, rather than the relative import path.
Releases contributed by @bellini666 via #4145
Improved execution performance by up to 10% by adding an optimized is_awaitable check with a fast path for common synchronous types (such as int, str,
Improved execution performance by up to 10% by adding an optimized is_awaitable check with a fast path for common synchronous types (such as int, str, list, dict, etc.).
This optimization reduces overhead when processing large result sets containing mostly basic values by avoiding expensive awaitable checks for types that are known to never be awaitable.
Releases contributed by @patrick91 via #4035
Support using enum values in the GraphQL schema
Support using enum values in the GraphQL schema
Releases contributed by @paulo-raca via #4071
Support using enum values in the GraphQL schema
Contributed by Paulo Costa via PR #4071
Added URL sharing support for GraphiQL. Query, variables, and headers are now persisted in the URL, allowing users to share GraphQL queries via links.
Added URL sharing support for GraphiQL. Query, variables, and headers are now persisted in the URL, allowing users to share GraphQL queries via links.
Releases contributed by @Arfey via #2842
Added URL sharing support for GraphiQL. Query, variables, and headers are now persisted in the URL, allowing users to share GraphQL queries via links.
Contributed by Mykhailo Havelia via PR #2842
Fixed a bug where strawberry.Maybe[T] was incorrectly accepting null values when passed through variables
Fixed a bug where strawberry.Maybe[T] was incorrectly accepting null values when passed through variables
Previously, Maybe[T] returned a validation error for literal null values in GraphQL queries, but allowed null when passed via variables, resulting in Some(None) reaching the resolver instead of raising a validation error.
This fix ensures consistent validation behavior for Maybe[T] regardless of how the input is provided:
Maybe[T] now returns a validation error for null in both literal queries and variablesMaybe[T | None] continues to accept null values as expectedMaybe[T | None] if null values are neededReleases contributed by @bellini666 via #4096
Fixed two bugs where using strawberry.Maybe wrapped in Annotated or using an explicit field definition would raise a TypeError about "missing 1 requir
Fixed two bugs where using strawberry.Maybe wrapped in Annotated or using an explicit field definition would raise a TypeError about "missing 1 required keyword-only argument", even though a Maybe field should allow None in all cases.
This fix addresses this via custom handling for annotations wrapped with Annotated and handling custom field with no default and no default_factory as possible to be None.
Releases contributed by @Birdi7 via #4084
Fixed a bug where using relay.node() or relay.connection() would raise a DeprecationWarning about "Argument name-based matching of 'info'", even thoug…
Fixed a bug where using relay.node() or relay.connection() would raise a
DeprecationWarning about "Argument name-based matching of 'info'", even though
the info parameter was correctly annotated.
This also fixes the same warning when using Python 3.12+ type alias syntax for
Info, such as type MyInfo = strawberry.Info[Context, None].
The fix recognizes strawberry.Info and strawberry.Parent annotations (with
or without generic parameters) when they appear as string forward references.
Only fully qualified names are matched to avoid confusion with user-defined types.
Releases contributed by @bellini666 via #4081
Deprecate passing a class to strawberry.scalar(). Use scalar_map in StrawberryConfig instead for better type checking support.
Deprecate passing a class to strawberry.scalar(). Use scalar_map in
StrawberryConfig instead for better type checking support.
# Before (deprecated)
Base64 = strawberry.scalar(
NewType("Base64", bytes),
serialize=lambda v: base64.b64encode(v).decode(),
parse_value=lambda v: base64.b64decode(v),
)
Instead, use scalar_map in StrawberryConfig:
# Recommended
Base64 = NewType("Base64", bytes)
schema = strawberry.Schema(
query=Query,
config=StrawberryConfig(
scalar_map={
Base64: strawberry.scalar(
name="Base64",
serialize=lambda v: base64.b64encode(v).decode(),
parse_value=lambda v: base64.b64decode(v),
)
}
),
)
This release also removes internal scalar wrapper exports (Date, DateTime,
etc.) from strawberry.schema.types.base_scalars. Most users are likely not
using these, but if you were, a codemod is available to help with the migration:
strawberry upgrade replace-scalar-wrappers .
More info about custom scalars at the updated doc page: https://strawberry.rocks/docs/types/scalars#scalars
Releases contributed by @bellini666 via #4076
Switch from lia-web to cross-web: lia-web has been renamed to cross-web. Update imports from lia to cross_web accordingly.
Switch from lia-web to cross-web: lia-web has been renamed to cross-web. Update imports from lia to cross_web accordingly.
Releases contributed by @Antiz96 via #4079
Switch from lia-web to cross-web: lia-web has been renamed to cross-web. Update imports from lia to cross_web accordingly.
Contributed by Robin Candau via PR #4079
Fix compatibility with Python 3.14 when using the Pydantic integration with Pydantic V2.
Fix compatibility with Python 3.14 when using the Pydantic integration with Pydantic V2.
Previously, importing strawberry.experimental.pydantic on Python 3.14 would trigger:
UserWarning: Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater.
This is now fixed by avoiding pydantic.v1 imports on Python 3.14+.
Releases contributed by @patrick91 via #4072
Fix compatibility with Python 3.14 when using the Pydantic integration with Pydantic V2.
Previously, importing strawberry.experimental.pydantic on Python 3.14 would trigger:
UserWarning: Core Pydantic V1 functionality isn't compatible with Python 3.14 or greater.
This is now fixed by avoiding pydantic.v1 imports on Python 3.14+.
Contributed by Patrick Arminio via PR #4072
Fixed a bug in the codegen where Relay Node's id field was incorrectly generated as _id in the output code.
Fixed a bug in the codegen where Relay Node's id field was incorrectly generated as _id in the output code.
The codegen now correctly respects the explicit graphql_name set via the @field(name="id") decorator, ensuring that the generated code uses id instead of the Python method name _id.
Releases contributed by @Ckk3 via #4053
Fixed a bug in the codegen where Relay Node's id field was incorrectly generated as _id in the output code.
The codegen now correctly respects the explicit graphql_name set via the @field(name="id") decorator, ensuring that the generated code uses id instead of the Python method name _id.
Contributed by Luis Gustavo via PR #4053
Fix mypy plugin issues related to new version of mypy. The TypeAlias class has one more required argument "module" in the mypy version >= 1.19.
Fix mypy plugin issues related to new version of mypy. The TypeAlias class has one more required argument "module" in the mypy version >= 1.19.
Releases contributed by @Ansud via #4060
Fix mypy plugin issues related to new version of mypy. The TypeAlias class has one more required argument "module" in the mypy version >= 1.19.
Contributed by Anton Zelenov via PR #4060
Change strawberry.http.base.BaseView.encode_json() type hint to str | bytes and adjust dependent code appropriately.
Change strawberry.http.base.BaseView.encode_json() type hint to str | bytes and adjust dependent code appropriately.
Releases contributed by @Brandieee via #4054
Change strawberry.http.base.BaseView.encode_json() type hint to str | bytes and adjust dependent code appropriately.
Set Content-Type to text/plain for exceptions so that these are displayed correctly.
Set Content-Type to text/plain for exceptions so that these are displayed
correctly.
Releases contributed by @mgorven via #4037
Set Content-Type to text/plain for exceptions so that these are displayed
correctly.
Contributed by Michael Gorven via PR #4037
This release changes _enum_definition to __strawberry_definition__, this is a follow up to previous internal changes. If you were relying on _enum_def
This release changes _enum_definition to __strawberry_definition__, this is a follow up to previous
internal changes. If you were relying on _enum_definition you should update your code to use __strawberry_definition__.
We also expose has_enum_definition to check if a type is a strawberry enum definition.
from enum import Enum
import strawberry
from strawberry.types.enum import StrawberryEnumDefinition, has_enum_definition
@strawberry.enum
class ExampleEnum(Enum):
pass
has_enum_definition(ExampleEnum) # True
# Now you can use ExampleEnum.__strawberry_definition__ to access the enum definition
Releases contributed by @Ckk3 via #3999
You must migrate to Federation v2. See the breaking changes documentation for detailed migration instructions.
This release removes support for Apollo Federation v1 and improves Federation v2 support with explicit version control and new directives.
enable_federation_2 parameter: Replaced with federation_version parameterenable_federation_2=TrueRemove the parameter:
# Before
schema = strawberry.federation.Schema(query=Query, enable_federation_2=True)
# After
schema = strawberry.federation.Schema(query=Query)
You must migrate to Federation v2. See the breaking changes documentation for detailed migration instructions.
schema = strawberry.federation.Schema(
query=Query, federation_version="2.5" # Specify a specific version if needed
)
@context, @fromContext, @cost, and @listSize directives (v2.7+)Releases contributed by @patrick91 via #4045
Nothing published for this version
Bumped minimum Typer version to fix strawberry CLI commands.
Bumped minimum Typer version to fix strawberry CLI commands.
Releases contributed by @valliu via #4049
Removed Transfer-Encoding: chunked header from multipart streaming responses. This fixes HTTP 405 errors on Vercel and other serverless platforms. The
Removed Transfer-Encoding: chunked header from multipart streaming responses. This fixes HTTP 405 errors on Vercel and other serverless platforms. The server/gateway will handle chunked encoding automatically when needed.
Releases contributed by @LouisAmon via #4047
Removed Transfer-Encoding: chunked header from multipart streaming responses. This fixes HTTP 405 errors on Vercel and other serverless platforms. The server/gateway will handle chunked encoding automatically when needed.
Contributed by Louis Amon via PR #4047
Your coding agent can read these notes before it upgrades. Set up the MCP server →