For years, I thought the problem was my code.
I optimized functions.
I profiled bottlenecks.
I rewrote entire modules because they "felt" slow.
Turns out, the biggest performance improvement I ever made wasn't rewriting Python.
It was replacing one library.
Not my framework.
Not my database.
Just one library.
And I haven't looked back since.
The Library: msgspec
If you've been living in the world of json, dataclasses, or even pydantic, there's a good chance you've never seriously looked at msgspec.
I ignored it too.
Big mistake.
It combines incredibly fast serialization with runtime validation while using surprisingly little memory.
For applications processing thousands of API requests every minute, those savings aren't theoretical.
They add up.
Fast.
Install it.
pip install msgspecThat's the easy part.
The interesting part comes next.
Most Python APIs Waste Time Here
Imagine receiving this JSON.
{
"id": 4821,
"username": "alex",
"email": "alex@example.com",
"active": true,
"roles": ["admin", "editor"]
}Most developers do something like this.
import json
data = json.loads(payload)
username = data["username"]
email = data["email"]
roles = data["roles"]Nothing wrong with it.
Until your application starts doing this millions of times.
Dictionary lookups.
Manual validation.
Missing keys.
Wrong types.
Unexpected values.
Eventually your code starts looking like defensive programming instead of business logic.
Here's What I Switched To
import msgspec
class User(msgspec.Struct):
id: int
username: str
email: str
active: bool
roles: list[str]
decoder = msgspec.json.Decoder(User)
user = decoder.decode(payload)
print(user.username)That's it.
No manual parsing.
No nested dictionary access.
No endless if "username" in data.
If the JSON is invalid…
It fails immediately.
Exactly where it should.
The Hidden Superpower Nobody Talks About
Serialization is only half the story.
The real magic is memory usage.
Let's create one million objects.
import msgspec
class Point(msgspec.Struct):
x: int
y: int
points = [Point(i, i + 1) for i in range(1_000_000)]Because Struct doesn't create a normal __dict__ for every object, memory usage stays surprisingly low.
If you've ever watched Docker containers slowly consume RAM until Kubernetes politely kills them…
You'll appreciate this.
Benchmark It Yourself
Never trust benchmarks from strangers on the internet.
Including mine.
Here's a tiny benchmark.
import json
import msgspec
import time
payload = b'{"id":1,"name":"Python","stars":99999}'
class Repo(msgspec.Struct):
id: int
name: str
stars: int
decoder = msgspec.json.Decoder(Repo)
N = 500000
start = time.perf_counter()
for _ in range(N):
json.loads(payload)
print("json:", time.perf_counter() - start)
start = time.perf_counter()
for _ in range(N):
decoder.decode(payload)
print("msgspec:", time.perf_counter() - start)Run it.
On your machine.
Your numbers won't exactly match mine.
That's okay.
What matters is the difference.
Here's Something Most Articles Never Mention
Nested decoding.
Real applications don't receive flat JSON.
They receive monsters.
{
"user": {
"profile": {
"address": {
"city": "London"
}
}
}
}Instead of digging through dictionaries…
city = (
data["user"]
["profile"]
["address"]
["city"]
)You define the structure once.
import msgspec
class Address(msgspec.Struct):
city: str
class Profile(msgspec.Struct):
address: Address
class User(msgspec.Struct):
profile: Profile
class Response(msgspec.Struct):
user: UserNow everything becomes autocomplete-friendly.
Your IDE suddenly understands your data.
That alone saves hours every month.
One Trick That Completely Changed My API Layer
Most REST APIs do this.
request = json.loads(body)
name = request["name"]
age = int(request["age"])
country = request["country"]Now imagine validation happens automatically.
class CreateUser(msgspec.Struct):
name: str
age: int
country: str
decoder = msgspec.json.Decoder(CreateUser)
user = decoder.decode(body)Wrong type?
Instant exception.
Missing field?
Instant exception.
Unexpected object?
Instant exception.
Less code.
Fewer bugs.
More confidence.
You Can Serialize Just As Fast
Encoding is equally straightforward.
encoder = msgspec.json.Encoder()
user = CreateUser(
name="Alice",
age=28,
country="Canada"
)
payload = encoder.encode(user)No custom encoder.
No helper function.
No conversion dance.
My Favorite Feature
Default values.
class Config(msgspec.Struct):
debug: bool = False
retries: int = 3
timeout: float = 5.0That's enough.
No factory.
No boilerplate.
Sometimes the simplest features are the ones you end up using every day.
The Performance Rabbit Hole
Curious how much object creation itself costs?
Here's a fun experiment.
import time
from dataclasses import dataclass
import msgspec
@dataclass
class UserA:
id: int
score: float
class UserB(msgspec.Struct):
id: int
score: float
N = 1_000_000
start = time.perf_counter()
for i in range(N):
UserA(i, 99.5)
print("dataclass:", time.perf_counter() - start)
start = time.perf_counter()
for i in range(N):
UserB(i, 99.5)
print("msgspec:", time.perf_counter() - start)I love microbenchmarks.
Not because they predict production performance.
Because they teach you where Python spends its time.
When You Shouldn't Use It
Every library has trade-offs.
If you're writing a quick automation script that parses one JSON file…
You probably don't need it.
If you're building APIs…
Message queues…
Data pipelines…
ETL systems…
Background workers…
Or anything that repeatedly serializes data…
It's worth serious consideration.
Sometimes the fastest code isn't clever.
It's choosing a better tool.
One Lesson I Learned After Four Years of Python
Early in my career, I believed becoming a better Python developer meant learning more syntax.
Then I thought it meant mastering design patterns.
Later, I became obsessed with algorithms.
Today?
I spend more time replacing libraries than rewriting functions.
A mature codebase isn't necessarily the one with the smartest code.
It's the one where every dependency earns its place.
The best optimization I've made this year wasn't deleting 500 lines of Python.
It was replacing one import statement.
Sometimes that's all it takes.
Enjoyed this one? Show some love with 50 claps 👏 and hit Follow to stay tuned for upcoming posts packed with fresh perspectives. Appreciate your time — see you in the next article! 🌟 Thanks a lot for reading! 🙌