Open source · Python · Apache-2.0

The Python framework for domain-driven systems.

Your whiteboard, shipped.

Sketch aggregates, events, and bounded contexts. In Protean that model is the architecture, and everything else, the API, the docs, the contracts, is derived from it.

$ pip install protean
Capabilities

Four things almost no framework does.

Four capabilities, each one following from a single idea: the model is the source of truth, and it is trustworthy enough to build everything else on.

01

Domain compiler

Protean parses your model into a machine-readable Intermediate Representation. Docs, API specs, and contracts are derived from it, so they cannot drift from the code.

02

Always-valid domain

Domain objects are always valid, or they do not exist. Four layers of validation run on every change, and the structure is checked before the first request.

03

Progressive architecture

Start with plain domain-driven design. Add CQRS or event sourcing for one aggregate at a time, in the same codebase, with no rewrite.

04

Infrastructure portability

Your domain knows nothing about databases, brokers, or caches. You swap them in configuration, and the model, the tests, and the rules stay untouched.

See it work

Your model, checked in the browser.

A real Protean domain, running on Pyodide in this page. Press check and Protean reads the design back: what each aggregate enforces, what it is missing, why it matters, and how to fix it. The code is editable, and nothing leaves your browser.

store.py
protean check 2 findings
info AGGREGATE_NO_INVARIANTS
Aggregate Order has no pre/post invariants (own or inherited); it enforces no business rules and may be an anemic data holder.
An aggregate is a consistency boundary. With no pre- or post-invariants it enforces no business rules and is usually an anemic data holder rather than a true aggregate.
Fix Add one or more @invariant.pre or @invariant.post methods expressing the business rules the aggregate must always satisfy, or reconsider whether this concept is an aggregate at all.
warning AGGREGATE_WITHOUT_COMMAND_HANDLER
Aggregate Order has no command handler, no write path exists
An aggregate with no command handler has no write path, nothing can change its state.
Fix Add a command handler for the aggregate, or model it as a read-only projection if no writes are expected.

First check downloads the Python runtime, about 8 MB over the wire, then it is cached by the browser.

Everything derived

Maintain one thing by hand.

Add a field to an Order in most stacks and you touch it in nine places: the model, the migration, the schema, the spec, the client types, the docs, the fixtures, the event, the version.

In Protean you touch the model. Everything that can be derived is derived, so the drift that pulls a real system away from its own drawing has nowhere to enter.

12,000+
tests, about three lines of test per line of code
3.11 → 3.14
every commit runs the core suite across all of them
100k lines
a real system runs on Protean in production today
Apache-2.0
open core, no lock-in, the model is plain Python you own
Whitepaper

Your Domain Model Is the Architecture

One source of truth, an always-valid domain, and why both matter more now that machines write the code.

Read the whitepaper →

Built for backend systems whose hard part is the business rules and the states things move through. It is honest about where it stops. Is Protean for you?