---
title: 'Announcement: Pydantic v2.13 Release'
description: >-
  Pydantic v2.13 introduces polymorphic serialization, exclude_if for computed
  fields, ascii_only validation, and private attribute factories.
date: '2026-04-13'
authors:
  - Victorien Plot
categories:
  - Pydantic Validation
  - Release
  - New Features
canonical: 'https://pydantic.dev/articles/pydantic-v2-13-release'
---

> Markdown version of [Announcement: Pydantic v2.13 Release](https://pydantic.dev/articles/pydantic-v2-13-release) — the canonical HTML page.
>
> By [Victorien Plot](https://pydantic.dev/authors/victorien-plot.md) · 2026-04-13 · Pydantic Validation, Release, New Features
>
> Related: [Emscripten wheels for Pydantic](https://pydantic.dev/articles/emscripten-wheels-pydantic.md) · [Reducing Pydantic's memory footprint using bitsets](https://pydantic.dev/articles/pydantic-bitset-performance.md)
>
> All articles: [/articles.md](https://pydantic.dev/articles.md) · Site index: [/llms.txt](https://pydantic.dev/llms.txt)

---

[Pydantic v2.13](https://github.com/pydantic/pydantic/releases/tag/v2.13.0) was released on April 13th.
You can install it now from [PyPI](https://pypi.org/project/pydantic/):

```bash
pip install --upgrade pydantic
```

v2.13 also comes with [new docs](https://pydantic.dev/docs/validation/latest/get-started/)! A unified home for Pydantic Validation, [Pydantic AI](https://pydantic.dev/pydantic-ai) and [Logfire](https://pydantic.dev/logfire).

This release features the work of 21 external contributors and provides various new features and bug fixes.
Several minor changes (considered non-breaking changes according to our [versioning policy](https://pydantic.dev/docs/validation/latest/get-started/version-policy/#pydantic-v2))
are also included in this release. Make sure to look into them before upgrading.

This release contains the updated `pydantic.v1` namespace, matching version 1.10.26 which includes support for Python 3.14.

Highlights include:
* [New polymorphic serialization behavior](#polymorphic-serialization)
* [`exclude_if` for computed fields](#exclude_if-support-for-computed-fields)
* [Validated data for default factories of private attributes](#validated-data-for-default-factories-of-private-attributes)

You can see the full changelog on [GitHub](https://github.com/pydantic/pydantic/releases/tag/v2.13.0).

:::commend
The [`pydantic-core` repository](https://github.com/pydantic/pydantic-core) was migrated to the `pydantic` repository, to ease maintenance.
`pydantic-core` is still being published as a separate package.
:::

## Quick Reference:

* [New Features](#new-features)
* [Changes](#changes)

## New Features

### Polymorphic serialization

In v2.12, the behavior of `serialize_as_any` [was unified](https://pydantic.dev/articles/pydantic-v2-12-release#unify-serialize_as_anyserializeasany-behavior) with the `SerializeAsAny` annotation.
This introduced unfortunate breakage for users relying on `serialize_as_any` to serialize model subclasses.

In this release, we introduced a new [_polymorphic serialization_ option](https://pydantic.dev/docs/validation/latest/concepts/serialization/#polymorphic-serialization), that applies specifically to model subclasses:

```python
from pydantic import BaseModel


class User(BaseModel):
    name: str


class UserLogin(User):
    password: str


class OuterModel(BaseModel):
    user: User


outer_model = OuterModel(
    user=UserLogin(name='pydantic', password='password'),
)


print(outer_model.model_dump())
#> {'user': {'name': 'pydantic'}}
print(outer_model.model_dump(polymorphic_serialization=True))
#> {'user': {'name': 'pydantic', 'password': 'password'}}
```

In some way, _polymorphic serialization_ can be seen as a subset of _serialize as any_, that only applies to Pydantic models and dataclasses (_serialize as any_ applies to all kind of fields).

PR reference: [#12518](https://github.com/pydantic/pydantic/pull/12518).

### `exclude_if` support for computed fields

In the previous v2.12 version, a new `exclude_if` option was added for regular fields. This option is now available for [computed fields](https://pydantic.dev/docs/validation/latest/concepts/fields/#the-computed_field-decorator):

```python
from pydantic import BaseModel, computed_field


class Model(BaseModel):
    cash_payments: int
    card_payments: int

    @computed_field(exclude_if=lambda v: v == 0)
    def total_payments(self) -> int:
        return self.cash_payments + self.card_payments


m = Model(cash_payments=0, card_payments=0)
m.model_dump()
#> {'cash_payments': 0, 'card_payments': 0}
```

Contributed by [@andresliszt](https://github.com/andresliszt). PR reference: [#12748](https://github.com/pydantic/pydantic/pull/12748).

### Validated data for default factories of private attributes

In v2.10, default factories of regular fields gained the ability to take the validated data as an optional argument. This ability was extended to
[private attributes](https://pydantic.dev/docs/validation/latest/concepts/models/#private-model-attributes) in this release:

```python
from pydantic import BaseModel, PrivateAttr


class Model(BaseModel):
    foo: int
    _priv1: int = PrivateAttr(default=2)
    _priv2: int = PrivateAttr(default_factory=lambda data: data['foo'] + data['_priv1'])


m = Model(foo=1)
m._priv2
#> 3
```

Contributed by [@andresliszt](https://github.com/andresliszt). PR reference: [#11685](https://github.com/pydantic/pydantic/pull/11685).

### `ascii_only` string validation flag

A new `ascii_only` flag was added to the [`StringConstraints`](https://pydantic.dev/docs/validation/dev/api/pydantic/types/#pydantic.types.StringConstraints) metadata:

```python
from typing import Annotated

from pydantic import StringConstraints, TypeAdapter

ta = TypeAdapter(Annotated[str, StringConstraints(ascii_only=True)])
ta.validate_python('é')
"""
pydantic_core._pydantic_core.ValidationError: 1 validation error for constrained-str
  String should contain only ASCII characters [type=string_not_ascii, input_value='é', input_type=str]
    For further information visit https://errors.pydantic.dev/2.13/v/string_not_ascii
"""
```

Contributed by [@ai-man-codes](https://github.com/ai-man-codes). PR reference: [#12907](https://github.com/pydantic/pydantic/pull/12907).

## Changes

This release contains some minor changes that may affect existing code. Make sure to go through them before upgrading.

### Serialization of unions

Some fixes and optimizations were applied to the serialization of unions (including discriminated unions). This should result
in more correct behavior and better performance, but could introduce unexpected regressions.

PR references: [#12604](https://github.com/pydantic/pydantic/pull/12604), [#12825](https://github.com/pydantic/pydantic/pull/12825).

### Tracking extra fields in `model_fields_set`

While [extra fields](https://pydantic.dev/docs/validation/latest/concepts/models/#extra-data) set _during_ validation were already tracked in
[`model_fields_set`](https://pydantic.dev/docs/validation/latest/api/pydantic/base_model/#pydantic.BaseModel.model_fields_set), this was not the case
if set _after_ model instantiation (unlike regular fields):

```python
from pydantic import BaseModel


class Model(BaseModel, extra='allow'):
    a: int
    b: int = 1


m = Model(a=1, extra_data='test')
m.model_fields_set
#> {'a', 'extra_data'}
m.b = 2
m.model_fields_set
#> {'a', 'b', 'extra_data'}
m.other_extra = 'test'
m.model_fields_set
#> In <= 2.12: {'a', 'b', 'extra_data'}
#> In >= 2.13: {'a', 'b', 'extra_data', 'other_extra'}
```

PR reference: [#12817](https://github.com/pydantic/pydantic/pull/12817).

:::commend
We are working on memory and performance improvements related to model fields set. Check [_Reducing Pydantic's memory footprint using bitsets_](https://pydantic.dev/articles/pydantic-bitset-performance.md)
for more details.
:::

### Shallow copies of root models

The behavior of shallow [`model_copy()`](https://pydantic.dev/docs/validation/latest/concepts/models/#model-copy) on [`RootModel`](https://pydantic.dev/docs/validation/latest/concepts/models/#rootmodel-and-custom-root-types)
has been changed to make a shallow copy of the root type.

The previous behavior was to only make a shallow copy of the root model instance, which wasn't really the behavior users would expect:

```python
from pydantic import RootModel


class MyList(RootModel[list[int]]):
    root: list[int]


m = MyList([1, 2])
copied = m.model_copy(deep=False)  # shallow copy (the default)
copied.root is m.root
#> In <= 2.12: True
#> In >= 2.13: False
```

Contributed by [@YassinNouh21](https://github.com/YassinNouh21). PR reference: [#12679](https://github.com/pydantic/pydantic/pull/12679).

### Validation of `@field_serializer` field names

Up until now, the field names arguments to the [`@field_serializer`](https://pydantic.dev/docs/validation/latest/api/pydantic/functional_serializers/#pydantic.functional_serializers.field_serializer) decorator
were not validated, unlike the [`@field_validator`](https://pydantic.dev/docs/validation/latest/api/pydantic/functional_validators/#pydantic.functional_validators.field_validator).

If you don't provide any field name to the decorator, or arguments that are not strings, a [`PydanticUserError`](https://pydantic.dev/docs/validation/latest/api/pydantic/errors/#pydantic.errors.PydanticUserError) will now be raised.

### Validation of `complex` and `Decimal` values

Prior to v2.13, [`complex`](https://docs.python.org/3/library/functions.html#complex) Python values were validated using the following rules:

* [`complex`](https://docs.python.org/3/library/functions.html#complex) instances are validated as-is.
* Strings are validated using the [`complex()`](https://docs.python.org/3/library/functions.html#complex) constructor.
* Numbers (integers and floats) are used as the real part.

Pydantic now defers validation to the [`complex()`](https://docs.python.org/3/library/functions.html#complex) constructor, meaning it will
support the [`__complex__()`](https://docs.python.org/3/reference/datamodel.html#object.__complex__), [`__float__()`](https://docs.python.org/3/reference/datamodel.html#object.__float__)
or [`__index__()`](https://docs.python.org/3/reference/datamodel.html#object.__index__) methods on the input being validated.

Similarly, [`Decimal`](https://docs.python.org/3/library/decimal.html#decimal-objects) values can now be validated as a three-tuple:

```python
from decimal import Decimal

from pydantic import TypeAdapter

ta = TypeAdapter(Decimal)
ta.validate_python((0, (1, 4, 1, 4), -3))
#> Decimal('1.414')
ta.validate_json("[0, [1, 4, 1, 4], -3]")
#> Decimal('1.414')
```

Contributed by [@tanmaymunjal](https://github.com/tanmaymunjal). PR references: [#12498](https://github.com/pydantic/pydantic/pull/12498), [#12500](https://github.com/pydantic/pydantic/pull/12500).

### `NamedTuple` subclasses

When using a subclass of an existing `NamedTuple` class, Pydantic was treating all annotations of this subclass as fields. In v2.13, Pydantic aligns with the Python behavior (which doesn't support fields
defined on subclasses), by checking the [`_fields`](https://docs.python.org/3/library/collections.html#collections.somenamedtuple._fields) attribute:

```python
from typing import NamedTuple

from pydantic import TypeAdapter

class Foo(NamedTuple):
    test: str
    test2: str

class Bar(Foo):
    test3: str


ta = TypeAdapter(Bar)

# Would work on <= 2.12, fails in >= 2.13:
ta.validate_python({'test': 'a', 'test2': 'b', 'test3': 'c'})
```

Defining such subclasses isn't a supported Python pattern for now, see [python/typing#427](https://github.com/python/typing/issues/427).

PR reference: [#12951](https://github.com/pydantic/pydantic/pull/12951).

---

Ready to try the new features? Upgrade now with `pip install --upgrade pydantic` or `uv add --upgrade pydantic` and check out the https://github.com/pydantic/pydantic/releases/tag/v2.13.0. Have questions or feedback? Join the conversation on our community [Slack](https://pydantic.dev/docs/logfire/join-slack/).
