A minimalist, zero-coercion validation library for Python.
Project description
iron-monk
Business constraint validation for people who hate data mutation.
The fastest Pure-Python validator. 0 Dependencies. 100% Type-Safe.
📖 Read the official documentation here: benesgarage.github.io/iron-monk
🤖 Using an AI coding agent? Point it at llms.txt for a single-fetch index of the public API, llms-ctx.txt for a token-trimmed essentials digest, or llms-full.txt for the concatenated full docs. Agents working inside your project will also pick up AGENTS.md automatically.
Installation
Install via your preferred package manager:
# Using pip
pip install iron-monk
# Using uv
uv add iron-monk
# Using poetry
poetry add iron-monk
iron-monkuses themonknamespace. Alwaysimport monkin your code.
Quickstart
from typing import Annotated
from monk import monk, validate
from monk.constraints import Email, Interval, Len
@monk
class User:
# No base class, no magic. Just your data.
email: Annotated[str, Email]
age: Annotated[int, Interval(ge=18)]
tags: list[Annotated[str, Len(min_len=2)]] # auto per-element validation
user = User(email="not-an-email", age=12, tags=["a"])
validate(user) # Aggregates ALL THREE errors. Never fails fast.
When validation fails, iron-monk returns every failure in one structured response:
from monk.exceptions import ValidationError
try:
validate(user)
except ValidationError as e:
print(e.errors)
# [{'field': 'email', 'message': 'Must be a valid email address.', 'code': 'Email'},
# {'field': 'age', 'message': 'Must be greater than or equal to 18.', 'code': 'Interval'},
# {'field': 'tags[0]', 'message': 'Must have a minimum length of 2.', 'code': 'Len'}]
print(e.flatten()) # → list[str] for logs
print(e.to_rfc7807()) # → RFC 7807 problem-detail dict for HTTP APIs
Custom constraints in 3 lines
from monk import constraint
@constraint
class DivisibleBy:
divisor: int
def validate(self, value: int) -> None:
if value % self.divisor != 0:
raise ValueError(f"Must be divisible by {self.divisor}.")
The Toolkit
A comprehensive suite of 60+ built-in constraints — including the kind most libraries punt on:
CSV— validate comma-separated strings in place, no list allocationCron— POSIX and AWS EventBridge scheduling stringsHash/CreditCard/ISBN— checksum-verified identifiers, zero third-party depsRef+When/Switch— declarative cross-field validation that resolves at runtime- PATCH semantics —
validate_dict(payload, Schema, partial=True)for incremental updates Not/AnyOf/AllOf— invert and compose any constraint into richer rules
Plus the usual suspects (Email, URL, UUID, JWT, Slug, IPAddress, …) and string/numeric/datetime/path guards.
Performance
iron-monk doesn't compromise on speed.
Tested on Python 3.14.4, primarily executing 100,000 simple primitive validations.
| Metric | iron-monk(v0.26.0) |
msgspec(v0.21.1) |
pydantic(v2.13.4) |
attrs(v26.1.0) |
marshmallow(v4.3.0) |
|---|---|---|---|---|---|
| Package Size | 0.10 MB |
0.44 MB |
5.88 MB |
0.21 MB |
0.17 MB |
| Cold Start | 39.46ms |
43.40ms |
75.17ms |
50.59ms |
61.94ms |
| Object (100k) | 0.158s |
0.013s |
0.054s |
0.086s |
N/A |
| Dict (100k) | 0.095s |
0.058s |
0.051s |
N/A | 0.440s |
| Nested Dict (100k) | 0.324s |
0.071s |
0.056s |
N/A | 1.403s |
| Invalid Dict (100k) | 0.235s |
0.082s |
0.075s |
N/A | 1.017s |
| Sanitized Dict (100k) | 0.104s |
0.060s |
0.050s |
N/A | 0.429s |
| Partial Dict (100k) | 0.065s |
N/A | N/A | N/A | 0.267s |
| Union Dict (100k) | 0.119s |
0.056s |
0.033s |
N/A | N/A |
| Large List (10k × 1k items) | 1.085s |
0.056s |
0.185s |
N/A | N/A |
| Refs / Cross-Field (100k) | 0.235s |
N/A | N/A | N/A | N/A |
| Guard Access (1M attr reads) | 0.257s (plain dataclass: 0.025s) |
N/A | N/A | N/A | N/A |
| Function Call (100k) | 0.171s |
N/A | 0.050s |
N/A | N/A |
The Takeaway: Rust-backed libraries win on raw loop speed, but iron-monk is the most efficient choice for the modern cloud. Faster cold starts, zero dependencies, and the only entry on the board that natively handles PATCH updates, payload sanitization, and standalone constraint execution make it the best-in-class validator for AWS Lambda, serverless environments, and CI/CD pipelines where install time and the network round trip are the real bottlenecks.
👉 See our benchmarking methodology →
Why iron-monk
Most validation libraries do too much — they coerce, force you to inherit from a base class, and stop at the first error. iron-monk flips all three.
- Zero coercion:
"123"is never silently rewritten to123. Wrong format = error. - Zero base classes: a
@monkclass is a plaindataclass. NoBaseModel, no metaclass. - Zero fail-fast: every field is checked. Get every error in one shot.
- Annotation is the schema: constraints live inside
typing.Annotated. No model layer to keep in sync.
Integrations
iron-monk drops into any modern Python project. Battle-tested recipes for:
- Strawberry GraphQL —
errors-as-datafor inputs,Maybe[T]integration - Starlette (ASGI) — RFC 7807 exception handlers, dict-mode and DTO-mode handlers
- SQLAlchemy 2.0 / Tortoise ORM — DTO pattern at the API boundary
- tyro — validate dataclass-driven CLIs
- beartype — stack runtime type-checking under business constraints
- App configuration — fail-fast environment-variable validation on boot
Feedback
PRs are not currently being accepted (see CONTRIBUTING.md), but bug reports, feature requests, and integration use cases are welcome.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file iron_monk-0.31.0.tar.gz.
File metadata
- Download URL: iron_monk-0.31.0.tar.gz
- Upload date:
- Size: 68.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b6085aebcb44fc99c5c7ad851ac3b03633bc545e39dbf2db02d7db250dbcc6af
|
|
| MD5 |
2730106fa59969d434a082ff6269d222
|
|
| BLAKE2b-256 |
d9516f48602c1dd83a1e2b4d67dab44e2cf46d48f4943f15e04ad989a0c04a0f
|
Provenance
The following attestation bundles were made for iron_monk-0.31.0.tar.gz:
Publisher:
publish.yml on benesgarage/iron-monk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
iron_monk-0.31.0.tar.gz -
Subject digest:
b6085aebcb44fc99c5c7ad851ac3b03633bc545e39dbf2db02d7db250dbcc6af - Sigstore transparency entry: 1633013991
- Sigstore integration time:
-
Permalink:
benesgarage/iron-monk@c270b10a89427c37764bcc9b1d6e7797309ef4e6 -
Branch / Tag:
refs/tags/0.31.0 - Owner: https://github.com/benesgarage
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c270b10a89427c37764bcc9b1d6e7797309ef4e6 -
Trigger Event:
release
-
Statement type:
File details
Details for the file iron_monk-0.31.0-py3-none-any.whl.
File metadata
- Download URL: iron_monk-0.31.0-py3-none-any.whl
- Upload date:
- Size: 37.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f73a350baf9923239b8f2e2b17ea13c6b1e1650b27d9b74d3b9ea171b462bbc
|
|
| MD5 |
bef71329d93747ec6981bbfc50fa915f
|
|
| BLAKE2b-256 |
f811c49da862749ac1ccee8d640ed6c9e6a32cfcf6654e43bab90990aa97eb6f
|
Provenance
The following attestation bundles were made for iron_monk-0.31.0-py3-none-any.whl:
Publisher:
publish.yml on benesgarage/iron-monk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
iron_monk-0.31.0-py3-none-any.whl -
Subject digest:
7f73a350baf9923239b8f2e2b17ea13c6b1e1650b27d9b74d3b9ea171b462bbc - Sigstore transparency entry: 1633014025
- Sigstore integration time:
-
Permalink:
benesgarage/iron-monk@c270b10a89427c37764bcc9b1d6e7797309ef4e6 -
Branch / Tag:
refs/tags/0.31.0 - Owner: https://github.com/benesgarage
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@c270b10a89427c37764bcc9b1d6e7797309ef4e6 -
Trigger Event:
release
-
Statement type: