v0.279.0 Breaking Changes

This release changes the strawberry.Maybe type definition to provide a more consistent and intuitive API for handling optional fields.

What Changed

The Maybe type definition has been changed from:

Maybe: TypeAlias = Union[Some[Union[T, None]], None]

to:

Maybe: TypeAlias = Union[Some[T], None]

Impact on Your Code

Type Annotations

If you were using Maybe[T] and expecting to handle explicit null values, you now need to explicitly declare this with Maybe[T | None] :

# Before (0.278.0 and earlier)
field: strawberry.Maybe[str] # Could handle Some(None)
# After (0.279.0+)
field: strawberry.Maybe[str] # Only handles Some("value") or None (absent)
field: strawberry.Maybe[str | None] # Handles Some("value"), Some(None), or None

Runtime Behavior

The runtime behavior changes to provide more consistent field checking:

This means Maybe[str] can no longer receive explicit null values - they will cause a validation error.

Consistent Field Checking

This change provides a single, consistent way to check if a field was provided, regardless of whether the field allows null values:

@strawberry.input
class UpdateUserInput:
# Can be provided with a value or not provided at all
name: strawberry.Maybe[str]
# Can be provided with a value, provided as null, or not provided at all
phone: strawberry.Maybe[str | None]
@strawberry.mutation
def update_user(input: UpdateUserInput) -> User:
# Same checking pattern for both fields
if input.name is not None: # Field was provided
user.name = input.name.value # Type checker knows this is str
if input.phone is not None: # Field was provided
user.phone = input.phone.value # Type checker knows this is str | None

The key benefit is that if field is not None now consistently means “field was provided” for all Maybe fields.

Migration

Automatic Migration

Strawberry provides a codemod to automatically update your code:

Terminal window
strawberry upgrade maybe-optional

The codemod will automatically convert Maybe[T] to Maybe[T | None] to maintain the previous behavior.

Manual Migration

Review your Maybe usage and decide whether you need the union type:

# If you only need "present" vs "absent" (most common case)
field: strawberry.Maybe[str]
# If you need "present with value", "present but null", and "absent"
field: strawberry.Maybe[str | None]

Why This Change?

After extensive discussion, we decided that changing Maybe to Some[T] | None (instead of Some[T | None] | None ) provides the best developer experience because:

  1. Consistent field checking: You can always use if field is not None: to check if a field was provided, regardless of whether the field allows null values

  2. Preserves existing behavior: You can still get the previous behavior by using Maybe[T | None] when you need to handle explicit nulls

  3. Better type safety: Maybe[str] now properly indicates that the field cannot be null, while Maybe[str | None] explicitly allows nulls

  4. Cleaner API: There’s now “one true way” to check if a field was provided, making the API more intuitive

The new approach provides both simplicity for common cases and flexibility for complex scenarios where null handling is needed.

Need Help?