Litestar 2.0 release

litestar-org

On the 2023-08-21, after about 7 months of intense development, Litestar 2.0 was released! Let's talk about it.

What's new?

Let's start this off with a non-exhaustive list of a few particularly noteworthy features:

  • All new DTOs, with support for dataclasses, Pydantic, [attrs][attrs], msgspec, and SQLAlchemy, allowing easy on-the-fly data transformation, greatly reducing the boilerplate needed to set up validation and serialization schemas

  • SQLAlchemy repositories, providing a synchronous and asynchronous implementation of common CRUD and highly optimized bulk operations, with extensive support and testing for SQLite, PostgreSQL, Oracle, MySQL/MariaDB, DuckDB and Spanner

  • SQLAlchemy integration including session management and serialization/validation, enabling you to directly return SQLAlchemy models from route handlers without the need for intermediary models

  • Full support for validation and serialisation of attrs classes and msgspec Structs. Where previously only Pydantic models and types where supported, you can now mix and match any of these three libraries. In addition to this, adding support for another modelling library has been greatly simplified with the new plugin architecture

  • Removal of Pydantic as a required dependency; Pydantic is now fully optional, while still being supported in the same capacity as before

  • Channels, a general purpose event streaming module, featuring inter-process communication and WebSockets integration

  • Unified storage interfaces. All internals (sessions, caches, middlewares) have been moved to the new Stores; low-level, asynchronous key/value stores. They are managed and accessible through a registry, and offer fine grained, centralised control over how and where your application stores data

  • Enhanced WebSockets support, including automatic connection handling, validation of incoming and serialisation of outgoing data, providing feature parity with route handlers and controllers, including full DTO support, OOP based event dispatching and enabling the handling of WebSockets with synchronous functions.

  • Server-sent events
  • HTMX support

If you're interested in a comprehensive list of all the new features and changes instead, check out the changelog and migration guide.

The departure from Pydantic

One of the most significant changes, and perhaps one of the more unexpected ones for some (since it can be seen as somewhat contrarian, regarding the trends in recent years), is the removal of Pydantic from Litestar's core, so I want to try to explain why this decision was made.

First of all, Pydantic is a great library. It's one of the most popular data modelling and validation libraries for Python, offers a wide variety of features and gained a huge boost in performance with its version 2 release, thanks to its core being re-written in Rust.

However, not everyone wants to use Pydantic, and, as with almost every tool out there, it's not the best choice for every job. As a framework, we're trying to give users what they need, without imposing to many restrictions on them, and we felt that with Pydantic, we were doing that in a way. Even if you were not explicitly using Pydantic, Litestar was still using Pydantic under the hood.

Let's take a look at what we are using Pydantic for prior to 2.0:

  • All parsing & validation of query parameters
  • All parsing & validation of request data
  • Serialisation of response data
  • Validation of dependencies
  • OpenAPI schema generation
  • Internal data modelling (headers, cookies, configuration, etc.)
  • All DTOs

All of these come with an additional overhead attached to them, due to the usage of Pydantic. Especially when using a different library, such as attrs for your modelling needs, this overhead is a tough sale.

And while it would have been possible to build out all the features we currently have with Pydantic, were keen to avoid as much unnecessary overhead while retaining the same set of features.

In Litestar v2, Pydantic usage is now restricted to cases where users supply Pydantic models / types, with the rest of them handled by msgspec. Compared to Pydantic, msgspec is not as feature rich, but the features it provides were just what we needed for our core logic; High performance, type oriented parsing, validation and serialisation of data. In these areas, msgspec is order of magnitude faster than Pydantic (less so compared to Pydantic 2, but our benchmarks still show up to 20x difference in performance), making it a formidable replacement.


So what changes for you as a user? If you're using Pydantic, nothing really. You can continue to use Pydantic for everything you desire, using all the same features as before, with performance being on-par with a pure-Pydantic approach. If you are not using Pydantic however or are looking to replace it, for example with plain dataclasses, attrs classes or msgspec's Struct types; They are now fully supported everywhere you previously could use Pydantic models, and you can expect a significant increase in performance, due to the fact that these type won't have to go through Pydantic anymore.

The road to 2.0 and a look into the future

So, why did this take so long? When we initially announced 2.0 back in February 2023, we intended for it to be nothing more than a maintenance release. An opportunity for us to introduce a few breaking changes, and then move on. We first planned to have it released in March 2023, then May. Obviously, none of this actually happened. So what did happen?

The reason for the initial plan was simply that, at the time, there was not a lot of things to be introduced that would require major changes. In fact, none of the more exciting new features now included in Litestar 2.0 were even planned at that point. This can be attributed to a number of things, but one factor that played a significant role was that we were all still getting used to working together as a team, and developing a shared vision for the project.

As we began venturing down that road, a few things emerged that would constitute significant changes to some of the core parts of Litestar, but there were two things in particular that started a chain reaction of changes by opening up further possibilities: The new DTOs and our switch from orjson to msgspec.

While experimenting with msgspec to replace orjson for JSON serialisation, it became clear that it was quite powerful, and soon after we made the switch, we also explored the possibility of moving all our internal validation and parsing logic to it, but at the time it was lacking several features that would be integral for us to make it work, so it was put on hold, to be reevaluated at a later point.

At the same time, the DTO implementation grew in scope, and as it turned out, msgspec proved to be a formidable backend to provide the transformations themselves, and doing so in a more performant way than the previously used Pydantic.

With the DTOs now not relying on Pydantic anymore, and idea began to form that would make Litestar immensely more flexible and powerful: Might it be possible to remove the dependency on Pydantic completely, while still supporting it in the same capacity as before?

Quite some time had passed now since our initial evaluation of msgspec as the core of our validation and parsing chain, and the DTO implementation had shown that it was feasible. So we started another attempt, and, as it turned out, this was entirely possible, albeit not particularly easy.

While all of this was going on, development on other parts of Litestar was still progressing, and since those core changes were taking longer as anticipated as they grew in scope, so did the other features. As it turned out, there was an abundance of features waiting to be realised once we had opened the metaphorical flood gates of widening the scope and estimated time frame for this project.


All of this resulted in what is now known as Litestar 2, and while the process may not have been as well thought out from the beginning as it could have been, what came out of it is something we are all proud of.

That being said, we are trying to learn from it, and expect the development of version 3.0 to be less turbulent and erratic. We believe that with Litestar 2, we have built a very solid foundation for many great things to come, and are currently working on a roadmap for future development.

The next major release will not be as big or breaking as this one. It will be less exciting, and that's a good thing. New features will be introduced gradually, and if all goes to plan, version 3 will simply be the point where we remove a few deprecated things and bump the version number. It's going to be what version 2 should have been

A look into the future

After the release of 2.0, and adding a vast number of new features, the next period is going to be focused more on refining what's already there. It's going to be lot of small fixes and incremental improvements for a while. We are planning to publish minor versions on a regular schedule, about once a month, and patch releases whenever necessary.

In roughly one year, we're aiming to release version 3.0, and are intended to keep this schedule going forward.

And while we are currently still working on an exact roadmap, here are some things that are actively being worked on / planned:

  • Significantly improved DTO performance via a new codegen backend (up to 500% performance increase)
  • Integration of background workers (think SAQ, ARQ, Celery)
  • CLI for generating / managing projects

Acknowledgements

At this point, I would like to extend a heartfelt "Thank you!" to a few people in particular, for their extraordinary contributions to the project:

  • Jim Christ-Harif for his amazing work on msgspec, implementing a litany of features specifically requested by us for our specific use cases
  • Peter Schutt for his outstanding work on the DTO implementation, msgspec integration, response model and so much more
  • Jacob Coffee for elevating our community interaction, outreach, project maintenance and branding to whole new level
  • Cody Fincher for the impressive litestar-fullstack repository and sharing his wisdom and knowledge about databases and SQLAlchemy with us, the SQLAlchemy repositories and being a constant source of new ideas
  • Na'aman Hirschfeld without whom none of this would have ever happened, and who has contributed so many things to the project that I'm not even going to attempt to list them here

Many more people were involved in the development of Litestar, a comprehensive list of which you can find here. Thank you all for your contributions!