Where laravelui5/odata Comes From
Every stack has a layer somebody else could have built. For us that layer was OData. For a long time somebody else had built it, and we were glad of it. This post is about why that changed, and about the thanks we owe along the way.
An engine that worked
In February 2024 we needed OData v4 for a Laravel application of our own, and flat3/lodata was the obvious choice. You pointed it at an Eloquent model and got an entity set, with $filter, $expand and $metadata included. Excel and Power BI could read it. We shipped it into production, and it did its job.
What we needed next
Then LaravelUi5 took shape, and with it an idea that the engine was not built for. In LaravelUi5, every UI5 application is its own OData service. It has its own URL, its own $metadata, its own entity sets. A host with ten applications serves ten services.
Lodata served one service per Laravel app. So in April 2025 we wrote the change we needed and offered it upstream: a pull request for several service endpoints, each with its own URI segment, its own namespace in $metadata, and discovery only when a request actually reached it. It left the existing single-endpoint behaviour untouched.
Chris Lloyd, who maintains Lodata, looked at it. He asked us to rebase onto the 5.x branch, and when the tests broke on a database library, he opened an issue upstream to get them green. We rebased, fixed what we had broken, and waited. In September we asked whether a merge was planned. In December we asked again.
There is no villain in this story. Maintaining an open source project on your own time is hard, and a maintainer owes nobody a merge. But we had a stack to ship. In January 2026 we closed the pull request and went a different way.
Starting again, from the tests
We did not fork. We wrote a new engine from the ground up, around the idea Lodata could not carry: a service is a class, and an application can have as many as it likes. Not one line of Lodata's code came along.
What did come along was its test suite. Years of careful work had gone into those tests, and they described what a correct OData server does, request by request. We used them as a specification while the new engine grew, and then rewrote every one of them in Pest. When they passed, the engine did what Lodata did in the places that mattered to us.
In April 2026 LaravelUi5 Core switched over. The part an application author touches did not change: configure() stayed configure(), and applications that worked before worked after. It was just another one of those moments when the layer underneath comes out whole and nothing above it notices. The first time was a quarter of a century ago, when a vendor's middleware to SAP vanished into bankruptcy and was replaced in a week, with the shops on top of it untouched.
What it became
laravelui5/odata is MIT licensed and sits at the bottom of the stack. Three decisions shaped it, and Lodata never had to take any of them.
It only reads. Writes belong in the application, where validation and business rules live. In LaravelUi5 they are named operations, not field writes. It is the decision in this list that costs you something, so it gets a section of its own below.
It streams. Rows go from the database into the response without being turned into models first. Below a few hundred rows nobody notices. Above that it decides whether a list opens at all, and choosing a resolver has the numbers.
Several services are the normal case. Not a special mode, not a flag you turn on. The engine assumes it, which is why a host can carry ten of them without ceremony. That is where all of this began.
The write path we chose
Keeping writes out of the engine deserves a defence, because the alternative to it is genuinely better. SAP's own stack has the luxury variant. A Fiori application with draft handling sends each change to the server as it is made, and the framework parks the half-finished object in a draft store of its own. The business layer does not have to see the typing. It meets the object once, complete, when the user presses save, and the developer behind it declares a few rules rather than building any of that machinery. It is superb engineering, and it stands on a platform that took a large company decades to build. We are not going to offer it, and saying otherwise would waste your time.
So LaravelUi5 takes the compromise. The browser holds the half-finished object, the application sees it once, and a named operation validates it as a whole and writes it in one transaction. A mid-sized company building its own applications gives up the server-side draft and gets a write path that any Laravel developer can read on the first day. For that company it is the better trade.
Thank you
Lodata showed that OData belongs in Laravel, and its tests showed us what doing it right looks like. Thank you, Chris, for both, and for the time you gave our pull request.
If you run Lodata today and want to move, Coming from Lodata maps what you have onto the new engine, key by key.