Migrating a Node.JS app from v0.10 to v6

David DOLCIMASCOLO
Linagora Engineering
4 min readOct 18, 2016
OpenPaas calendar app

At Linagora we actively develop an open-source collaborative platform called OpenPaas for 2 years now. This started as an enterprise social network web application and quickly grew to a full-featured collaborative platform including services such as emails management, shared calendars, address books and contacts management, etc.

Our technical stack is an extended MEAN (extended because we now make heavy use of lots of other components such as Elastic to index our data and Redis as a pub/sub) which we never really upgraded in two years, meaning we were still using Node 0.10, Express 3, etc. As we’re getting closer to our first release, we considered it was a pretty good moment to bump our dependencies and fast-forward Node version. Well… Actually maybe this also assisted decision-making :)

Upgrading Node

We knew we were using a pretty old version of Node, but it had proven very stable and was still receiving security patches and fixes; so we were not in a rush to upgrade. Once the decision was made to do the switch, we started by looking at the available versions to decide what would be the most suitable version for us. We wanted to grab the LTS train and at the time we looked at the schedule Node 6 was planned to become the active LTS version in October 2016. Gotcha !

The upgrade itself was very easy. It turned out we were only affected by the API changes to the url module because we had tests not expecting the query property in the returned object from url.parse.

Difficulty: easy-peasy

Upgrading Express

Upgrading Express.js to v4 was a bit more complicated. Not because we had features breaking after the upgrade (thanks Express for maintaining such an impressive backwards compatibility!), not even because of the small number of failing tests after the upgrade. Because of deprecation warnings, literally requiring hundreds of micro-changes in our code base. I really recommend reading the migration guide carefully if you plan to do such an upgrade.

We could have just ignored them, but that would have been reporting the issue to the migration to Express 5 which we’ll do anyway in the future (deprecation warning actually warn you about removed features in the next major version).

Major deprecation warnings you should care about:

  • req.param(key). This will be removed in Express 5. You should always target either the route parameters (with req.params[key]), the query string (with req.query[key]) or the request payload (with req.body[key]).
  • res.json(status, body). This will be removed in Express 5. You must now use res.status(status).json(body) instead.
  • res.send(status, body). This will be removed in Express 5. You must now use res.status(status).send(body) instead.

Difficulty: easy, but time-consuming

Upgrading Mongoose

The upgrade to Mongoose 4 was a bit more complicated because this time it broke a few features in the product. I recommend reading the migration guide and the release notes carefully if you plan to do such a migration.

Here’s a couple of examples of breaking changes we had to deal with after upgrading Mongoose to v4:

  • We were using query.stream to get a Node stream from a MongoDB result set. This is now deprecated in Mongoose 4 in favor of query.cursor but there’s also a subtle breaking change: the cursor will emit a end event (to indicate that all data has been consumed and the stream can be closed) but won’t emit a close event (as query.stream was doing). So watch out if you have code depending on the close event as we did.
  • findOneAndUpdate, the Mongoose method allowing you to perform a findAndModify operation on the underlying MongoDB database, now returns the old document by default. To get the modified document back, pass the new option (options are the third argument to the function).

Difficulty: moderate

Upgrading Async

Async v2 also has quite a few breaking changes but they’re documented. We now know very well that filter, reject, some and every expects an error as the first callback argument. This was done to match Node’s callback convention callback(err, value)

After a couple of hours refactoring our tests and production code we were up and running with async 2.

Difficulty: easy

Conclusion

Though it was sometimes painful to refactor all this code, sometimes hard to find the culprit for a specific test failure and also a bit boring to wait for all these builds to fail after several minutes, we’re all glad we did this migration now.

We’re on good tracks for the release and we use updated dependencies which we believe is an important topic for our community !

--

--