pydantic-extra-types review
pydantic-extra-types 2.11.1 supplies Pydantic 2 field annotations for values that need more than a plain string or integer. Its modules cover phone numbers, country and currency codes, payment card checks, colors, coordinates, ISBNs, MAC addresses, timezones, cron expressions, ULIDs, Mongo ObjectIds, S3 paths, routing numbers, and other domain formats. Successful validation feeds the parsed value into a model and contributes constraints to JSON Schema where the type defines them. Release 2.11.1 adds IBAN validation, UUID versions 6, 7, and 8, database and messaging DSN types moved from `pydantic.networks`, and a root-level `Color` export. Several modules wrap optional packages, so the annotation you import determines which extra belongs in the lock file.
pydantic-extra-types 2.11.1 installed in 0.4 seconds, occupied 8 MB across 6 packages, imported in 0.20 seconds, and had 0 audit findings in our sandbox. Install it for repeated Pydantic 2 domain fields, while keeping existence checks and authorization outside the annotation.
We installed it
| Install | ✓ · 0.4s | 6 packages on disk · 8 MB |
| Import | ✓ | import pydantic_extra_types in 0.20s · pure Python · py.typed · requires Python >=3.9 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does pydantic-extra-types install cleanly?
Yes. In a fresh container with an empty cache, pip install pydantic-extra-types finished in 0.4s, leaving 6 packages and 8 MB on disk. pip-audit reported no known vulnerabilities.
What does pydantic-extra-types need to run?
Python >=3.9, and nothing compiled: it is pure Python. In our run import pydantic_extra_types succeeded in 0.20s, and the package ships py.typed for type checkers.
pydantic-extra-types or pydantic: which should you use?
pydantic: Use core constrained fields and local validators when the project has only a few domain rules. pydantic-extra-types 2.11.1 installed in 0.4 seconds, occupied 8 MB across 6 packages, imported in 0.20 seconds, and had 0 audit findings in our sandbox.
When should you not use pydantic-extra-types?
The application still supports Pydantic 1. Package 2.11.1 builds schemas through the Pydantic 2 core-schema hooks and requires Pydantic 2.5.2 or newer.
Use it if
- Pydantic 2 models repeat checks for IBANs, phone numbers, ISO codes, coordinates, UUID versions, or other domain-shaped fields.
- FastAPI request and response schemas should expose a named field type instead of hiding all validation inside custom functions.
- A Pydantic 1 migration needs former core types such as `Color` or `PaymentCardNumber` in their maintained package.
- The team will pin the optional extras used by production models and test those imports during startup.
- The application still supports Pydantic 1. Package 2.11.1 builds schemas through the Pydantic 2 core-schema hooks and requires Pydantic 2.5.2 or newer.
- One short local validator covers the entire need. Adding a satellite package plus an optional data library makes that rule harder to find and upgrade.
- Validation must confirm that a bank account, card, phone subscriber, S3 object, or database server exists. These types check representation, ranges, registries, or checksums without contacting the external system.
- Production installs only the base extra while code imports `phone_numbers`, `country`, `cron`, `pendulum_dt`, or another optional integration. Those modules can fail at import when their companion package is absent.
- The service cannot accept validation changes caused by refreshed country, phone, timezone, or currency data. Optional packages carry datasets whose accepted values can change independently.
Setup reality
We installed pydantic-extra-types 2.11.1 in a fresh Python 3.12 Bookworm sandbox. Installation succeeded in 0.4 seconds, left 6 packages and 8 MB on disk, and import pydantic_extra_types worked in 0.20 seconds. Pip-audit reported 0 known vulnerabilities. The distribution is pure Python, ships py.typed, requires Python 3.9 or newer, and uses the MIT license. Its package metadata reports 22 direct dependencies.
The top-level import proves only the base package loads. Phone parsing needs the phonenumbers extra; country, currency, language, and script data need pycountry; cron expressions need cron-converter. Pendulum, semantic versions, Mongo ObjectIds, and ULIDs have their own extras. On Python before 3.14, generating UUID v7 also needs uuid-utils. Record the chosen extras in the production dependency group instead of relying on a developer's broad [all] install.
No credentials or config files are involved. The common deployment failure is a missing optional package that appears only when a route imports its model. Import each production model in CI and the container startup check. Version 2.11.1 also moves DSN annotations into this package, so code following the new location needs pydantic-extra-types even when it uses no dataset-backed fields.
A parsed value still needs business checks. The new IBAN type removes spaces, uppercases input, enforces the country-specific length, and applies MOD-97; it cannot prove the account is open. PaymentCardNumber cannot authorize a charge. S3Path parses bucket and key without making a network request. Phone parsing may need a default region for national input. Treat the 0.20-second import result as an environment check, then test policy after model validation.
Patterns
Normalize and validate an IBAN validate-iban
from pydantic import BaseModel
from pydantic_extra_types.iban import IBAN
class BankAccount(BaseModel):
iban: IBAN
account = BankAccount(iban="gb29 nwbk 6016 1331 9268 19")
print(account.iban) # GB29NWBK60161331926819Version 2.11.1 removes spaces, uppercases the value, checks the country's exact length, and applies MOD-97. It does not contact the bank.
Accept only UUID version 7 require-uuid7
from pydantic import BaseModel
from pydantic_extra_types.uuid_types import UUID7
class Event(BaseModel):
id: UUID7
event = Event(id="018f0e8c-7a6a-7b1c-a3e4-fdf3e0ef7a4a")
print(event.id.version) # 7`UUID7` rejects UUIDs carrying another version nibble. The parsed field is a standard `uuid.UUID` object.
Generate and inspect UUID version 7 generate-uuid7
from pydantic_extra_types.uuid_types import uuid7, uuid7_to_datetime
identifier = uuid7()
created_at = uuid7_to_datetime(identifier)
print(identifier, created_at)Python 3.14 uses `uuid.uuid7()`. Earlier Python versions require the `uuid-utils` extra to generate a value, even though validation itself accepts a UUID7 string.
Constrain a PostgreSQL connection URL validate-database-dsn
from pydantic import BaseModel
from pydantic_extra_types.dsn import PostgresDsn
class Settings(BaseModel):
database_url: PostgresDsn
settings = Settings(
database_url="postgresql://app:secret@db.internal:5432/orders"
)
print(settings.database_url.hosts())Version 2.11.1 moved DSN aliases from `pydantic.networks` into this package. Validation parses URL structure without opening a database connection.
Parse a phone number into E.164 parse-phone-number
from typing import Annotated
from pydantic import BaseModel
from pydantic_extra_types.phone_numbers import PhoneNumberValidator
E164Phone = Annotated[
str,
PhoneNumberValidator(number_format="E164", default_region="US"),
]
class Contact(BaseModel):
phone: E164Phone
print(Contact(phone="650-253-0000").phone) # +16502530000Install the `phonenumbers` extra. National input needs `default_region`; a valid parse does not confirm that a subscriber owns the number.
Validate and convert a country code look-up-country
from pydantic import BaseModel
from pydantic_extra_types.country import CountryAlpha2
class Supplier(BaseModel):
country: CountryAlpha2
supplier = Supplier(country="IN")
print(supplier.country.alpha3) # IND
print(supplier.country.short_name) # IndiaInstall the `pycountry` extra. Accepted values follow its ISO dataset, which can change when that dependency is updated.
Inspect a payment card number check-payment-number
from pydantic import BaseModel
from pydantic_extra_types.payment import PaymentCardNumber
class Checkout(BaseModel):
card: PaymentCardNumber
checkout = Checkout(card="4000000000000002")
print(checkout.card.brand, checkout.card.last4)The type checks card-number structure and Luhn validity. A successful model does not confirm the account, available funds, or authorization.
Convert a color to hex normalize-color
from pydantic import BaseModel
from pydantic_extra_types import Color
class Theme(BaseModel):
accent: Color
theme = Theme(accent="rgb(38, 200, 122)")
print(theme.accent.as_hex()) # #26c87aVersion 2.11.1 exports `Color` from the package root. Existing module-level imports from `pydantic_extra_types.color` also remain available.
Reject out-of-range coordinates bound-coordinates
from pydantic import BaseModel
from pydantic_extra_types.coordinate import Latitude, Longitude
class Point(BaseModel):
latitude: Latitude
longitude: Longitude
point = Point(latitude=28.6139, longitude=77.2090)Latitude is limited to -90 through 90 and longitude to -180 through 180. Bounds cannot detect a plausible pair entered in the wrong order.
Parse a five-part cron expression validate-cron
from datetime import datetime, timezone
from pydantic import BaseModel
from pydantic_extra_types.cron import CronStr
class Schedule(BaseModel):
expression: CronStr
schedule = Schedule(expression="*/15 * * * *")
next_run = schedule.expression.next_after(
datetime(2026, 8, 26, tzinfo=timezone.utc), "UTC"
)Install the `cron` extra. `CronStr` expects exactly 5 components and delegates schedule calculations to `cron-converter`.
Split an S3 URI into bucket and key parse-s3-path
from pydantic import BaseModel
from pydantic_extra_types.s3 import S3Path
class ImportJob(BaseModel):
source: S3Path
job = ImportJob(source="s3://invoices/2026/08/report.csv")
print(job.source.bucket) # invoices
print(job.source.key) # 2026/08/report.csv
print(job.source.last_key) # report.csv`S3Path` checks and splits the URI locally. It does not verify credentials, bucket ownership, object existence, or region.
Check an ABA routing number validate-routing-number
from pydantic import BaseModel
from pydantic_extra_types.routing_number import ABARoutingNumber
class USBankTransfer(BaseModel):
routing_number: ABARoutingNumber
transfer = USBankTransfer(routing_number="021000021")The field requires 9 digits and checks the ABA checksum. Passing validation does not establish that the bank or account accepts the transfer.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| pydantic | PyPI | Use core constrained fields and local validators when the project has only a few domain rules. |
| phonenumbers | PyPI | Use its full API directly for phone parsing, formatting, region data, carrier data, and geocoding. |
| pycountry | PyPI | Use direct ISO database lookups when Pydantic annotations and schema output add no value. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

