# laravel-doctrine/orm: putting Doctrine's mapping into a Laravel app

> This package wires Doctrine DBAL and ORM into Laravel so that models use annotations or attributes, repositories become injectable services and the container owns the entity manager, while the rest of the application stays on Eloquent. It is MIT licensed and the version 3 line tracks DBAL 4 and ORM 3 on PHP 8.2.

**laravel-doctrine/orm** — An integration library for Laravel and Doctrine ORM

- Repository: https://github.com/laravel-doctrine/orm
- Stars: 837 · Forks: 180
- Language: PHP
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/laravel-doctrine-orm

## What the integration actually changes

laravel-doctrine/orm is described simply as an integration library for Laravel and Doctrine ORM, and that plainness is worth pausing on, because a Doctrine integration for a framework that already has an ORM is a strange thing to build unless you have a specific reason.

The reason is usually in the mapping and the model. Eloquent derives its behaviour from conventions: a class is a table, properties are columns, relations are methods with particular names, and the framework decides a great deal for you. Doctrine inverts that. You describe the mapping explicitly, whether through PHP attributes or annotations, and the persistence behaviour follows from the description rather than from the shape of the class.

That inversion is what makes the library worth the friction for some projects. With explicit mapping you can point a property at a different table and column, use an embedded object, map a value object, or share a mapping definition with another framework. It is the usual answer for a codebase organised around domain objects and repositories rather than around models and query builder calls.

The other half of the value is the repository model. In Doctrine, a repository is an explicit service class with its own interface, and the ORM hands it to you through dependency injection. In Laravel, that maps onto the container the framework already has, so a repository class can be type hinted and resolved rather than built by hand inside a controller.

The scope of the library is what it says it is. It provides the Doctrine side inside a Laravel application, with the service provider and facades wired into the framework, the configuration published as a normal Laravel config file, and the documentation describing how the pieces fit. The Laravel side of the application, the HTTP layer, queues, events and the rest of the framework, is unchanged.

## Installation is a composer require and one publish command

The install path is the standard Laravel package path, and it is short.

```bash
composer require laravel-doctrine/orm
```

The service provider and the facades are autodiscovered, so there is nothing to register manually in config/app.php or bootstrap/providers.php. That is the part of a Laravel package installation that usually causes friction, and here it does not.

The configuration is published explicitly:

```bash
php artisan vendor:publish --tag="config" --provider="LaravelDoctrine\ORM\DoctrineServiceProvider"
```

The tag and the provider class are both named in the command, so it is unambiguous which config file is written. From there the connection settings live in the published config file and are read through the Laravel config repository, which is the arrangement the framework expects and which means the usual environment variable and config caching behaviour applies to your database credentials.

The documentation is hosted on ReadTheDocs at laravel-doctrine-orm-official.readthedocs.io, with the same content available in the docs directory of the repository. The README points to both, and a badge in the README tracks the latest build of that documentation, so the docs are published from the repository rather than maintained separately.

That is the whole setup. There is no manual entity manager registration step described here, no manual container binding to write, and no migration story, because the Doctrine side has its own schema tooling rather than using Laravel migrations. That last point is the one to think about before you start, because a project on Eloquent migrations cannot simply be switched over.

## Version 3 means DBAL 4, ORM 3 and PHP 8.2

The version table in the README is short and the branches are tied to major versions of the underlying libraries, which is where the real compatibility constraints live.

Version 3 supports DBAL ^4.0, ORM ^3.0 and PHP 8.2, and the README points at an upgrade guide for the details. Version 2 supports Laravel 9 to 11, DBAL ^3.0, ORM ^2.0 and PHP ^8.0. Version 1 supports Laravel 6 to 9, DBAL ^2.0, ORM ^2.0 and PHP ^5.5 to ^8.0.

The consequence is that this is not a drop-in upgrade path across the whole library. Moving from version 2 to version 3 means moving from ORM 2 to ORM 3 and from DBAL 3 to DBAL 4 at the same time, and both of those are major versions of the libraries underneath with their own breaking changes. The upgrade guide exists for that reason. If you are on Laravel 9 or 10, you are on version 2, and your upgrade path runs through a Laravel upgrade and a Doctrine upgrade together.

The default branch here is 3.3.x, and the listed releases are 3.3.3 from 2026-04-12, 3.3.2 from 2026-03-08 and 3.3.1 from 2026-02-13, so the 3.3 line is getting patch releases on a regular cadence.

The repository is not archived, and the last push was on 2026-04-12, which is the same day as the 3.3.3 release. That is a consistent picture: a maintained 3.x line with a slower release rhythm than the major version churn would suggest, and no work in the branch names beyond 3.3.x in the listing above.

The licence is MIT, with the LICENSE file at the repository root, and the README simply points at it. MIT is permissive and carries no obligation on the applications you build with it, which matters here because this library sits underneath a business application rather than being the product.

## The repository layout of a package that is mostly integration

The top level entries show what this project actually is, and it is mostly glue plus a great deal of testing.

There is src for the package code, config for the configuration that the publish command writes, docs for the documentation, and tests. Two entries stand out for a package rather than an application. There is a workbench directory and a testbench.yaml file, and testbench is the standard mechanism for testing a Laravel package: it boots a minimal Laravel application in the test suite so the package can be exercised inside a real framework context rather than against mocks. A workbench directory is where the developer app used by that harness lives.

There is also a phpunit.xml for the test suite and a testbench.yaml, plus a phpcs.xml.dist for coding standard checks and a phpstan.neon with a companion phpstan-baseline.neon. The PHPStan badge in the README reads level 1, which is the lowest strictness setting, and the presence of a baseline file is the more interesting detail: a baseline records the errors that are known and accepted, so the static analysis run stays green while the debt is tracked in a file rather than in a stream of warnings.

The README also carries a continuous integration badge pointing at a GitHub Actions workflow, and a codecov badge for coverage.

There is a CLAUDE.md at the root, which is the kind of file that holds instructions for AI coding assistants working in the repository, and a .readthedocs.yaml that configures the documentation build. There is no application code, no database schema and no frontend, which is the correct shape for a library and a reminder that everything else lives in the host application.

The practical takeaway from the layout is that the bulk of the engineering effort here goes into making the integration behave correctly across Laravel and Doctrine version combinations, not into the persistence features themselves, which come from Doctrine.

## Where this is the wrong choice

The most common case for reaching for this library is that someone has read about Domain Driven Design and wants entities and repositories. That is not a good enough reason, and the cost is concrete.

The first cost is that you now run two persistence approaches in one application. Eloquent models have their own conventions, their own hydration, their own relationship handling and their own query builder. Doctrine entities have attributes or annotations, their own identity map, their own unit of work and their own change tracking. They do not share a model, a transaction boundary or a query API, and a project that uses one for reads and the other for writes has two sets of rules to reason about.

The second cost is migrations. Laravel's migration system and Doctrine's schema tooling both want to own the schema, and they express it differently. A project that already has Laravel migrations cannot point Doctrine at the same tables without a reconciliation step, and the reconciliation is a permanent tax if the two tools disagree about column types, indexes or naming conventions.

The third cost is the team. Doctrine's mapping model, proxies, lazy loading and the unit of work are concepts that Laravel developers do not know, and the documentation here is a set of integration notes rather than a teaching resource. If one person on the team knows Doctrine and the rest know Laravel, the integration is where the misunderstandings land.

There is a good reason to use it, and it is worth naming precisely. If your application has to share its domain model or its database with a second system that already uses Doctrine, if you need mapping features Eloquent does not offer, or if your organisation has a platform standard built on Doctrine, then this library is the sensible way in. The Interplay between Laravel and Symfony in one organisation is the classic case, and it is exactly the case the library was written for.

The alternative for most teams is to stay on Eloquent and get the same design benefits through other means: a dedicated repository layer over Eloquent, explicit form request objects for validation, and an application service layer that holds the business logic. That is more typing, but it stays inside one persistence model.

## What to check before you commit

Four checks, in the order they will bite you.

Check the version matrix first, and it is a matrix rather than a single constraint. Version 3 needs PHP 8.2, DBAL 4 and ORM 3, and version 2 is the one for Laravel 9 to 11 with DBAL 3 and ORM 2. If your application is on Laravel 10, you are looking at version 2 and a future move to version 3 that also drags DBAL and ORM forward. The upgrade guide is linked from the README and is the thing to read before committing, not after.

Check the connection configuration next. The published config file is where the connection lives, and the README does not describe its options, so the file itself and the documentation are what you have. The question to answer is whether the connection is shared with the Eloquent side or separate, because a shared connection has implications for transactions across the two.

Check how the entity manager is resolved. The service provider and the facades are set up for you, and the facade is the quick path. For anything beyond a single repository call, the entity manager should come from the container so that you get the same instance and the same unit of work within a request. A package that constructs its own entity manager per call will not share a transaction with the rest of your application, and that failure is invisible until a write is half applied.

Check the logging and the exceptions. Doctrine has its own exception hierarchy and its own logger, and a Laravel application that expects Illuminate exceptions in a handler will need to know how Doctrine failures surface.

On the maintenance side, the 3.3 line is being patched regularly and the last push was on 2026-04-12. That is a healthy signal for a library version, but the whole project is version-locked to major releases of Doctrine, so your upgrade calendar is set by Doctrine's, not by Laravel's. Plan for that rather than discovering it.

## Conclusion

Adopt laravel-doctrine/orm if you are on Laravel and need Doctrine's mapping and DDD oriented repository model, for example to share entities with a Symfony side of the system or to use a schema the Eloquent conventions cannot express. Do not adopt it for a new application that has no reason to leave Eloquent, since the two persistence approaches will not mix cleanly in one model. Verify first that your PHP version and Laravel version match the branch you install, that the config file you publish names the connection you intend, and that the EntityManager is resolved through the container rather than constructed per request.

## FAQ

### How do I install laravel-doctrine/orm?

Add it with Composer using `composer require laravel-doctrine/orm`. The service provider and facades are autodiscovered, and you publish the config with `php artisan vendor:publish --tag="config" --provider="LaravelDoctrine\ORM\DoctrineServiceProvider"`.

### Which Laravel and PHP versions does laravel-doctrine/orm support?

Version 3 supports DBAL ^4.0, ORM ^3.0 and PHP 8.2. Version 2 supports Laravel 9 to 11, DBAL ^3.0, ORM ^2.0 and PHP ^8.0, and version 1 supports Laravel 6 to 9 with DBAL ^2.0 and ORM ^2.0.

### Where is the documentation for laravel-doctrine/orm?

The full documentation is hosted at laravel-doctrine-orm-official.readthedocs.io and is also available in the docs directory of the repository. The README links to both, and a badge tracks the latest published build.

### Can I use Eloquent and Doctrine in the same Laravel application?

The library integrates Doctrine into a Laravel application, but the two persistence approaches have separate conventions, hydration, transactions and query APIs, and the schema tooling differs as well. The README does not describe mixing them in one model, so treat the two as parallel rather than interchangeable.

### What license is laravel-doctrine/orm released under?

MIT, with the LICENSE file at the repository root and the README linking to it.

## Sources

- [Issues](https://github.com/laravel-doctrine/orm/issues)
- [laravel-doctrine/orm on GitHub](https://github.com/laravel-doctrine/orm)
- [License: MIT](https://github.com/laravel-doctrine/orm/blob/3.3.x/LICENSE)
- [README](https://github.com/laravel-doctrine/orm/blob/3.3.x/README.md)
- [Releases](https://github.com/laravel-doctrine/orm/releases)

---

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