Sitemap

Pydantic in Python

3 min readApr 6, 2026

--

Pydantic is a Python library used for data validation, parsing, and settings management using Python type hints.

It is different from Python’s built-in library Dataclass for similar uses.

It is widely used in frameworks like FastAPI and modern AI systems.

Since Python is dynamically typed, ie

x = 10
x = "abc"

will not cause errors during runtime. But as the codebase and complexity grow, we need to have a fixed type for what variables can accept as values to prevent data processing errors and system failures, such as when making a mathematical calculation, which can result in errors if the variables involved have values of invalid data types.

Pydantic enforces types at runtime.

Pydantic helps with data validation, IDE type hints, and JSON serialization.

Install pydantic

pip install pydantic

Using Pydantic we create models that define, validate, and structure data.

To create a model

  1. Create a model class that inherits from BaseModel class
  2. Define variables as class variables
  3. Create instances of the model
from pydantic import BaseModel

class User(BaseModel):
name: str
email: str
age: int

user1 = User(
name = "Alice",
email = "alice@gmail.com",
age = 26
)

# or using Dictionary unpacking
user_data = { 'name':'Bob', 'email':'bob@gmail.com', 'age':26 }
user2 = User(**user_data)

# or validate and parse
user3 = User.model_validate(user_data)

If the data passed is valid, the user object is successfully created.

Custom validation

We can use a declarator to define custom validations

# creating a custom validation for age
@validator("age")
def validate_age(cls, value):
if value <= 0:
raise ValueError("age must be greater than 0")
return value

JSON Serialization

Convert Pydantic models to and from JSON.

Get Nimmikrishnab’s stories in your inbox

Join Medium for free to get updates from this writer.

To JSON

user_json1 = user.json()
user_json2 = user.model_dump_json()

From JSON to Pydantic model

user = User.parse_raw(json_str)

Data Types

  • Basic Types: str, int, float, bool
  • Container Types: for collection of data, we can define what’s inside
tags: list[str] = ["abc", "edf"]
q: list[int] = [1,2,3]
count: dict[str, int] = {"abc":1, "efg":3}

Optional Values

Used when the value might not exist

from typing import Optional
description: Optional[str] = None # if no value then value is None

# or
description: str | None = None

Literal Types

When the value must be one of the specific options.

from typing import Literal
progress: Literal["Started","Done"] = "Started"

progress = "Started" # Valid
progress = "Done" # Valid
progress = "OK" # Invalid

Automatic Type Coercion

Pydantic can smartly convert compatible types automatically.

class User(BaseModel):
age: int

user = User(age="25") # no error raised

Pydantic will try to convert the entered value to int, and if no error during conversion, then it will accpet the input string “25” and use int 25.

Default Values

class item(BaseModel):
name: str
quantity: int = 10

Strict Mode

Disables the automatic type coercion.

from pydantic import BaseModel, ConfigDict
class StrictUser(BaseModel):
model_config = ConfigDict(strict = True)
name: str
age: int

# below will throw error
user = StrictUser(name="abc", age="25")

# valid
user = StrictUser(name="abc", age=25)

JSON Schema Generation

Generate JSON schema from models. Useful for API documentation and integration with other tools.

from pydantic import BaseModel, Field
class User(BaseModel):
name: str = Field(min_length = 1, description = "User name")
age: int = Filed(age=0, description= "User age in years")

User.model_json_schema()

# output
{
'properties': {
'name': { 'description':'User name', 'min_length':1, 'type':'string'},
'age': { 'description'= 'User age in years', 'minimum':0, 'type':'integer'}
},
'required':['name','age']
'title':'user'
'type':'Object'
}

Nested Models

Real-world data are often nested

class Person(BaseModel):
name: str
age: int

class Student1(BaseModel):
classes: str
bio: Person

student1 = Student1 (
classes = "physics",
bio = Person(name="Alice", age=25)
)

# list of Person
class Student2(BaseModel):
classes: str
biolist: list[Person]

student_data = { "classes" = "physics",
"biolist" : [{"name":"Alice","age": 25}, {"name":"Bob","age": 25} ]
}
student2 = Student2(**student_data)

Pydantic settings

This is a separate package used for type-safe config from environment variables.

from Pydantic_settings import BaseSettings
class Settings(BaseSettings):
api_key: str
max_connection: int
debug: bool = False

settings = Settings() # redas from environmental variables automatically

Structure LLM output

Using Pydantic for LLM prompts

response = client.responses.parse(
model = "gpt-4o",
input = "Extract students in physics class"'
text_format = Student
)

result = response.output_parsed

Summary

Pydantic is a Python library that helps you define, validate, and structure data using Python type hints. It ensures that the data your application receives or produces is correct, consistent, and well-structured.

--

--