For the past two years I have worked on a SaaS platform for the education space that we are about to launch (small 2 person start up) - it involves a lot of highly dynamic forms and fairly complex client side state and tons of rather complex components and workflows.
The stack for non-specifics we landed on for now coincides with a lot of what is mentioned in the blog post with a few extras:
Nextjs, oRPC, Next-Intl, Zod, Tanstack Form, Tanstack Query, Drizzle, SQLite, Tiptap, Better-Auth, Jest, Tailwind, a heavily customized Shadcn.
However there are a few more things I would like to mention.
Formatting: Oxfmt
Linting: Oxlint
E-Mails: react-email
Icon Library: Lucide
User HTML in React: Interweave
Date Handling: date-fns
Drag and Drop Handling: DnD Kit
Payment (MoR): Creem (we are EU based, so a EU MoR matters to us)
The blog post creates a good overview of technologies that exist out and some pros and cons but it's not so clear to me why the things that are recommended are recommended except for: Companies use them.
We went through multiple rewrites of large parts of the codebase, originally we started out using supabase for the backend, then moving to drizzle with self hosted postgres, then switching to sqlite. We started with react-hook-form and switched to Tanstack Form. We had our own UI library, then switched to Shadcn and customized that heavily. We used next-auth (now auth.js) and switched to better-auth, used server actions, then switched to oRPC.
Most of the decisions we made were either grounded in a very specific technical aspect related to our product or just out of curiousity of whether the grass would be greener on the other side (it was sometimes, not always).
In my normal day job I have also mostly worked on Nextjs apps for the past few years, eCommerce, internal dashboards and tools etc and I guess my takeaway is that most of these tools can get you where you want but depending on the shape of your problem(s), some lend themselves better than others and you will probably only find out if you try it out. If you are building a highly complex app, you will inevitably run into situations where all those libraries and frameworks will not provide you with the things you want or will expose primitives that make it cumbersome to work with. I will give one recent example:
In our application we worry a lot about potential loss of form data of dynamically created forms, so we need some sync solution for said form data and have some form of persistence. The all-encompassing solution for us would involve: Local sync to indexed db, including tab sync, websocket sync of change increments (not the entire form, they are quite large), retry on error / connection loss, ideally some state merging logic for the form state in case of divergence with last writer wins fallback, granular form validation with different representations of data for draft and submit states, atomic re-renders (e.g. save button gets disabled when sync is in flight but no full re-renders when the form object changes) and different representations of the form data (image URLs from the server snapshot look different than base64 representations in the form for example). This is not trivial. We looked at different LoFi solutions (Tinybase, different CRDT approaches, Zero, SignalDB) with SignalDB being the closest one to what we would like. Eventually we had to ditch that too and implement a lesser version of all of this for our v1 that syncs the entire exam state periodically over oRPC (+ debounced local storage) and a pretty massive hook that abstracts the sync logic over various forms and form builders we have to handle all sorts of edge cases. Tanstack form is not meant for this (dirty tracking does not line up if the "default state" changes), there is no concept of drafts and final forms, there are no storage adapters that do conflict resolution the way you might want because that is so specific to your app.
Another point I would like to make is that, while modern react stacks do afford the developer a pretty nice UX 90% of the time, sometimes that comes with some pretty annoying tradeoffs. Nextjs is quite heavy and slow. No cron jobs when self-hosting. Having your db schema defined in TS (using drizzle), tacking some extra Zod on it at the client/server boundary and carry it through into the frontend and eventually in Tanstack form is very nice on paper but for dynamic forms with arrays and more complex data types the TypeScript LSP will absolutely shit the bed, even TSGO can't keep up or outright crashes regularly for me. Tanstack form type inference for form fields is also lacking for complex array types for us. Using SQLite is great because no separate process is needed to host the DB, but you don't get CDC or realtime updates easily (maybe turso will help here in the future).
Using shadcn is really cool to get up and running and build things that look generally professional and nice, but once you modify the files (which you will need to in order to keep up with the demands of the app) the upgrade path becomes painful and the shadcn dependency list and amount of DOM it sometimes produces of it is also ridiculous.
All that is to say, I think the difficult part of engineering even in 2026 happens at the outer edges of what you build and no framework or stack is gonna save you from all of that (and probably shouldn't!).
For the past two years I have worked on a SaaS platform for the education space that we are about to launch (small 2 person start up) - it involves a lot of highly dynamic forms and fairly complex client side state and tons of rather complex components and workflows.
The stack for non-specifics we landed on for now coincides with a lot of what is mentioned in the blog post with a few extras:
Nextjs, oRPC, Next-Intl, Zod, Tanstack Form, Tanstack Query, Drizzle, SQLite, Tiptap, Better-Auth, Jest, Tailwind, a heavily customized Shadcn.
However there are a few more things I would like to mention.
Formatting: Oxfmt
Linting: Oxlint
E-Mails: react-email
Icon Library: Lucide
User HTML in React: Interweave
Date Handling: date-fns
Drag and Drop Handling: DnD Kit
Payment (MoR): Creem (we are EU based, so a EU MoR matters to us)
The blog post creates a good overview of technologies that exist out and some pros and cons but it's not so clear to me why the things that are recommended are recommended except for: Companies use them.
We went through multiple rewrites of large parts of the codebase, originally we started out using supabase for the backend, then moving to drizzle with self hosted postgres, then switching to sqlite. We started with react-hook-form and switched to Tanstack Form. We had our own UI library, then switched to Shadcn and customized that heavily. We used next-auth (now auth.js) and switched to better-auth, used server actions, then switched to oRPC.
Most of the decisions we made were either grounded in a very specific technical aspect related to our product or just out of curiousity of whether the grass would be greener on the other side (it was sometimes, not always).
In my normal day job I have also mostly worked on Nextjs apps for the past few years, eCommerce, internal dashboards and tools etc and I guess my takeaway is that most of these tools can get you where you want but depending on the shape of your problem(s), some lend themselves better than others and you will probably only find out if you try it out. If you are building a highly complex app, you will inevitably run into situations where all those libraries and frameworks will not provide you with the things you want or will expose primitives that make it cumbersome to work with. I will give one recent example:
In our application we worry a lot about potential loss of form data of dynamically created forms, so we need some sync solution for said form data and have some form of persistence. The all-encompassing solution for us would involve: Local sync to indexed db, including tab sync, websocket sync of change increments (not the entire form, they are quite large), retry on error / connection loss, ideally some state merging logic for the form state in case of divergence with last writer wins fallback, granular form validation with different representations of data for draft and submit states, atomic re-renders (e.g. save button gets disabled when sync is in flight but no full re-renders when the form object changes) and different representations of the form data (image URLs from the server snapshot look different than base64 representations in the form for example). This is not trivial. We looked at different LoFi solutions (Tinybase, different CRDT approaches, Zero, SignalDB) with SignalDB being the closest one to what we would like. Eventually we had to ditch that too and implement a lesser version of all of this for our v1 that syncs the entire exam state periodically over oRPC (+ debounced local storage) and a pretty massive hook that abstracts the sync logic over various forms and form builders we have to handle all sorts of edge cases. Tanstack form is not meant for this (dirty tracking does not line up if the "default state" changes), there is no concept of drafts and final forms, there are no storage adapters that do conflict resolution the way you might want because that is so specific to your app.
Another point I would like to make is that, while modern react stacks do afford the developer a pretty nice UX 90% of the time, sometimes that comes with some pretty annoying tradeoffs. Nextjs is quite heavy and slow. No cron jobs when self-hosting. Having your db schema defined in TS (using drizzle), tacking some extra Zod on it at the client/server boundary and carry it through into the frontend and eventually in Tanstack form is very nice on paper but for dynamic forms with arrays and more complex data types the TypeScript LSP will absolutely shit the bed, even TSGO can't keep up or outright crashes regularly for me. Tanstack form type inference for form fields is also lacking for complex array types for us. Using SQLite is great because no separate process is needed to host the DB, but you don't get CDC or realtime updates easily (maybe turso will help here in the future). Using shadcn is really cool to get up and running and build things that look generally professional and nice, but once you modify the files (which you will need to in order to keep up with the demands of the app) the upgrade path becomes painful and the shadcn dependency list and amount of DOM it sometimes produces of it is also ridiculous.
All that is to say, I think the difficult part of engineering even in 2026 happens at the outer edges of what you build and no framework or stack is gonna save you from all of that (and probably shouldn't!).