Skip to main content
This guide will walk you through the basics of using lodum to serialize and deserialize Python objects.

Define your data structure

Use the @lodum decorator on your class. You can use standard __init__ methods or dataclasses. Make sure to include type hints, as lodum uses them to understand your data.
from lodum import lodum
from dataclasses import dataclass

@lodum
@dataclass
class User:
    name: str
    age: int
    is_active: bool
Type hints are required. lodum uses them to generate optimized serialization code.

Encode to JSON

Use the json.dumps() function to convert an instance of your class into a JSON string:
from lodum import json

user = User(name="Alex", age=30, is_active=True)

# Encode the object to a JSON string
json_string = json.dumps(user)
print(json_string)
# Output: {"name": "Alex", "age": 30, "is_active": true}

Decode from JSON

Use the json.loads() function to decode a JSON string back to a Python object:
json_data = '{"name": "Barbara", "age": 25, "is_active": false}'

# Decode the JSON string to a User object
barbara = json.loads(User, json_data)

print(f"Name: {barbara.name}, Age: {barbara.age}, Active: {barbara.is_active}")
# Output: Name: Barbara, Age: 25, Active: False
The first argument to loads() is the class type. This enables full type validation and ensures you get the correct object type back.

Multiple formats

You can easily switch between formats. lodum supports JSON, YAML, TOML, MessagePack, CBOR, BSON, and Pickle:
from lodum import json, yaml, toml

user = User(name="Alex", age=30, is_active=True)

# Encode to different formats
json_output = json.dumps(user)
yaml_output = yaml.dumps(user)
toml_output = toml.dumps(user)

print(yaml_output)
# Output:
# name: Alex
# age: 30
# is_active: true

# Decode from YAML
user_from_yaml = yaml.loads(User, yaml_output)

Field customization

Customize individual fields using the field() function:
from lodum import lodum, field, json

@lodum
class User:
    def __init__(
        self,
        # Rename 'user_id' to 'id' in the output
        user_id: int = field(rename="id", default=0),
        
        # This field is required
        email: str = "",
        
        # This field will not be included in the output
        password_hash: str = field(skip_serializing=True, default=""),
        
        # If 'prefs' is missing on decoding, it will default to an empty dict
        prefs: dict = field(default_factory=dict),
    ):
        self.user_id = user_id
        self.email = email
        self.password_hash = password_hash
        self.prefs = prefs

# Encode a user
user = User(email="[email protected]", user_id=123, password_hash="secret")
print(json.dumps(user))
# Output: {"id": 123, "email": "[email protected]", "prefs": {}}

# Decode a user
user_data = '{"id": 456, "email": "[email protected]"}'
user = json.loads(User, user_data)
print(user.user_id)  # 456
print(user.prefs)    # {}

Supported field options

rename
str
Use a different name for the field in the output
skip_serializing
bool
Exclude the field from the output
default
Any
Provide a default value if the field is missing during decoding
default_factory
Callable[[], Any]
Provide a zero-argument function to call for a default value
serializer
Callable[[Any], Any]
A function to call to encode the field’s value
deserializer
Callable[[Any], Any]
A function to call to decode the field’s value
validate
Callable[[Any], None] | list
A function or list of functions to validate the field’s value during decoding

Validation

lodum includes built-in validators to ensure your data meets specific criteria:
from lodum import lodum, field, json
from lodum.validators import Range, Length, Match, OneOf

@lodum
class Product:
    def __init__(
        self,
        name: str = field(validate=Length(min=3, max=50)),
        price: float = field(validate=Range(min=0)),
        category: str = field(validate=OneOf(["electronics", "books", "clothing"])),
        code: str = field(validate=Match(r"^[A-Z]{2}-\d{4}$"))
    ):
        self.name = name
        self.price = price
        self.category = category
        self.code = code

# This will raise a DeserializationError
try:
    json.loads(
        Product, 
        '{"name": "A", "price": -10, "category": "food", "code": "abc"}'
    )
except Exception as e:
    print(f"Validation failed: {e}")

Built-in validators

Range
class
Validates that a value is within a specified range
Range(min=0, max=100)
Range(min=0)  # No maximum
Length
class
Validates that a collection has a length within a specified range
Length(min=3, max=50)
Length(min=1)  # At least 1 item
Match
class
Validates that a string matches a regular expression pattern
Match(r"^[A-Z]{2}-\d{4}$")
OneOf
class
Validates that a value is one of a set of allowed values
OneOf(["small", "medium", "large"])

Error reporting

lodum provides detailed path information when deserialization fails:
from lodum import lodum, json
from lodum.exception import DeserializationError

@lodum
class User:
    def __init__(self, name: str, age: int):
        self.name = name
        self.age = age

json_data = '{"name": "Alex", "age": "not_an_int"}'

try:
    json.loads(User, json_data)
except DeserializationError as e:
    print(e)
    # Output: Error at age: Expected int, got str
The path tracking works through nested objects, lists, and dictionaries (e.g., root.users[2].id).

Working with dictionaries

Convert objects to and from plain Python dictionaries:
import lodum

@lodum
class User:
    def __init__(self, user_id: int = lodum.field(rename="id"), name: str = ""):
        self.user_id = user_id
        self.name = name

user = User(user_id=1, name="Alex")

# Convert to dictionary
data = lodum.asdict(user)
print(data)
# Output: {"id": 1, "name": "Alex"}

# Convert from dictionary
new_user = lodum.fromdict(User, {"id": 2, "name": "Sam"})
print(new_user.user_id)  # 2

JSON schema generation

Generate standard JSON Schema for any @lodum-decorated class:
import lodum
import json

@lodum
class User:
    def __init__(self, id: int, name: str):
        self.id = id
        self.name = name

# Generate the schema
schema = lodum.schema(User)

print(json.dumps(schema, indent=2))
# Output:
# {
#   "type": "object",
#   "properties": {
#     "id": { "type": "integer" },
#     "name": { "type": "string" }
#   },
#   "required": ["id", "name"]
# }
This is particularly useful for documenting your data models or for use with LLM tool definitions.

Streaming serialization

For extremely large datasets, lodum supports O(1) memory streaming serialization:
import sys
from lodum import lodum, json

@lodum
class LargeData:
    def __init__(self, items: list[int]):
        self.items = items

# Serialize a large object directly to stdout (or a file)
data = LargeData(items=list(range(1000000)))
json.dump(data, sys.stdout)
For loading, json.stream() provides lazy, iterator-based deserialization of JSON arrays.

Next steps

API reference

Explore the complete API documentation

Migration guide

Migrating from another library?

Architecture

Learn how lodum works under the hood

Performance

See detailed benchmark results

Build docs developers (and LLMs) love