# Doctrine MongoDB ODM: mapping PHP objects onto documents without pretending MongoDB is SQL

> Doctrine MongoDB ODM is the PHP library for persisting objects in MongoDB, maintained under MIT with a 2.x line still receiving releases. It suits PHP teams that want a documented mapping layer and query builder over the driver, and the repository's own agent skill spells out the mistake it exists to prevent, treating the ODM as if it were a SQL ORM.

**doctrine/mongodb-odm** — The Official PHP MongoDB ORM/ODM

- Repository: https://github.com/doctrine/mongodb-odm
- Website: https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/
- Stars: 1,098 · Forks: 511
- Language: PHP
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/doctrine-mongodb-odm

## An object mapper, not a relational mapper in disguise

The Doctrine MongoDB ODM project is a library that provides PHP object mapping functionality for MongoDB. That single sentence is the whole scope, and the project is careful not to overpromise it as a relational ORM in a different coat.

That care shows up in an unexpected place. The package ships a coding-agent skill at `skills/mongodb-odm/`, and the description of what it teaches is unusually pointed. It teaches an agent how to map documents, query and aggregate, model references and embeds, and use Atlas Search, Vector Search and Queryable Encryption correctly, and how to avoid the mistakes that come from treating the ODM like a SQL ORM.

That last clause is the interesting one, and it tells you what the maintainers consider the characteristic failure. A developer arrives from Doctrine ORM, and the muscle memory of entity managers, repositories, associations and SQL semantics gets carried over into a document store where the wrong instincts produce slow queries, embedded documents that should be references, and aggregations written as joins.

The repository is the official one under the doctrine organisation, the language is PHP, the licence is MIT, and the topics list mongodb, odm, orm, php and symfony, which is a reasonable hint at the audience.

## The AI agent skill is declared, discovered and installed automatically

The skill mechanism is a small piece of engineering worth understanding, because it is a pattern more PHP packages will copy.

The skill itself lives in the package at `skills/mongodb-odm/SKILL.md`, and it is declared in `composer.json` under `extra.ai-mate.skills`. That declaration is what makes it discoverable. A project that uses Symfony AI Mate picks the skill up with no configuration in the consuming project:

```bash
composer require --dev symfony/ai-mate
vendor/bin/mate init
vendor/bin/mate discover
```

Mate installs the skill under the name `mate-mongodb-odm` and mirrors it into `.claude/skills/` and `.agents/skills/`. The last point matters for the practical reality of agent tooling, since different agents read `SKILL.md` directly, and the documentation says those can simply be pointed at `vendor/doctrine/mongodb-odm/skills/mongodb-odm/SKILL.md`.

So the design is a two tier distribution. The skill travels inside the Composer package, where it is versioned with the library it describes, and the `extra.ai-mate.skills` key is the discovery contract that lets a tool find it. The consequence for a team is that the guidance an agent gets about using the ODM is the same guidance that ships with the version of the ODM you installed, rather than a set of blog posts an agent may have memorised.

The skill covers mapping, querying, aggregation, references and embeds, plus three MongoDB specific features that have no SQL equivalent in the same shape: Atlas Search, Vector Search and Queryable Encryption. Queryable Encryption in particular is the kind of capability where getting the model wrong leads to a design that quietly leaks data, so having the rule set next to the code is useful.

## Version lines and the long chain of upgrade notes

The release history is dense, which is normal for a Doctrine project and worth planning around.

Version 2.17.0 was tagged on 2026-09-01, 2.17.1 on 2026-09-03, and 2.17.2 on 2026-10-14. The default branch of the repository is `2.18.x`, so the next minor line is in development while the current one is being patched. The last push was on 2026-10-15, and the repository is not archived.

The upgrade documentation is the part that shows the project's age. The top level of the repository contains `UPGRADE-2.0.md`, `UPGRADE-2.1.md`, `UPGRADE-2.2.md`, `UPGRADE-2.3.md`, `UPGRADE-2.4.md`, `UPGRADE-2.5.md`, `UPGRADE-2.6.md`, `UPGRADE-2.7.md`, `UPGRADE-2.16.md`, `UPGRADE-2.17.md`, `UPGRADE-2.18.md` and `UPGRADE-3.0.md`, alongside a `CHANGELOG-2.0.md`. Not every minor version has one, and the gaps are where the less interesting upgrades are, but there is a document to read for most jumps you plan.

The presence of `UPGRADE-3.0.md` is also a signal. A 3.0 document exists while the released line is 2.17, so the next major version is being prepared, and projects that pin aggressively will find themselves crossing a major boundary sooner or later.

The rest of the tooling in the repository is standard Doctrine practice. There is a `phpstan.neon.dist` with a `phpstan-baseline.neon`, a `phpunit.xml.dist` for tests, a `phpcs.xml.dist` for coding standards, a `phpbench.json.dist` and a `benchmark/` directory, a `docker-compose.yaml` for a local MongoDB, and a `doctrine-mongo-mapping.xsd` schema definition, which is how mapping is validated against an XML schema.

## The local MongoDB setup embeds an embedding provider endpoint

The `docker-compose.yaml` at the top of the repository is a single service, and it is more revealing than a plain MongoDB container would be.

The service is `mongodb-atlas-local`, using the image `mongodb/mongodb-atlas-local:preview`. It reads an optional `.env` file, and the environment section sets two variables:

```yaml
environment:
  - VOYAGE_API_KEY=${VOYAGE_API_KEY:-}
  - EMBEDDING_PROVIDER_ENDPOINT=${EMBEDDING_PROVIDER_ENDPOINT:-https://api.voyageai.com/v1/embeddings}
```

The port mapping is `"27018:27017"`, so the container's standard MongoDB port is published on 27018 on the host, which avoids colliding with a locally running MongoDB.

The embedding endpoint is the notable part. A local development stack that carries an embedding provider endpoint is set up for vector search work, and the pairing with the `EMBEDDING_PROVIDER_ENDPOINT` default pointing at Voyage AI's embeddings API connects the local container to an external embedding service. The matching `.env.example` file contains exactly two lines, an empty `VOYAGE_API_KEY=` and the same `EMBEDDING_PROVIDER_ENDPOINT` default, which confirms that the two variables are the intended configuration surface for a developer.

So the development environment is built around the newer MongoDB capabilities rather than the plain CRUD baseline. The `preview` tag on the image also tells you the project is tracking a feature that is not yet in a stable release, which is consistent with a project whose skill document covers Atlas Search and Vector Search.

## What the ODM gives you, and what it asks of your schema

The value of a mapping layer is that it turns a document into a typed object with a known shape, and it gives you one place to describe how the two correspond. The documentation and the project site are where that description lives, and the repository points at the doctrine-project.org site, the stable documentation, the issue tracker and the releases page.

The cost is that the mapping becomes part of your architecture. A document shape that is easy to read in the MongoDB shell can be awkward to express as a class, and a class with a type hint can be a poor fit for a document where a field is sometimes a string and sometimes an array. The skill's emphasis on references and embeds is really an emphasis on these modelling decisions, because choosing between embedding a related document and referencing another collection has different query costs and different update semantics in MongoDB, and the ODM exposes both.

The feature surface the skill names is a fair summary of what modern MongoDB work involves. Mapping documents covers the class definitions. Querying and aggregating cover the two different ways to read data, since a find with a filter is not the same operation as an aggregation pipeline, and confusing the two is another documented mistake. Atlas Search is the full text search capability, Vector Search is the embedding similarity capability that the local docker setup is pointed at, and Queryable Encryption is the capability that encrypts fields client side so the server never sees the plaintext.

The absence of a SQL-style schema migration story is a genuine difference from a relational ORM, and the repository does not claim one. What it has instead is the mapping XML schema, the static analysis configuration, and the benchmark harness, which is a different kind of safety net: it catches type errors and measures behaviour rather than enforcing a normalised relational model.

## Where it is the wrong tool

The first case is a small project that does not want a mapping layer. If your documents are already close to the shape you want to read, the ODM adds mapping files, a manager object and a query builder over a driver that already does that work, and every schema change becomes a class change plus a mapping change plus a migration question.

The second case is a project that has learned to read MongoDB queries directly. A team comfortable with aggregation pipelines and with thinking in documents will often find the ODM's abstractions an obstacle rather than a convenience, particularly when they need an aggregation shape the query builder does not express well and end up dropping to raw commands anyway.

The third is a schema-light, write-heavy workload where the ODM's value proposition, typed classes and query builder, is least useful and its overhead, mapping maintenance and object hydration on read, is most visible.

The alternative approach is the MongoDB PHP driver directly, and the difference in approach is where the work goes. With the driver you own the document shape, the query syntax and the result arrays, and you gain the ability to use any server feature as soon as it ships, since there is no mapping layer to extend. With the ODM you get a documented mapping model, a query and aggregation API, tooling that understands your documents, and the cost of waiting for the ODM to support the capability you need. The skill is an argument for the ODM position, since it exists precisely because the ODM has its own rules that a general purpose model gets wrong.

One practical note on the branch structure. The default branch is `2.18.x` while the tagged releases are in the 2.17 line, so pinning a version in `composer.json` rather than tracking a branch is the safer habit, and reading the `UPGRADE-2.18.md` document before moving to that line is worth the few minutes it takes.

## Conclusion

Doctrine MongoDB ODM fits a PHP team that wants typed document classes, repositories and a query builder instead of hand-written arrays, and it fits Symfony projects in particular, since the topics and the ecosystem point that way. Skip it if your data model is naturally document-shaped and your team is happy with the raw driver, since the ODM adds a mapping layer you then have to maintain, and do not use it as a mental model for MongoDB itself, which is the exact error the bundled skill warns about. Before you upgrade, read the UPGRADE file for your target version, because the repository carries upgrade notes for many earlier minor lines and for 3.0, and check the branch you are on, since the default branch is 2.18.x while the latest tagged release is 2.17.2. The last push was on 2026-10-15.

## FAQ

### What is Doctrine MongoDB ODM used for?

It provides PHP object mapping functionality for MongoDB, so PHP classes can be persisted as documents and queried through a documented API instead of working with raw arrays and driver commands.

### What does the mongodb-odm agent skill cover?

It teaches an agent how to map documents, query and aggregate, model references and embeds, and use Atlas Search, Vector Search and Queryable Encryption correctly, and how to avoid treating the ODM like a SQL ORM.

### How is the mongodb-odm skill discovered by a project?

It is declared in `composer.json` under `extra.ai-mate.skills`, so with Symfony AI Mate installed, running `vendor/bin/mate init` and `vendor/bin/mate discover` installs it as `mate-mongodb-odm` and mirrors it into `.claude/skills/` and `.agents/skills/`.

### How do I run a local MongoDB for Doctrine MongoDB ODM development?

The repository ships a `docker-compose.yaml` with a `mongodb-atlas-local` service on the `mongodb/mongodb-atlas-local:preview` image, published on port 27018, and a `.env.example` holding `VOYAGE_API_KEY` and `EMBEDDING_PROVIDER_ENDPOINT`.

### What licence does Doctrine MongoDB ODM use?

MIT, and the repository carries a LICENSE file along with a SECURITY.md for reporting vulnerabilities.

## Sources

- [doctrine/mongodb-odm on GitHub](https://github.com/doctrine/mongodb-odm)
- [License: MIT](https://github.com/doctrine/mongodb-odm/blob/2.18.x/LICENSE)
- [Project website](https://www.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/)
- [README](https://github.com/doctrine/mongodb-odm/blob/2.18.x/README.md)
- [Releases](https://github.com/doctrine/mongodb-odm/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/doctrine-mongodb-odm
