Use Day.js instead of Moment.js for less cognitive load and fewer bugs

There are good reasons why you would choose to use Day.js instead of Moment.js for date manipulation.

  • The smaller bundle size
  • TypeScript support out of the box
  • The fact that Moment.js is no longer maintained

But the main reason that I’d recommend Day.js is that it’s immutable. What does this look like in practice?

Say you have a date for an event and you want to create a reminder one day before the event. With Moment.js you’d do something like this:

// Moment.js
const newYearsDay = moment('2024-01-01')
const newYearsEve = newYearsDay.subtract(1, 'day')

At a glance, this looks fine – but what if we want to render both of these dates?

// Moment.js
<span>{newYearsDay.format('YYYY-MM-DD')}</span> // 2023-12-31 😱
<span>{newYearsEve.format('YYYY-MM-DD')}</span> // 2023-12-31

Oh no! We’ve mutated the original date! This sort of bug is hard to spot and I’ve been a victim of this specifically with Moment.js a few times.

Sure, you could use clone() to avoid this, but that’s just more cognitive load.

// Moment.js
// Use clone() to avoid mutating the original date, if you remember to do so
const newYearsEve = newYearsDay.clone().subtract(1, 'day')

Let’s use Day.js instead 😎.

// Day.js
const newYearsDay = dayjs('2024-01-01');
const newYearsEve = newYearsDay.subtract(1, 'day');

<span>{newYearsDay.format('YYYY-MM-DD')}</span> // 2024-01-01 👍
<span>{newYearsEve.format('YYYY-MM-DD')}</span> // 2023-12-31

Much better! Now we can use the original date without worrying about mutating it or having to clone it.


Here’s a browser-rendered example comparing both libraries, assuming the approach detailed above is used for both:

view source

Moment.js
Today: Monday 18 Dec 2023 09:09:28 😱
Yesterday: Monday 18 Dec 2023 09:09:28

Day.js
Today: Tuesday 19 Dec 2023 09:09:28 👍
Yesterday: Monday 18 Dec 2023 09:09:28