Library / SDK
ponyorm/pony avatar
ponyorm/pony

Pony ORM: generator-expression queries for Python 3.10 to 3.14

Pony Object Relational Mapper

3,819 stars255 forksPythonApache-2.0

At a glance

What is it?
Pony is an Apache-2.0 object-relational mapper that turns Python generator expressions into SQL. It supports SQLite, MySQL, PostgreSQL and Oracle, and the package metadata still labels it Beta.
Who is it for?
Adopt Pony when you want query syntax that looks like the rest of your Python and you are targeting SQLite, MySQL, PostgreSQL, Oracle or CockroachDB. Do not adopt it if you need a stable 1.0 API contract, since pyproject.toml still declares Development Status 4 - Beta, or if your team wants an ORM with a large surrounding ecosystem.
Can I use it commercially?
Yes. Apache-2.0 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 last received commits 53 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

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

Editorial analysis

What Pony ORM solves, and which Python teams it fits

Most Python ORMs ask you to describe a query twice: once as a chain of method calls and again in your head, to predict the SQL that will come out. Pony's premise is that a generator expression is already a description of a filter, and that the library can read it. The README states that Pony analyzes the abstract syntax tree of the expression and translates it into a SQL query. The canonical example from the README is a select over Product entities filtered by a name prefix and a cost ceiling.

The audience is narrower than "all Python developers". Pony suits people writing database-backed applications who value short entity declarations and want to inspect generated SQL in a readable, indented form. The README lists interpreter interactivity and error messages that point at the exact failing part of a query as first-class features, which tells you the project is aimed at interactive development rather than at large teams splitting work across layers. If your application is mostly raw SQL with a thin mapping layer, Pony's model is more machinery than you asked for.

How Pony translates a generator expression into SQL

The mechanism is source-level, not runtime-level. Pony receives the generator, walks its abstract syntax tree, and rewrites the comprehension into a dialect-specific SQL statement. The README is explicit that translation happens per database dialect, and it names SQLite, MySQL, PostgreSQL and Oracle as supported targets; the repository topics add cockroach and cockroachdb to that list.

Two consequences follow. First, the query language is bounded by what Pony's translator understands, so an expression it cannot map is a failure at query build time rather than a slow query at execution time. Second, because the mapping is per dialect, the same generator can produce different SQL on different backends, which is exactly why the README treats readable, indented SQL output as a feature rather than a debug aid.

Entity definitions are the other half. The README calls them "compact" and points readers to pony/orm/examples/estore.py in the repository for a worked example. That file is the honest starting point for understanding how much of a schema Pony expects you to declare before queries become useful.

Installing Pony ORM and running a first query

The setup.py long description gives the installation step as a single pip command. No extra system packages are mentioned for the base install; database drivers are a separate concern from the ORM itself, and the repository does not document a bundled driver set.

bash
pip install pony

The package metadata constrains the interpreter. In pyproject.toml, requires-python is ">=3.10,<3.15", and the classifiers list Python 3.10 through 3.14 plus PyPy. Installing outside that range is not a supported configuration.

The README's own query example is a generator passed to select:

python
select(p for p in Product if p.name.startswith('A') and p.cost <= 1000)

That is the line to watch. Pony does not execute the generator as Python; it lifts the expression out and compiles it. If the expression contains something the translator cannot handle, the error message is the one the README describes as pointing to the exact failing part of the query. To see the SQL, the README notes that Pony can display the generated statement in indented form, which is the practical way to confirm your generator produced the query you intended.

For an iterative workflow, the README also mentions running Pony inside a Python interpreter. That is the fastest way to check how a given comprehension is translated before it reaches a codebase.

Where Pony ORM is the wrong tool

The most concrete limitation is stated by the project itself. In pyproject.toml the classifier is "Development Status :: 4 - Beta". Beta is a claim about API stability, and it sits alongside a release history where 0.7.19 and 0.7.18 landed one day apart in August 2024, followed by 0.7.20 on 2026-08-09. That gap is not evidence of abandonment, and the last push to the repository was on 2026-08-10, but it does mean you should not read the version number as a maturity signal.

The second limitation is dialect coverage in practice. Pony works across SQLite, MySQL, PostgreSQL, Oracle and, per the repository topics, CockroachDB. A team on a database outside that set has no path with Pony, and a team that needs to use vendor-specific SQL features will find the generator-expression layer gets in the way rather than helping.

The third is the translation boundary. Because queries are compiled from syntax trees, any expression that falls outside what Pony understands becomes an error you must rewrite, not a fallback. Teams that rely heavily on dynamic query construction, where the query shape is assembled at runtime from arbitrary user input, will spend time fighting that boundary. Pony rewards queries you can write down; it does not reward queries you build programmatically.

Pony ORM compared with SQLAlchemy's approach

SQLAlchemy is the obvious alternative for a Python team choosing an ORM, and the difference is architectural rather than cosmetic. SQLAlchemy exposes a query builder: you compose a statement through Python objects and method calls, and the resulting structure is the query. Pony inverts this. You write an ordinary generator expression, and Pony recovers the query by reading the syntax tree.

That inversion is the whole product. It means Pony queries look like the loops and filters elsewhere in your code, and it means the compiler, not the developer, decides how an expression maps to SQL. It also means Pony's error surface is different: a SQLAlchemy query that is malformed fails at the point where you called the wrong method, while a Pony query that the translator cannot handle fails during the AST analysis the README describes.

SQLAlchemy's query builder is also the safer choice when the query shape is not known until runtime, because building a structure incrementally is what a builder is for. Pony's strength is the opposite case: a fixed set of filters that reads better as a comprehension than as a chain. Neither is a general answer. The repository topics list cockroach and cockroachdb, which is worth noting if you are evaluating Pony specifically for CockroachDB, since that is a target SQLAlchemy reaches through a separate dialect package.

Licence, maintenance and the cost of upgrading

Pony is released under Apache-2.0. The LICENSE file sits in the repository root, and pyproject.toml declares license = "Apache-2.0" with license-files = ["LICENSE"]. The README's own wording is that Pony ORM is an Apache 2.0 licensed open source project. Apache-2.0 includes an explicit patent grant and requires that notices be preserved, which matters if you redistribute Pony inside a larger product. Read the LICENSE file for the terms that apply to you; nothing here is legal advice.

Upgrade cost is shaped by the release cadence rather than by the licence. The three most recent releases are v0.7.20 on 2026-08-09, v0.7.19 on 2024-08-27 and v0.7.18 on 2024-08-26. The two-year span between 0.7.19 and 0.7.20 means a team that pinned to the 2024 line and skipped ahead will be crossing a large amount of accumulated change in one step, and the 0.7.x series offers no compatibility guarantee to lean on. There is a CHANGELOG.md in the repository root, and that file is the place to look before bumping a pinned version.

Development tooling is documented in the README for contributors rather than users: requirements-dev.txt, then ruff for linting and formatting.

bash
python -m pip install -r requirements-dev.txt
python -m ruff check .
python -m ruff format --check .

Those commands check code without modifying it. The README also gives the --fix and non-check variants for applying changes. The repository ships run_tests.py at the top level for running the test suite. None of this is required to use Pony as a dependency.

The ER diagram editor and the docs split

Pony is not only a library. The README points to an online Entity-Relationship Diagram Editor at editor.ponyorm.com, which lets you draw a schema, generate the database schema from that diagram, and then query it with Pony. The setup.py description adds that the editor can generate Pony entity declarations or a SQL script for creating the schema. For prototyping, that is a shorter path than hand-writing entity classes, and it is the part of the project least likely to be replicated by a competing ORM.

The documentation is maintained in a separate repository, ponyorm/pony-doc, and the README asks that documentation issues be filed there rather than on the main repository. That split is a real operational detail: a bug report about unclear docs will be closed on the wrong tracker. Community support runs through Stack Overflow under the ponyorm tag, a Telegram group, and a newsletter, per the README.

Editorial conclusion

Adopt Pony when you want query syntax that looks like the rest of your Python and you are targeting SQLite, MySQL, PostgreSQL, Oracle or CockroachDB. Do not adopt it if you need a stable 1.0 API contract, since pyproject.toml still declares Development Status 4 - Beta, or if your team wants an ORM with a large surrounding ecosystem. Before committing, verify that your Python version falls inside the requires-python range of >=3.10,<3.15, confirm your database is one of the supported dialects, and read the Apache-2.0 LICENSE file in the repository root for the terms that apply to your distribution.

Frequently asked questions

How do I install Pony ORM?

The setup.py long description gives the installation step as pip install pony. The package metadata requires Python >=3.10,<3.15, so check your interpreter version before installing.

Which databases does Pony ORM support?

The README states that Pony translates queries using a specific database dialect and currently works with SQLite, MySQL, PostgreSQL and Oracle. The repository topics additionally list cockroach and cockroachdb.

Is Pony ORM production ready?

The project classifies itself as Development Status 4 - Beta in pyproject.toml, and the current release line is 0.7.x, with v0.7.20 published on 2026-08-09. Treat the version number as a stability signal rather than assuming a 1.0 contract.

Is Pony ORM still maintained?

The repository is not archived and the last push was on 2026-08-10. The release history shows 0.7.19 and 0.7.18 in August 2024 and 0.7.20 on 2026-08-09, so releases are infrequent rather than continuous.

What licence does Pony ORM use?

Pony is released under the Apache 2.0 license, declared in pyproject.toml as license = "Apache-2.0" with the LICENSE file in the repository root. The README repeats that Pony ORM is an Apache 2.0 licensed open source project.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. ponyorm/pony on GitHub
  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/ponyorm-pony.svg)](https://hysenlabs.com/projects/ponyorm-pony)