For the past three years, I’ve been a huge advocate of Bookshelf.js to my friends and the companies I have worked at. I’ve built small libraries that depend on it, and I’ve read most of the source code and understand the internals. I have actively followed open issues and tried to help developers with their problems whenever I had time outside of work.
However, over the past few months I have distanced myself from the project. I dropped my maintainer status (my contributions were just documentation work and code review, no actual features) and left the Bookshelf organization.
So what?
I was a huge fan of Bookshelf for a few reasons:
- It was built on the Knex query builder. Knex is very feature-complete and has great maintainer support & documentation (it was also made by the creator of Bookshelf). Bookshelf makes it reasonable to write custom queries using the Knex API.
- Bookshelf doesn’t force you to create a Mongo-like schema. Instead, it delegates your types to your database and migrations directly. This avoids you from having to update your schemas in two places.
- The API is focused on the common operations for your database models.
- It has decent documentation for most of its methods.
Sounds OK, right? Let’s talk about some serious issues with Bookshelf that will most likely never be fixed:
- The Relations API is poorly documented and hard to understand. Method naming is very easy to mix up, and when your data model gets more complicated it gets harder to manage this in your models. Most of my time I have spent answering my coworkers’ questions about Bookshelf revolve around this issue. Here’s proof it is not isolated to my team.
- Extending Backbone brought along the Collections API, which is confusing and unnecessary. Instead of using arrays of models, Bookshelf uses a Backbone-like
Collection
class to store a list ofModel
s. This leads to the addition of unnecessary accessor methods and a weird API with Lodash methods. - Really poor examples exacerbate the issues above. The docs give very basic examples of the
Model
andCollection
methods, which means you have to go digging through source code to find what you need.
What prompted me to leave?
This issue was the straw that broke my back.
In June 2017, Tim Griesser moved the Bookshelf project from his personal account to an organization and handed admin rights over to a small group of (mostly) non-active maintainers. A few of the maintainers I have worked with have backed away from the project due to other responsibilities, and the newer maintainers have not roadmapped possible features. From the issue above, there are a lot of s but no lead maintainer who can review PRs and maintain the project.
In addition, issues that are well-documented have been ignored for a long time. Take this issue from a maintainer I’ve worked with. This issue has been open for almost three years. These problems with Bookshelf’s API have been unaddressed, and this was when Bookshelf was much more actively maintained. With even less maintainers and no lead, it is doubtful that these issues will ever be addressed.
On top of this, all releases in the past year were small bug fixes. No major features were shipped, and no issues in the API were addressed.
OK, so Bookshelf is dead. What replaces it?
I’ve been following a lot of different ORM projects in JavaScript (including ones from former maintainers), and the best ORM I have come across so far is Vincit’s objection.js.
There are a few things about this library that really won me over:
- It’s still built on top of Knex, just like Bookshelf.
- No more
Collection
API. Objection uses raw JavaScript arrays, and only has an API around Models. This is the correct approach to building an ORM API. Most database operations happen at a model-level, and batch operations are still accepted through the insert method. - A fantastic Relation API. Objection has designed an excellent DSL around designing your model relations. While I’m not a huge fan of the “stringified arrays”, I am willing to forgive this since the API is truly in a class of its own.
- Excellent, up-to-date documentation. This is the kind of documentation I expect from a top-tier library. Examples are all ES6 or newer, with a very in-depth API reference and lots of examples (including Typescript ones!). The Vincit team has done an amazing job here, and I strive to write documentation this complete in the libraries I build in the future.
The features above are the stand-outs, but this only scratches the surface. Graph upserts, simple eager loading, paging, and the list goes on and on. I’ve also had a chance to meet some of the team behind this library, and they are very smart developers who are excited about evangelizing their library. Vincit is clearly committed to supporting Objection’s development, which means active maintainers who are putting time into addressing issues.
So, for future projects, I will be using Objection.js. I highly recommend developers who are looking for a rock-solid ORM to check out the docs and be sold for yourself on the documentation and simple API.