What I Would Change About Next.js
Next.js: People love it, or they hate it


Next.js, in the last few years, has become the go-to framework for web development. Partly because of its flexibility to do server-side, fully-static, or incremental-static rendering, but mostly because of the improved developer experience, people love using it.
Or…they hate it.
As any framework gets more mature it also tends to get more complex, and Next.js is no different.
A developer might easily get started with their implementation (probably starting from a simplified template) and then get bogged down in details with React Server Components versus Client Components, caching, performance, middleware – any number of things can make the experience of building a website on Next.js troublesome.
Personally, I think it’s still the best framework out there; Next.js is flexible in places where it needs to be, and opinionated where it has to be.
There are a few things I’d like to see improved, though:
- Hosting
- Caching
- Middleware
- Vendor Lock-in
Let’s look at each one, with hosting being by far the biggest headache.
Next.js Hosting: I Want More Options
One of the things that happens to developers I’m working with, and I’ve experienced this myself, is that they’ll build their site and have everything going great. DevOps is all setup and they are able to test their site out on their chosen hosting environment.
Then, something goes wrong that makes them do a TON of work to solve what might not even have been a consideration at the start. Maybe it’s some quirk of caching that causes content not to update properly. Maybe it’s a performance issue.
I recall a time when I needed to process query strings in a server component, but as soon as I did that, the rendering changed automatically from static to dynamic (meaning that rendering would be slower AND I would be charged for compute for EVERY page load). It took me ages to sort this out. and it was very frustrating.
Since Next.js is SO flexible, the details about HOW each hosting platform handles all the different modes and possibilities should be much more clear. The open-source team behind Next.js (mainly funded by Vercel) have stated that they are working on a Deployment Adapter API that will standardize all of this.
Currently the hosting possibilities for Next.js are limited (in my opinion) to the following. Note that my list is somewhat different from what appears on the Next.js docs:
Best In Class Experience:
Vercel
-
Best experience, everything works...
-
...but I have no idea HOW it all works since that’s a trade secret for them.
-
Developers have become jaded after seeing folks complain of huge cloud bills from Vercel.
Netlify
-
Great experience, everything works (I think…), but there are slight differences into how it behaves from Vercel.
-
Again, it feels like a black box. I don’t have any idea how caching or middleware is implemented, although I was able to glean from the docs that middleware runs BEFORE cache, which is an important detail.
I will note that I use both Netlify and Vercel to host both the Agility CMS website, our docs, and all my personal projects and websites. They are great offerings!
We even have an integration with Vercel and Agility CMS to help developers deploy there with only a couple clicks.
With that being said, however, only having these two offerings isn’t enough for many organizations. What if there are enterprise agreements in place with AWS or Azure?
Let’s look at the possibilities there.
The Public Cloud Experience
AWS Amplify
-
The support for Next.js in Amplify has gotten a LOT better in recent months, and I recommend it to anyone who really needs to put their site in AWS.
-
It’s missing edge support for Middleware, which is a big drawback, but it’s not insurmountable, but it does mean that the middleware runs AFTER the cache layer (if you put your site behind a CDN – see the next bullet).
-
If you put the site behind Cloudfront (AWS’s CDN) you will need do some header tweaking to make sure you handle all the different modes correctly, such as preview/draft mode.
Azure Static Web Apps
-
This isn’t as well-known an offering, but it works surprisingly well. Their docs outline what is and isn’t handled. It was originally intended to support fully static sites only, but later added support for the SSR and ISR modes, known as hybrid rendering here.
-
They are a bit behind on features, but it’s still worth looking at.
-
You can automatically include Azure CDN to help with scaling.
Both of these public cloud offerings are similar in that they try to handle the devops for you, provided automatic microservice-based function generation to handle the compute, which you are then free to scale yourself as you see fit.
You get automatic preview deployments for PRs (similar to Netlify and Vercel) which is a huge benefit to developers.
Docker / Azure App Services / Nodes.js Hosting
One of the easiest ways to host Next.js is in a Docker container, Azure App Service, or any environment that supports modern Node.js. I have a lot of customers that do this, with a lot of success, but sometimes a lot of extra work, too.
If you have a load-balanced environment with multiple server compute instances serving requests, you could end up with different versions of a page delivered from different instances.
We have a customer who synchronizes the cache files for each instance across multiple regions – it works well, but it’s also a lot of overhead work that could be built into the deployment adaptor implementation and abstracted away from the website code itself.
Next.js Caching: Let’s Not Reinvent the Wheel
One of the best parts of Next.js is always that it’s pretty opinionated about caching a LOT of stuff.
Not only does it cache the full route at the origin server, but it was the first framework I used to send a stale-while-revalidate
cache header so that a CDN would keep a route in the edge cache and only send a single request back to the origin server to update. You get stale content while the origin server is working to refresh the content, but your site is WAY more stable.
Cache-Control Headers
What I don’t like about Next.js is that it’s REALLY hard to adjust the cache control header on a regular route-by-route basis. This is something that should be MUCH easier to do.
Object -> Route -> CDN Cache Dependancy
Something that works extraordinarily well in Next.js is the cache dependency chain that is automatically setup when we cache the response from a fetch
call, which is itself used in a route which is cached on the origin server, and subsequently cached on the CDN.
If we clear out that cached object using a cache tag, the route cache is invalidated on both the origin and the CDN. This functionality doesn’t work anywhere except on Vercel and Netlify (see above), but it’s fantastic when it’s setup properly – especially for Agility CMS.
It means that, if a site is built right, content teams can publish items in Agility, a webhook hits the site to clear to the cache for that content, and any pages that content was used on are automatically invalidated as well. Combine that with stale-while-revalidate
CDN logic and it means instance content updates while still maintaining content performance.
The problem with the current model for object caching in Next.js is that it ONLY works from fetch
calls; if I obtained an object from any other method, I can’t cache it.
There is an experimental use cache
feature coming that you can use to decorate a route, function, or component. While this might be useful for some folks, I find it to be a VERY strange way to work. Why not provide access to the underlying primitives that are being used to store the fetch responses in cache?
If that were simply an API that we could invoke, we could cache any object that we wanted to store and tag it the same way we are doing with fetch results.
When I look at libraries like .Net, which has a very rich cache abstraction layer, I feel that it’s great that I have so much control, but it’s VERY hard to setup the cache invalidation tree that Next.js provides. I don’t want something as complicated as .Net, but certainly providing an API beats an opinionated decoration that, no doubt, comes with unintended consequences.
I think “use cache” is a bad idea. I’ll use it once it’s available, but certainly I think a more standard cache API would be much simpler to implement.
Middleware
Middleware is a weird term, since it runs BEFORE the request of the request pipeline.
Indeed, it’s not even intended to run on the same compute location as the main route request; middleware is supposed to run at the edge. While only Vercel and Netlify provision our deployments in this way (see above regarding hosting), even in those situations I think the framework could operate better.
Currently, if I want to intercept a request in middleware and pass context data down to a route handler or component, I need to do that in a cookie or other header.
This means that I can ONLY intercept that data in a PAGE component, not in a regular server component. This situation comes up over and over again when we need to do personalization or other edge-specific logic. An easier methodology for working with edge -> origin functionality would be awesome.
Separate Middleware Deployment SDK
The other thing about middleware that comes up a lot is the ability to have a Next.js site hosted on one origin or more physical locations, but delivered from a totally different CDN provider (or set of providers).
For instance:
- If my site is hosted in Azure using Docker, and I want to use Cloudflare on the CDN, I can certainly perform some logic using Cloudflare’s workers, but having a dedicated “Edge SDK” for Next.js means that I could do the same logic that I would code into a middleware.ts file and deploy it. As more folks move to multi-cloud hosting solutions, this situation will come up more and more.
The Ties to Vercel and Vendor Lock-In
Having an open-source framework tied directly a hosting provider is something that the development community has been harping on for years.
With Vercel being the maintainer for Next.js, and Vercel also being the premier hosting platform for Next.js is not a good thing. Without a decent hosting adapter to allow other providers to scaffold their own hosting solution that tie in DevOps, Serverless Functions, Caching, Edge middleware and all the other aspects of a Next.js app, we feel locked in.
I feel a ton of gratitude to the engineers at Netlify who have done this without an adapter layer to work with, but I wonder if that kind of reverse engineering is sustainable.
The fact that Next.js has become the preferred framework for React is also troublesome. That puts even more pressure on the Vercel team to deliver an Open Source technology to an incredibly large developer community while also monetizing the hosting aspect that very tech sits on.
Is it sustainable long-term?
Conclusion
While Next.js has evolved a ton in recent years, it’s still the go-to standard for modern web development, and getting more popular. It’s a great way to build websites that are flexible and performant.
Every framework tends to get more complex as it matures, but it also tends to get more bloated with age, too. I feel that the maintainers have attempted to add features as prudently as possible, but even so, there are areas that could be improved to provide a better developer experience.
What I have experienced in using Next.js since adopting it first in 2019 is a huge improvement in the workflow for developers. Coupled with the incredible DevOps and Hosting experience that Vercel and Netlify have provided,
I’m happy to continue recommending Next.js a platform that I believe is great decision to build on. This is something that organizations are betting on for the future, so I don’t make that recommendation lightly.
I feel that with a bit more reconsideration of a few features, and the provision of a hosting adapter layer, Next.js will continue to be positioned as the go-to choice for devs and technologists like me.

About the Author
Joel is CTO at Agility. His first job, though, is as a father to 2 amazing humans.
Joining Agility in 2005, he has over 20 years of experience in software development and product management. He embraced cloud technology as a groundbreaking concept over a decade ago, and he continues to help customers adopt new technology with hybrid frameworks and the Jamstack. He holds a degree from The University of Guelph in English and Computer Science. He's led Agility CMS to many awards and accolades during his tenure such as being named the Best Cloud CMS by CMS Critic, as a leader on G2.com for Headless CMS, and a leader in Customer Experience on Gartner Peer Insights.
As CTO, Joel oversees the Product team, as well as working closely with the Growth and Customer Success teams. When he's not kicking butt with Agility, Joel coaches high-school football and directs musical theatre. Learn more about Joel HERE.