Library / SDK
coleifer/peewee avatar
coleifer/peewee

Peewee: A Small Python ORM for SQLite, MySQL, and PostgreSQL

a small, expressive orm -- supports postgresql, mysql, sqlite, now with asyncio

11,994 stars1,384 forksPythonMIT

At a glance

What is it?
Peewee is a single-file Python ORM with no required dependencies that supports SQLite, MySQL, MariaDB, and PostgreSQL, including asyncio through standard async drivers, and provides schema migration tooling and a large playhouse extensions library.
Who is it for?
Peewee is the right ORM for Python projects that need database access with a small, readable API and no mandatory third-party dependencies, especially when SQLite is the target database. It is less suited to projects that need ORM-level support for complex joins across many related tables, advanced PostgreSQL-specific types, or team-wide conventions enforced through the ORM's scaffolding.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

Single Module, No Required Dependencies

Peewee ships as a single Python file: `peewee.py`. The only install requirement for SQLite support is Python itself, since SQLite is handled by the standard library `sqlite3` module. Other database backends require a driver package that must be installed separately, but the ORM core has no required dependencies.

This design makes peewee practical in constrained environments. A script that needs persistent storage can add peewee with `pip install peewee` and connect to a local SQLite file without pulling in a dependency tree. The README notes that the project has been running production workloads of all sizes since 2010, and it reached version 4.5.2 with a push on 2026-09-27.

The `pwiz` command-line tool (installed with the package) introspects an existing database and generates peewee model definitions from it, which handles the common scenario of adding peewee to a project with an existing schema. The `pyproject.toml` confirms that `pwiz` and `pwmigrate` are both registered as console_scripts, so both tools are available on the PATH after installation without any extra setup step.

Peewee supports PyPy in addition to CPython. The PyPI classifiers list both CPython and PyPy as implementation targets, and the build system skips C extension compilation on non-CPython implementations automatically.

Model Definition and Query Building

Models are defined as classes that inherit from `Model`, with field types as class-level attributes:

python
from peewee import *
import datetime

db = SqliteDatabase('my_database.db')

class BaseModel(Model):
    class Meta:
        database = db

class User(BaseModel):
    username = CharField(unique=True)

class Tweet(BaseModel):
    user = ForeignKeyField(User, backref='tweets')
    message = TextField()
    created_date = DateTimeField(default=datetime.datetime.now)
    is_published = BooleanField(default=True)

This pattern is similar to Django's ORM and SQLAlchemy's declarative API. Queries are composable expressions:

python
User.get(User.username == 'charlie')

The README shows how to write atomic updates using the ORM's expression syntax rather than read-modify-write, which avoids race conditions in concurrent scenarios:

python
Counter.update(count=Counter.count + 1).where(Counter.url == request.url).execute()

Relationships use `ForeignKeyField` with a `backref` that creates a reverse accessor on the related model, and joins are expressed directly in the query:

python
tweets = (Tweet
          .select()
          .join(User)
          .where(User.username.in_(usernames)))

Installing Peewee with Database Backend Support

Base installation:

bash
pip install peewee

SQLite works immediately after this install. For other backends:

bash
pip install peewee[mysql]
bash
pip install peewee[postgres]

For asyncio backends with asyncpg:

bash
pip install peewee[asyncpg]

The package installs two command-line tools: `pwiz` for model generation from an existing schema, and `pwmigrate` for running schema migrations. Python 3.8 or later is required.

On CPython, the build system optionally compiles a C extension (`playhouse/_sqlite_udf`) using Cython if available. This is optional and the pure-Python version works without it. Setting `NO_SQLITE=1` in the environment skips the C extension entirely.

Asyncio Support Through Standard Drivers

Peewee 4.x adds asyncio support through the playhouse module using standard async drivers:

python
import asyncio
from peewee import *
from playhouse.pwasyncio import AsyncPostgresqlDatabase

db = AsyncPostgresqlDatabase('my_app')

class User(db.Model):
    username = CharField(unique=True)

async def main():
    async with db:
        await db.acreate_tables([User])
        huey = await User.acreate(username='huey')

        async with db.atomic():
            huey.message = 'updated'
            await huey.asave()

        async for row in db.iterate(query):
            print(row.user.username)

    await db.close_pool()

asyncio.run(main())

Async methods follow a consistent naming convention: the sync `create` becomes `acreate`, `save` becomes `asave`, and `execute` becomes `aexecute`. Streaming results via a server-side cursor uses `db.iterate(query)`. Supported async drivers are aiosqlite, asyncpg, and aiomysql, each installed via the corresponding extras package.

Playhouse Extensions and Schema Migrations

The `playhouse` directory in the repository contains a large set of extensions that cover PostgreSQL-specific types, SQLite full-text search, connection pool management, Pydantic integration, Flask and FastAPI integration helpers, and the migration runner.

The migration runner (`pwmigrate`) handles schema migrations with diff-based generation. Running `pwmigrate` compares the current database schema against the model definitions and generates migration scripts for the differences. The README links to the migration documentation at docs.peewee-orm.com for the full workflow. Migration scripts are regular Python files that peewee can apply in order.

Framework integration with Flask requires registering database open/close hooks with the application context. With FastAPI, the database connection is managed through lifespan context managers. Pydantic integration is handled by `playhouse.pydantic_utils`, which allows generating Pydantic models from peewee model definitions. This is useful when using peewee for database access and Pydantic for API serialization in the same codebase, since the two model types can be kept in sync.

The extensions are maintained in the same repository as the core ORM, which means they track the same release cycle and version number. The `examples/` directory in the repository includes standalone files demonstrating the adjacency list pattern, analytics queries, FastAPI integration, SQLite FTS with compression, and a Reddit-style ranking algorithm using peewee.

Where Peewee Falls Short

Peewee's query builder exposes most SQL capabilities, but it is not a complete mapping of every PostgreSQL feature. Advanced PostgreSQL-specific types, complex window functions, and certain lateral join patterns may require falling back to raw SQL execution. SQLAlchemy's ORM covers a wider range of database-specific features.

Peewee has no built-in concept of an application factory or registry that organizes models across a large codebase into subsystems or namespaces. Large projects that want models grouped by feature domain need to establish that structure themselves. There is no equivalent to Django's `AppConfig` or SQLAlchemy's declarative base registry with named components.

The single-module design that makes peewee lightweight also means that reading the source is the primary way to understand its internals. The codebase is all in `peewee.py`, a file that is long by design. Teams that debug ORM behavior by reading source code will need to navigate a single large file rather than a modular package structure.

Pagination is supported through the `.paginate(page, page_size)` method on queries. The README shows paginating the user table to page 3 at 20 per page with `User.select().order_by(User.username).paginate(3, 20)`. However, peewee does not provide cursor-based pagination out of the box, which matters for efficiently paginating large result sets without using OFFSET.

Peewee Against SQLAlchemy

SQLAlchemy is Python's most complete database toolkit. Its ORM layer provides an expressive query DSL, relationship loading strategies, unit-of-work pattern implementation, and extensive PostgreSQL-specific type support. It requires installing `SQLAlchemy` and at minimum one DBAPI2 driver.

Peewee's differences are scope and simplicity. SQLAlchemy's full power comes with a steeper learning curve: sessions, identity maps, relationship loading strategies, the distinction between the Core and ORM layers, and the two-phase query execution model all take time to understand correctly. Peewee's API is smaller and more direct. For projects that need basic CRUD with relational data and do not require SQLAlchemy's advanced features, peewee is faster to use correctly without incurring the cognitive overhead of the full SQLAlchemy stack.

Peewee's asyncio support is newer than SQLAlchemy's and covers fewer edge cases. SQLAlchemy's async extension (via `asyncpg` or `aiomysql`) is more mature and better documented for high-concurrency production workloads where connection pool behavior under load matters.

Both are MIT-licensed.

Editorial conclusion

Peewee is the right ORM for Python projects that need database access with a small, readable API and no mandatory third-party dependencies, especially when SQLite is the target database. It is less suited to projects that need ORM-level support for complex joins across many related tables, advanced PostgreSQL-specific types, or team-wide conventions enforced through the ORM's scaffolding. Before using it, confirm that the Playhouse extension covering your specific need (PostgreSQL-specific types, full-text search, schema migrations) is maintained in the current 4.x series.

Frequently asked questions

How do you install peewee for a PostgreSQL project?

Run `pip install peewee[postgres]` to install peewee with the psycopg2-binary driver, or `pip install peewee[psycopg3]` for psycopg3. For asyncio with asyncpg, use `pip install peewee[asyncpg]`. SQLite support is included in the base `pip install peewee` install without additional packages.

Does peewee support asyncio?

Yes. Peewee 4.x includes asyncio support through the playhouse module using standard async drivers: aiosqlite, asyncpg, and aiomysql. Async model methods follow an `a` prefix convention (acreate, asave, aexecute) and transactions use `async with db.atomic()`.

How does peewee compare to SQLAlchemy?

Peewee is a smaller, simpler ORM with a single-module design and no required dependencies, while SQLAlchemy is a full database toolkit with a larger API, more advanced features, and wider database-specific type coverage. Peewee is easier to learn and sufficient for most CRUD applications; SQLAlchemy covers complex query patterns and advanced PostgreSQL types that peewee does not.

Official sources

  1. coleifer/peewee on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/coleifer-peewee.svg)](https://hysenlabs.com/projects/coleifer-peewee)