Library / SDK
vrana/notorm avatar
vrana/notorm

NotORM: a PHP library where the relationships are the interesting part

NotORM - PHP library for simple reading data from the database

849 stars156 forksPHPNOASSERTION

At a glance

What is it?
NotORM is a PHP library for reading data out of a database, and the thing it is actually built around is table relationships rather than model classes. It runs on any PDO-supported database, it comes with an upgrade guide from the first major version, and its licence is the one detail in the repository that needs checking before you ship it.
Who is it for?
Adopt NotORM if you are reading from a database in PHP and want relationships traversed inline rather than through a model layer you have to write, since that is the feature the project is organised around. Do not adopt it for writes, because the README describes it as a library for simple working with data and the usage it documents is all reading.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly PHP, according to GitHub's language statistics.

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

Editorial analysis

An ORM organised around relations, not around models

NotORM is described as a PHP library for simple working with data in the database, and the repository description calls it a library for simple reading data from the database.

The sentence that matters is the second one in the README. The most interesting feature is very easy work with table relationships, and overall performance is also very important, with the claim that NotORM can actually run faster than a native driver.

That is an unusual framing for an ORM, and it says something about the design. A conventional mapper gives you model classes with relations declared on them, and the library then does the work of building the joins. NotORM is organised the other way around: you ask for a table, you get rows, and reaching a related table is a property access on the row rather than a declared relation. The table relationships are the feature, not an annotation.

The consequence is that the library is for reading. The usage in the README is entirely reads, and the description in the repository listing says the same, and no write API is documented anywhere in the README. For a project that mostly renders data, that is a sensible scope. For a project that writes, it means you are looking at a different tool.

The other thing the README leads with is the performance claim, and it is worth putting next to the relationship story, because a lazy loader that fetches related rows one at a time is exactly the design that would be slow. The claim of being faster than a native driver therefore implies the relationship traversal is batched rather than chatty, and that is the first thing you would want to see in a benchmark.

The licence in the repository listing is recorded as a custom one that GitHub cannot classify, with the details in the licence file, and that is worth checking before you put it in a product.

The usage example is the whole documentation

The README's example is short, and it is the fastest way to understand the API because it shows a full traversal in one pass.

php
<?php
require "vendor/autoload.php";
$connection = new PDO("mysql:dbname=software");
$software = new NotORM\NotORM($connection);

foreach ($software->application()->order("title") as $application) { // get all applications ordered by title
    echo "$application[title]\n"; // print application title
    echo $application->author["name"] . "\n"; // print name of the application author
    foreach ($application->application_tag() as $application_tag) { // get all tags of $application
        echo $application_tag->tag["name"] . "\n"; // print the tag name
    }
}

The structure is worth reading line by line. The object is constructed from a plain PDO connection, so there is no configuration object, no connection factory and no bootstrap beyond Composer's autoloader. The table is then reached through a method named after it, application, and the result supports a chainable order by column, so the ordering is part of the query rather than something you do in PHP afterwards.

Rows are read like arrays, with the column name in square brackets, and a related row is read the same way, which is why the author line is a single expression rather than a separate variable. A related collection is a method call, application_tag, and it returns rows you iterate, each of which has its own relation, so the tags of a tag can be reached the same way.

The naming convention is that the method name is the table name in a singular form, and the relation methods follow the same rule. So the library gives you a query interface whose vocabulary is the database schema, and nothing else. That is a design you either like immediately or never do, and there is no middle ground in it.

Requirements are short, and the upgrade path is documented

The requirements section fits in two lines, and that is a genuine sign of a small dependency surface.

PHP 8.0 or newer, and any database supported by PDO. The README adds which databases it has actually been tested with, and the list is long: MySQL, SQLite, PostgreSQL, MS SQL and Oracle. That is the practical difference between running on a PDO driver and being supported, and the fact that the SQLite entry is in the list means you can develop the whole data layer against a file before touching the production server.

Installation is a single Composer requirement:

bash
composer require vrana/notorm

There is no service provider, no package discovery entry and no container to register, because the library is not a framework component. You construct it yourself with a connection, which is also what makes it testable.

One piece of housekeeping is called out explicitly. Upgrading from NotORM 1 is covered in a separate upgrade document in the repository, under the upgrade directory, and the README links it as the way to migrate. A library that has changed shape between major versions and writes that migration down is doing the right thing, and for a project that adopted the first version, that document is the place to start.

The repository listing also shows an upgrade directory alongside the source, the tests, the upgrade notes and the configuration files for the static analysis tools, so the migration guide is maintained in the same tree as the code rather than on a website that can rot.

The performance claim is the one to test first

The README says that overall performance is very important and that NotORM can actually run faster than a native driver. That is a strong claim, and it deserves a careful reading rather than a repetition.

A native driver is the low level layer, the thing that talks to the database over the wire. Beating it is only meaningful if the comparison is with the same work done by hand in plain PDO, including the joins and the row hydration, not with the driver executing a single query. And the work itself matters: the example traverses three levels, applications, then authors and tags, which is a shape that a naive implementation would turn into a query per row.

So the claim to test is specific. Take a query with a join, and a traversal of the kind in the example, and compare the time and the number of round trips against the equivalent raw PDO code. The round trip count is the more interesting number than the wall clock, because it is what decides whether the library is comfortable on a slow link or a busy server.

The other thing worth checking is how the library behaves when a relation is not used. If the relationship traversal is lazy, then a row that has no related entries should cost nothing, and a row that has many should not trigger a query per row. That is the detail that decides whether the performance claim holds up in your schema rather than in the example.

And the fair comparison for a project that already has an ORM is not the driver at all, it is the mapper you would otherwise write. A library that saves you the model layer and gives you relationships inline is worth adopting for the code you delete, not for the milliseconds it saves.

Static analysis, a style checker, and tests that need real databases

The development section is two commands, and the configuration files in the repository tell you what they do.

The first command checks the code with PHP_CodeSniffer and PHPStan, and both tools are configured in the repository with a phpcs.xml for the style rules and a phpstan.neon for the static analysis. The second command runs the tests, and the README points at a readme in the tests directory for setting up the databases before you run them.

That last point is the interesting one. A test suite that needs databases set up before it runs is a suite that exercises the library against real database engines rather than against a stub, which is the only way to catch the differences between them, the quoting of identifiers, the handling of the different limit syntaxes, the behaviour of the drivers. The price is that running the tests is more work than running a unit test suite, and the cost is also that the same test runs across engines become your compatibility check.

The repository listing also shows an editor configuration file and an attributes file, so the formatting is defined centrally, and there is a file for instructions aimed at coding assistants, which is a small signal about how the project expects to be worked on.

The overall picture is of a small, mature library with an unusually good upgrade path for its size: a documented migration from the first version, two static analysis tools, a style checker, and a test suite that talks to real databases.

Editorial conclusion

Adopt NotORM if you are reading from a database in PHP and want relationships traversed inline rather than through a model layer you have to write, since that is the feature the project is organised around. Do not adopt it for writes, because the README describes it as a library for simple working with data and the usage it documents is all reading. Before you depend on it, check the licence file, since the repository listing records the licence as a custom one that GitHub cannot classify, and measure the performance claim yourself, because the statement that it can run faster than a native driver is the project's own and the right comparison is against the query plan you already use.

Frequently asked questions

What is NotORM and what is it for?

It is a PHP library for simple working with data in the database, described as a library for simple reading data from the database. The feature the README emphasises is very easy work with table relationships, and the performance claim is that it can run faster than a native driver.

How do I install NotORM and what does it require?

You install it with composer require vrana/notorm. It requires PHP 8.0 or newer and any database supported by PDO, with MySQL, SQLite, PostgreSQL, MS SQL and Oracle listed as tested. An upgrade guide for users coming from NotORM 1 is in the upgrade directory of the repository.

How do I read related rows with NotORM?

You construct the library with a PDO connection, call the method named after the table, and chain the ordering onto it. A single row is read with the column name in square brackets, a related row is read the same way as a property, and a related collection is a method call named after the related table that returns rows you iterate.

How do you run the NotORM tests?

The README gives two development commands, composer check to run PHP_CodeSniffer and PHPStan over the code, and composer test to run the tests. The tests need databases set up first, and the README points at the readme in the tests directory for those instructions, which means the suite runs against real engines rather than stubs.

Is NotORM maintained and what licence does it use?

The last push to the repository was on 2026-10-19 and the project publishes no GitHub releases. The repository listing records the licence as a custom one that GitHub cannot classify, with the details in the LICENSE file, so read that file before shipping the library in a product.

Official sources

  1. Issues
  2. Project website
  3. README
  4. vrana/notorm on GitHub
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/vrana-notorm.svg)](https://hysenlabs.com/projects/vrana-notorm)

Was this useful?