Ok, so here are a few examples of the things we didn't like:

1. We were doing SSR, and given we needed authentication we used next-auth [1], which is a great library btw, but the problem is given the architecture you buy into when you do an SPA, we had to check for authentication in three places: 1) In the frontend you need to check if the user is logged in or not and show information accordingly. In getServerSideProps you also need to check for permissions, because otherwise you'd be leaking private information in the "initial data" that gets embedded in the first's request html as json. And then you also need to check for authentication in the API pages/endpoints... each one of these has their own ways to be done (well documented in next-auth's docs) but still, you need to be careful, and it was very, very easy to make a mistake, forget to check on some place, etc. Of course you have tests for preventing this, but still... a lot more fragile than just using devise, or a "middleware" in a traditional MVC application. This is one of the things I refer as being more "solid" or "robust".

2. Validation. Oh my!!!... Prisma, again, is an awesome library. The best I've seen and I've used many similar in the past (django's ORM, ActiveRecord, etc). Prisma is up to that level in my opinion... but it is just the data access layer, on top of that you need to implement your own validation rules. We used Yup [1] for this, which, once again, it's a great library. But then we realized we needed to validate things such as already taken emails... but of course, you would not check by issuing first a get() or select and if you didn't find it you'll create it, because that could lead to race conditions... so the "proper" way to do it is to attempt an insert, and if the insert fails because of an unique index then handle the exception, generate an error message, and make it back to the frontend. All doable, and not that difficult. But still a lot of work, and it is easy to forget about corner cases, etc: fragile.

3. Then we needed to add internationalization. So we mixed in next-i18next [3], which added another axis of complexity because translations need to be available both at SSR time plus at the client side. Plus we also need to translate the error messages from the handling of the unique index exceptions from above....

4. We needed to implement some CLI tasks, (think of equivalents to runing a worker or a sync process, etc) which needed to import some domain logic... but next has its own babel and webpack so you cannot write them with plain node, so we needed to do a lot of hacks with @babel/register so that we could import this code, and then we found problems with our code relying on things such as getConfig that next sets up on boot, but this was a CLI so we were not booting next... so we needed to init the config ourselves.

5. By this point our index page was about 250k of javascript + translations + css... and we were not done yet. And the feeling of the end result was not that great.

And we all had a feeling that any of these libraries might change at any point [4], or go unmaintained, or out of fashion and we were just a team of 3.

I insist, I don't think the problems are in any of these tools, nor in JavaScript itself, nor in the ecosystem. These libraries are great, we really liked them. You would have the exact same problems if you try to use Flask, or Sinatra, or any other "lightweight" solution.... it can be done, and it can work very well for you... but it is 1) much more work, 2) requires very experienced people that really know what they're doing and 3) you'll end up re-implementing django, rails, or similar... in your own way, with less documentation and less real-world battle tested. These problems are caused, in my opinion, by the "architecture" you get in (SPA + separate backend).

We rewrote the thing in 1/4 the time with Rails + sorcery + Tailwind + delayed_job + a few other smaller gems. Just a bunch of models and some "services" (plain ruby objects), hotwire for the "spa feel" and stimulus for things such as date pickers, modals, etc.

I think also something to consider is the team size and skills. If you have, let's say, 5 backend devs, and 5 frontend devs, then it might make sense to get into the SPA + separate backend... it is more work, but it is easier to split it... if you're a small team, and/or want to stay as a small team, then nothing beats Rails (or symfony, etc... never used those others) for this.

Hope it helps, and good luck with your project!

[1] https://next-auth.js.org/
[2] https://www.npmjs.com/package/yup
[3] https://www.npmjs.com/package/next-i18next
[4] For example, Prisma 1 is a totally different beast from prisma 2.