You could certainly get the same effect without downtime prior to this. It just needed a few extra steps and some cooperation by the application: adding a null able column without default has always been instantaneous, so you would do that, then update all the rows that are missing the value.
Finally, you add the default to the schema which will now be in the millisecond range because all/most rows have a default.
And then you add the not null constraint which will also be in the ms range.
You can do all of this in a transaction too because postgres' Schema modifications are transactional.
This is how I have added countless columns with default values without downtime over the last few years.