Pydantic in Python: Data Validation Guide With Examples

If you've ever written a function that manually checks whether a dictionary has the right keys, the right types, and sane values before using it, you've already felt the problem Pydantic solves. Pydantic is a Python library that validates and parses data using your existing type hints, so you describe the shape of your data once and get automatic validation, clear errors, and serialization for free.
This guide walks through Pydantic's core BaseModel pattern, field constraints, custom validators, serialization, and how it powers request and response handling in FastAPI, with runnable code at every step.
Transform Your Career
Choose from our industry-leading programs designed for career success
Modern Software and AI Engineering Program
Master full-stack development with AI integration
+1000 moreModern Data Science and ML with specialisation in AI
Advanced data science techniques with AI specialization
+1000 moreAdvanced AIML with Specialisation in Agentic AI
Deep dive into AIML with focus on Agentic systems
+1000 moreDevOps, Cloud & AI Platform Engineering
Build and manage AI-powered cloud infrastructure
+1000 moreAI Engineering Advanced Certification by IIT-Roorkee
Premier AI engineering certification from IIT-Roorkee
What is Pydantic?
Pydantic is a data validation and parsing library that uses standard Python type hints to define the expected shape of your data. Instead of writing manual if isinstance(...) checks, you declare a class with annotated fields, and Pydantic handles validating, coercing and parsing incoming data against those annotations automatically.
Under the hood, Pydantic v2 runs on a Rust-based core (pydantic-core), which makes validation fast enough to use in performance-sensitive paths like API request handling, not just as a convenience layer. For the full, authoritative reference, see the official Pydantic documentation.
If you want a refresher on Python's type hint system before diving in, see Advanced Python, since Pydantic's entire API is built on top of it.
Why Use Pydantic? (The Problem It Solves)
Most real-world Python code eventually has to deal with data it doesn't fully control: JSON from an external API, form submissions, config files, environment variables. Without a validation layer, you end up writing repetitive, error-prone checks by hand, and bugs slip through when a check gets missed or a type assumption turns out wrong three functions downstream.
Pydantic solves this by centralizing validation in one place: the model definition. You declare what a valid User or Order looks like once, and every part of your code that creates one of these objects gets the same validation, with the same clear error messages, for free. This matters most anywhere you're handling untrusted or external data, which is why Pydantic shows up so often in API backends, config management and data pipelines.
If you're still building comfort with Python's basic type system, this is a good foundation first: Data Types in Python. For a structured path through Python fundamentals more broadly, see Python for Beginners.
Pydantic BaseModel (First Example)
Every Pydantic model inherits from BaseModel. You define fields as class attributes with type annotations, and Pydantic validates any data passed in against those types.
Output:
Notice that age="29" was passed as a string but printed as an integer. Pydantic performs sensible type coercion by default, in this case parsing a numeric string into an int, rather than rejecting it outright.
Now here's what happens with genuinely invalid data:
Output (simplified):
e.errors() returns a structured list of every validation failure, including which field failed (loc), why (msg), and what was actually passed in (input), which makes it easy to turn into a useful error response rather than a raw traceback. For more on how Python functions handle exceptions like this one, see Functions in Python.
Scaler Placement Report and Statistics
Scaler learners achieved 2.5x salary growth with average post-Scaler CTC reaching ₹23L.
Field Types, Constraints and Defaults
Type hints alone tell Pydantic what type a value should be, but real-world validation often needs more: minimum lengths, numeric ranges, default values. That's what Field() is for.
Output:
Output:
A few of the most commonly used Field() constraints:
| Constraint | Applies To | What It Does |
|---|---|---|
| gt, ge | Numbers | Value must be greater than / greater than or equal to |
| lt, le | Numbers | Value must be less than / less than or equal to |
| min_length, max_length | Strings, lists | Enforces length boundaries |
| pattern | Strings | Value must match a regex pattern |
| default | Any | Fallback value if none is provided |
| default_factory | Any | A function called to generate a default (useful for lists, dicts, timestamps) |
Custom Validators
Field constraints cover common cases, but sometimes you need custom logic, checking a username format, or comparing two fields against each other. Pydantic v2 handles this with field_validator for single-field checks and model_validator for checks that span multiple fields.
Output:
Output:
Turn Learning into Career Growth
Serialization and Parsing
Validation is half of what Pydantic does. The other half is moving data between Python objects, dictionaries and JSON cleanly in both directions.
python
from pydantic import BaseModel
class Order(BaseModel):
id: int
item: str
price: float
order = Order(id=101, item="Mouse", price=799.0)
# Model to dict
print(order.model_dump())
# Model to JSON string
print(order.model_dump_json())
# dict to Model
data = {"id": 102, "item": "Monitor", "price": 12000.0}
order2 = Order.model_validate(data)
print(order2)
# JSON string to Model
json_data = '{"id": 103, "item": "Webcam", "price": 2500.0}'
order3 = Order.model_validate_json(json_data)
print(order3)
Output:
{'id': 101, 'item': 'Mouse', 'price': 799.0}
{"id":101,"item":"Mouse","price":799.0}
id=102 item='Monitor' price=12000.0
id=103 item='Webcam' price=2500.0
model_dump() gives you a plain Python dict, model_dump_json() gives you a JSON string directly, and model_validate() / model_validate_json() go the other direction, turning a dict or JSON string back into a validated model instance. This pair of methods is what makes Pydantic models a natural fit for reading external JSON and writing API responses.
Pydantic with FastAPI
FastAPI uses Pydantic models directly as the type hints for request bodies and response types, which is a big part of why the two are so often used together.
python
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
in_stock: bool = True
@app.post("/items/")
def create_item(item: Item):
return item
When a request hits this endpoint, FastAPI automatically validates the incoming JSON body against the Item model before your function even runs. If the data doesn't match malformed types, missing required fields, values that fail a constraint, FastAPI returns a 422 response with Pydantic's structured error details, without you writing any manual validation code.
This same model also drives FastAPI's automatically generated OpenAPI schema and interactive docs, since the field types and constraints you declared for validation double as the schema definition. For a closer look at building APIs this way, see REST API with Django, FastAPI with TensorFlow, and the official FastAPI documentation. If you want to build these skills as part of a structured program, see the Data Science Course or browse the full course catalogue.
FAQs
What is Pydantic in Python?
Pydantic is a library that validates and parses data using Python type hints, ensuring objects conform to the field types and constraints you declare, and raising clear errors when they don't.
What is BaseModel in Pydantic?
BaseModel is the base class you inherit from to define a model. Every annotated attribute on the class becomes a field that Pydantic validates whenever an instance is created.
How does Pydantic validate data?
It checks incoming values against each field's type hint and any constraints defined with Field(), coercing compatible values (like a numeric string into an int) where reasonable, and raising a ValidationError with structured details when a value doesn't fit.
What is the difference between Pydantic and a dataclass?
A standard Python dataclass stores typed data but doesn't validate it at runtime, incorrect types are simply accepted. Pydantic adds automatic validation, parsing and serialization (model_dump, model_validate, JSON conversion) on top of the same type-hint-based approach.
How is Pydantic used in FastAPI?
FastAPI uses Pydantic models as type hints for request bodies and response types, automatically validating incoming requests and serializing outgoing responses, while also generating the OpenAPI schema from the same model definitions.
How do I add custom validation in Pydantic?
Use the field_validator decorator for rules that depend on a single field, or model_validator for rules that need to compare multiple fields against each other, such as confirming two password fields match.




