Tech News
← Back to articles

Keep Pydantic out of your Domain Layer

read original related products more articles

Keep Pydantic out of your Domain Layer

Jul 22 2025

You’re probably reading this because you’re using Pydantic yourself. Maybe you’re building a FastAPI application and hit a point where it started getting too big to manage, and you realized you need better separation of concerns. Perhaps you’ve started adopting a clean architecture or onion architecture kind of layering to keep business logic separate from application logic, aiming for better maintainability and testability. But Pydantic is starting to creep into every layer, even your domain, and it starts to itch. You know you don’t want that, but you’re not quite sure how to fix it. If that’s you, then you’re standing at the same crossroads I once did. Keep reading :)

You’ve probably been spoiled by the amazing features Pydantic has to offer. It’s incredibly convenient to spin up an entire hierarchy of nested objects by simply passing in a multilayered dictionary. Which makes Pydantic fantastic for data validation and that’s probably the main reason you should use it for.

Pfff, who even cares? Yeah yeah, with great power comes great responsibility… But why shouldn’t I just use Pydantic everywhere? It’s so convenient, what’s the harm?

And like almost everything in software engineering… it depends. If you’re building a simple CRUD app, it might feel like overkill to write a bunch of extra boilerplate just to keep Pydantic out of everything except the edges of your application, like the presentation and infrastructure layers. But as your application grows, this tight coupling can turn into a liability. That’s when concerns like loose coupling and separation of responsibilities start to matter more. The less your core logic depends on specific tools or libraries, the easier it becomes to maintain, test, or even replace parts of your system without causing everything to break.

But how to translate Pydantic BaseModels to Plain Old Python Objects?

There are a few ways to approach this, and one of them is using Dacite. I’ll start with a quick and simple example using that library alongside the most obvious alternative. After that, I’ll demonstrate how Dacite can be used in a more structured, layered setup, with a clear separation of concerns between the different parts of your application.

Dacite

What mainly makes it difficult to convert a Pydantic BaseModel to plain Python dataclasses is that, quite obviously, it takes a lot of manual work to re-initialize the nested structures, especially if you already have a fairly deep object hierarchy. Dacite is a tool that takes care of much of this heavy lifting for you and was specifically designed with this purpose in mind: initializing nested dataclasses from a dictionary. So here’s a small and overly simplified example.

... continue reading