Beanie
Async Python ODM for MongoDB built on Pydantic. Current version: 2.0.1 (Nov 2025). v2.0 breaking change: dropped Motor in favor of pymongo AsyncMongoClient. Requires Pydantic v2. Inner class Collection removed — use Settings instead. Must call init_beanie() before any document operations. Sync version is Bunnet (separate package).
Common errors
-
beanie.exceptions.CollectionWasNotInitialized
cause This error occurs when Beanie attempts to perform document operations (like find, insert, or update) before the `init_beanie()` function has been called, or if the relevant document models were not included in the `document_models` list during initialization.fixEnsure that `await init_beanie(database=client.db_name, document_models=[YourDocumentClass])` is called at application startup, providing a valid Async PyMongo database instance and a list of all Document classes. -
AttributeError: get_motor_collection
cause This error typically arises in Beanie v2.0.1 because the library transitioned from using Motor to `pymongo.AsyncMongoClient`, removing Motor-specific attributes and methods like `get_motor_collection`. This can also be seen when `fetch_links=True` is used with incompatible setups.fixUpdate your code to use `pymongo.AsyncMongoClient` directly and remove any explicit references to Motor's API, as Beanie v2.x handles the asynchronous client internally. Review the Beanie v2 migration guide for specific changes regarding the Motor to PyMongo Async API transition. -
TypeError: 'AgnosticClientSession' cannot be assigned to 'ClientSession' in function 'find_one'
cause This type error occurs due to incompatibility between `motor` client session types (e.g., `AsyncIOMotorClientSession` or `AgnosticClientSession`) and the `ClientSession` type expected by Beanie's document methods, especially after `motor` updates that introduced stricter type hints.fixEnsure your `motor` and `beanie` versions are compatible. If using sessions, explicitly cast or ensure the session object is compatible with `pymongo.ClientSession` which Beanie expects internally, or check if an updated Beanie version resolves the type mismatch. -
TypeError: beanie.odm.queries.find.FindOne.update() got multiple values for keyword argument 'response_type'
cause This error indicates that the `update()` method is being called with `response_type` both as a positional argument and a keyword argument, or due to changes in the method signature in `beanie` v2.x regarding how `response_type` should be passed.fixPass `response_type` only once as a keyword argument to the `update()` method, typically `response_type=UpdateResponse.NEW_DOCUMENT` or `response_type=UpdateResponse.UPDATE_RESULT`, according to the current Beanie documentation. -
Pydantic 'model_fields' attribute on the instance is deprecated
cause This is a Pydantic v2 deprecation warning (PydanticDeprecatedSince211) indicating that direct access to `model_fields` on a Pydantic model instance is deprecated in favor of accessing it via the model class (e.g., `YourModel.model_fields`).fixWhile this is often an internal warning from Beanie itself that may be addressed in future library updates, if you are directly accessing `model_fields` in your custom code, change `instance.model_fields` to `YourModelClass.model_fields`. Ensure your Beanie version is compatible with Pydantic v2.
Warnings
- breaking Beanie v2.0 dropped Motor. Use pymongo AsyncMongoClient instead of AsyncIOMotorClient. Motor-based code breaks with ImportError or unexpected behavior.
- breaking Inner class Collection removed in v2. Use Settings instead. Collection still referenced in most tutorials and LLM-generated code.
- breaking Beanie v2.0 requires Pydantic v2. Pydantic v1 patterns (@validator, class Config) break. See pydantic registry entry for migration.
- breaking Sync usage removed in beanie. There is no sync version. Use Bunnet (pip install bunnet) for synchronous MongoDB access.
- gotcha init_beanie() must be called before any Document operation. Calling Document.find() or Document.insert() before init raises RuntimeError. Common mistake in FastAPI startup.
- gotcha All document models must be passed to init_beanie(document_models=[...]). Missing a model means that model's collection is not configured — operations silently fail or error.
- gotcha allow_index_dropping defaults to False. Indexes are not deleted automatically when removed from model. Old indexes accumulate silently.
- gotcha The application is unable to connect to the MongoDB server, leading to a pymongo.errors.ServerSelectionTimeoutError during `init_beanie`. This often means MongoDB is not running, is inaccessible from the application's host, or is listening on a different address/port than expected.
- gotcha Applications using Beanie (and PyMongo) will fail with ServerSelectionTimeoutError if the MongoDB server is not running or not accessible at the specified host and port. This is an environmental issue, not a Beanie API usage issue.
Install
-
pip install beanie
Imports
- Document + init_beanie
from motor.motor_asyncio import AsyncIOMotorClient # v2: motor no longer needed from beanie import Document, init_beanie class Product(Document): name: str class Collection: # removed in v2 — use Settings name = 'products' client = AsyncIOMotorClient('mongodb://localhost') await init_beanie(database=client.mydb, document_models=[Product])from pymongo import AsyncMongoClient from beanie import Document, Indexed, init_beanie from pydantic import BaseModel from typing import Optional class Category(BaseModel): name: str class Product(Document): name: str price: Indexed(float) category: Optional[Category] = None class Settings: # v2 style — not Collection name = 'products' async def init(): client = AsyncMongoClient('mongodb://localhost:27017') await init_beanie( database=client.mydb, document_models=[Product] ) - CRUD operations
# Calling before init_beanie() raises RuntimeError product = await Product.find_one({'name': 'Widget'})# All operations require init_beanie() to have been called first # Create product = await Product(name='Widget', price=9.99).insert() # or: product = await Product.insert_one(Product(name='Widget', price=9.99)) # Find products = await Product.find(Product.price < 10.0).to_list() product = await Product.find_one(Product.name == 'Widget') product = await Product.get(product_id) # by _id # Update await product.set({Product.price: 12.99}) # or: product.price = 12.99 await product.save() # Delete await product.delete()
Quickstart
# pip install beanie
from pymongo import AsyncMongoClient
from beanie import Document, Indexed, init_beanie
from typing import Optional
import asyncio
class Product(Document):
name: str
price: Indexed(float)
in_stock: bool = True
class Settings:
name = 'products' # MongoDB collection name
async def main():
client = AsyncMongoClient('mongodb://localhost:27017')
await init_beanie(database=client.shop, document_models=[Product])
# Insert
p = await Product(name='Widget', price=9.99).insert()
print(p.id) # ObjectId
# Query
cheap = await Product.find(Product.price < 20.0).to_list()
one = await Product.find_one(Product.name == 'Widget')
# Update
await one.set({Product.price: 11.99})
# Delete
await one.delete()
asyncio.run(main())