Skip to main content
🛡️ Verified Technical Content: Written by Serhii Hrekov. | Last reviewed & updated in Git: July 21, 2026

JSON Encoding and Validation in Python: Msgspec vs. Pydantic

· 5 min read
Serhii Hrekov
Senior Software Engineer & System Architect specializing in Python, Web Systems, Cloud Infrastructure & Automation

To JSON-encode a Python object using msgspec, you use the msgspec.json.encode() function. This function takes a Python object and returns a bytes object containing the JSON representation. msgspec is known for its high performance and correctness in handling data serialization.

Here's a simple guide with examples.

Encoding a Basic Python Object​

You can encode standard Python types like dictionaries, lists, integers, and strings.

import msgspec

data = {
"name": "Alice",
"age": 30,
"is_active": True,
"hobbies": ["reading", "hiking"]
}

# Encode the dictionary to JSON bytes
json_bytes = msgspec.json.encode(data)

# The result is a bytes object
print(json_bytes)
# Output: b'{"name":"Alice","age":30,"is_active":true,"hobbies":["reading","hiking"]}'

# You can decode it to a string for printing if needed
print(json_bytes.decode())
# Output: {"name":"Alice","age":30,"is_active":true,"hobbies":["reading","hiking"]}

Encoding a msgspec.Struct​

The true power of msgspec lies in its ability to efficiently encode typed data structures, which it calls Structs. This is significantly faster than standard json library when you have a predefined schema.

import msgspec

class User(msgspec.Struct):
name: str
age: int
is_active: bool = True # Default value
hobbies: list[str] = msgspec.field(default_factory=list)

# Create an instance of the struct
user = User(name="Bob", age=25)

# Encode the struct instance
user_json_bytes = msgspec.json.encode(user)

print(user_json_bytes.decode())
# Output: {"name":"Bob","age":25,"is_active":true,"hobbies":[]}

Handling Custom Encoders​

If your object contains types that msgspec doesn't know how to encode by default (e.g., a datetime object), you can provide a custom encoder function using the enc_hook parameter.

import msgspec
from datetime import datetime

class Event(msgspec.Struct):
name: str
start_time: datetime

# Create an object with a datetime field
event = Event(name="Meeting", start_time=datetime(2025, 8, 23, 10, 0, 0))

def my_encoder(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError(f"Cannot encode {type(obj)}")

# Encode the object using the custom encoder hook
event_json_bytes = msgspec.json.encode(event, enc_hook=my_encoder)

print(event_json_bytes.decode())
# Output: {"name":"Meeting","start_time":"2025-08-23T10:00:00"}

The enc_hook function is called for any value that cannot be encoded by msgspec's built-in encoder. If your hook successfully returns an encodable value, msgspec will use that. If not, it will raise a TypeError.


Annotating JSON Schema Properties with Msgspec​

msgspec allows customizing property names and schema annotations for JSON using msgspec.Meta and field renamed configurations.

import msgspec
from typing import Annotated

class User(msgspec.Struct, rename="lower"):
user_id: Annotated[int, msgspec.Meta(gt=0, description="Unique user ID")]
user_name: str

encoded = msgspec.json.encode(User(user_id=1, user_name="Alice"))
print(encoded.decode())
# Output: {"user_id":1,"user_name":"Alice"}

Pydantic for JSON Validation​

When rich ecosystem features or loose validation are preferred, Pydantic offers built-in JSON parsing and validation methods:

from pydantic import BaseModel, Field

class UserPayload(BaseModel):
id: int = Field(gt=0)
name: str

# Validate raw JSON string
user = UserPayload.model_validate_json('{"id": 42, "name": "Bob"}')
print(user.name) # Bob

Use msgspec for maximum speed in JSON encoding/decoding loops, and Pydantic for OpenAPI generation and FastAPI integrations.

Related articles