So then there's:
- code-splitting needed for larger codebases
- taking the window object into account
Other stuff I can think of:
- more limited options for routing/etc. because you want to avoid having to maintain two codebases. This means you might have to use Redux+redux-router+whatever instead of express/hapi/etc. because you can't (?) run those frameworks client-side.
- less freedom to modularize state in your app, because last I checked it was still rather messy to ensure that all the separate data-loading events are taken care of server-side before everything is sent to the client. If you're a fan of the Redux approach this shouldn't be a problem though.
- Possible 'issues' with using ESNext features server-side without going through Babel.
All in all I think it's worthwhile and, nowadays, pretty doable to create a 'universal app'. But it has its own complexities and at least last time I tried, I could find very few examples of how to best do this, and we're probably still far away from a 'canonical' solution.
Furthermore, in practice I've found that in many cases it's not really worth the extra effort. If your app is large/complex enough to have a noticeable load-time, it's probably fine for the user to load the entire app first (it might even still be cached), and it's often the case that SEO is not really important.
In my experience, the few cases where a big-ish app needed to load stuff quickly involved going straight to some subpage in the app. In that situation I often found it easier to either just render that bit server-side the old-fashioned way, with its own logic (in which case React is still a good option).