Beanie
Async Python MongoDB ODM with Pydantic validation — Document-Object Mapper built on Motor + Pydantic v2. Beanie features: Document class (Pydantic BaseModel + MongoDB collection), async CRUD (await Agent.insert(), await Agent.find_one()), query builder (Agent.find(Agent.status == 'idle')), aggregation expressions, link references (Link[Task] for relations), lazy loading, Settings class for collection/index config, migrations via beanie-migration, and built-in JSON serialization. The FastAPI-native MongoDB ODM that makes agent document validation and persistence ergonomic.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Pydantic validation prevents malformed agent documents at the model layer. Beanie query builder uses proper MongoDB operators — less NoSQL injection risk than raw string queries. Store MONGO_URI in environment variables. Enable MongoDB TLS for production agent deployments.
⚡ Reliability
Best When
Your FastAPI agent backend uses MongoDB and you want Pydantic model validation, type-safe queries, and automatic JSON serialization — Beanie eliminates the Motor + Pydantic boilerplate in FastAPI agent services.
Avoid When
You need synchronous MongoDB access, raw Motor control, or your team doesn't use Pydantic.
Use Cases
- • Typed agent document model — class Agent(Document): name: str; status: Literal['idle', 'running', 'error'] = 'idle'; class Settings: name = 'agents'; await Agent(name='SearchAgent').insert() — Pydantic validation + MongoDB persistence in one model
- • FastAPI agent CRUD endpoint — @router.get('/agents/{id}'); agent = await Agent.get(id); return agent — Beanie Document is Pydantic model, serializes to JSON automatically; no manual ObjectId serialization unlike raw Motor
- • Agent linked documents — class Task(Document): agent: Link[Agent]; task = await Task.find_one(Task.id == task_id, fetch_links=True); task.agent.name — Beanie fetches linked Agent document in one query via $lookup
- • Agent query builder — agents = await Agent.find(Agent.status == 'idle', Agent.created_at >= datetime.now() - timedelta(hours=1)).sort(-Agent.created_at).limit(10).to_list() — type-safe query builder with Pydantic field references
- • Agent aggregation pipeline — result = await Agent.find_many(Agent.status == 'completed').aggregate([{'$group': {'_id': '$team_id', 'count': {'$sum': 1}}}]).to_list() — Pydantic-typed aggregation results for agent analytics
Not For
- • Synchronous Python — Beanie is async-only via Motor; for sync MongoDB use MongoEngine or PyMongo directly
- • Non-Pydantic codebases — Beanie's Document class is a Pydantic BaseModel; deep Pydantic integration may conflict with non-Pydantic agent architectures
- • Complex MongoDB operations — Beanie adds abstraction over Motor; for raw aggregation, change streams, GridFS use Motor directly or via Beanie's motor_client access
Interface
Authentication
Auth via Motor/PyMongo connection string. Beanie inherits Motor auth configuration. Store MONGO_URI in environment variables.
Pricing
Beanie is Apache 2.0 licensed. Free for all use. Requires MongoDB server or Atlas.
Agent Metadata
Known Gotchas
- ⚠ await init_beanie() required before any Document operation — init_beanie(database=db, document_models=[Agent, Task]) must be called at app startup (FastAPI lifespan); Document operations before init raise RuntimeError: 'Beanie not initialized'; agent startup must include init_beanie in lifespan or startup event
- ⚠ Link fields require fetch_links=True or are unloaded stubs — task = await Task.find_one(Task.id == id); task.agent is a Link stub not Agent instance; await task.fetch_link(Task.agent) or use fetch_links=True in query; agent code accessing task.agent.name without fetch raises AttributeError
- ⚠ Pydantic v2 vs v1 compatibility — Beanie 1.25+ requires Pydantic v2; older Beanie requires Pydantic v1; agent FastAPI apps with mixed pydantic versions cause ImportError; ensure beanie and pydantic versions are compatible via pip install 'beanie>=1.25'
- ⚠ Document class requires Settings with name — class Agent(Document): class Settings: name = 'agents'; omitting Settings.name uses class name as collection (lowercase); agent code expecting 'agents' collection but getting 'agent' (singular) causes confusion; always set explicit collection name
- ⚠ Index creation runs at init_beanie — Indexes defined in Settings.indexes are created on startup; if MongoDB user lacks createIndex permission, init_beanie fails; agent production deployments need MongoDB user with createIndex; disable auto-creation with allow_index_dropping=False if indexes managed separately
- ⚠ to_list() memory and revision — await Agent.find_all().to_list() loads ALL documents; agent collections with 100k+ documents exhaust memory; use .find().batch_size(100) with async for, or .skip()/.limit() for pagination; Beanie's revision_id automatic field can cause concurrent update conflicts (DocumentRevisionIdWasChanged)
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for Beanie.
Scores are editorial opinions as of 2026-03-06.