TL;DR
Yes, I understand that you will immediately have doubts about what I am saying, because "How can you change what Spotify, OpenAI and other big companies use?".
But I want to say that this topic is clearly not new in 2025, I will not reveal anything supernatural here. HTMX and Alpine.js have already fully proven to everyone that this is not nonsense. I am just retelling everything, but with one interesting remark - this is the HMPL template language which is better than the previous two in some tasks. Next, I will describe why and how it will help you replace Next.js.
Let's get started! ποΈ
π What is this app?
At first, I wanted to make a small landing page for an example. Purely for myself. For a resume, or for other purposes, but I just wanted to do something quickly.
Of course, I chose the stack that I use every day at work, which is Next.js, and I thought that I would quickly do something with it, but it turned out not to be so.
Let's take a look at the design of the app:
It would seem like a simple application that can be made in 5 minutes, but obviously, when you come across a heavyweight framework, the most difficult part begins - implementation.
π¨ Building the structure, components and first difficulties
What's the first thing that comes to mind when you start doing something with Next.js? Of course, you need to install it into the project. And here we come to one of the main drawbacks of the approach associated with creating sites on frameworks, no matter whether it's Next.js or Nuxt.js or Remix. The point here is different.
But let's move on to the installation. Let's write the command to initialize the starting point in the terminal:
npx create-next-app@latest
I set up a starting point without additional CSS modules, without TypeScript and other stuff, I only installed TurboPack so that everything would be built faster and this is what you can see:
And here is the weight of the project itself, only the starting one and without the starting components:
And I haven't even started doing anything, I just installed the app. And how much will it weigh if I want, yes, even in Next.js, to install RTK-Query, or another state manager, what will happen if I start making the app seriously?
And I can tell you, it will weigh under 500 megabytes, or even a 1 gigabyte if I have a lot of components.
π¦ Application size and extensibility
I continued making the application further, creating suitable components, uploading images, changing the config a little, and other similar things.
As a result, I managed to create the following components:
- Header
- Features
- Promo
- CTA
- Footer
They are there, yes, in principle these components did not weigh anything, since they were simple functions, but, of course, a couple of MB were added, but it is understandable, because the application is small.
And, I come to, probably, one of the most important reasons for replacing frameworks - their heaviness.
Let's say we take a regular website of a medium-sized company on Next.js, which is located in Gitlab or GitHub, there it will weigh this website a couple of hundred megabytes or even gigabytes and without the node_modules
folder, no matter how you reduce it. But what if we take really large projects? Their code base can be tens of gigabytes, as if it were some serious game from Steam.
At this rate, we are reaching the point of cloud storage overload, simply terabytes of information all over the world, requiring entire buildings with servers to store it all - this is difficult to comprehend even within the framework of an average company, but what if we are talking about large ones?
Also, we take into account that the build from such frameworks weighs quite a bit, 30-40 megabytes of pure javascript, which will be executed on the client.
π¬ And what to do with the weight?
The most obvious solution for this, of course, some see in using web components, or even making websites without such systems at all, like in the early 2000s, but in practice this doesnβt work in production projects.
People have long ago come up with an alternative to all this, even before Next.js. This alternative is a mechanism for creating dynamic web interfaces directly through markup. That is, roughly speaking, what .ejs
files do, but only on the client and through attributes.
<div data-some-custom-attr="getHTML()" @click="someFunction()">
</div>
Some of the most popular libraries for this are HTMX and Alpine.js. Alpine.js, probably to a lesser extent, since the emphasis is on js interaction in markup, while HTMX is presented by people as a complete replacement for frameworks. And, in part, this is true, I do not argue with this, but there are serious shortcomings in this approach:
- Almost minimal js integration
- Almost non-customizable requests
- Old standard for sending requests
It was more about HTMX, but it is also clear that Alpine.js has some shortcomings in the syntax, that it is like .jsx
and so on.
π A slightly different approach
There is a combination of several approaches, when we have neither HTMX nor EJS, but something in between. And this is the HMPL template language.
First, let's look at what the result of what we change will look like.
Instead of page.jsx
:
<body>
<Header/>
<Features/>
<Promo/>
<CTA/>
<Footer/>
</body>
I replace it with a regular index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Landing Page</title>
<link rel="stylesheet" href="global.css" />
</head>
<body>
<script src="./json5/dist/index.min.js"></script>
<script src="./dompurify/dist/purify.min.js"></script>
<script src="./hmpl-js/dist/hmpl.min.js"></script>
<script src="global.js"></script>
<script>
const body = document.querySelector("body");
const template = `
<main>
<!-- Header Component -->
{{#request src="http://localhost:8000/api/get-header-component"}}{{/request}}
<!-- Features Component -->
{{#request src="http://localhost:8000/api/get-features-component"}}{{/request}}
<!-- Promo Component -->
{{#request src="http://localhost:8000/api/get-promo-component"}}{{/request}}
<!-- CTA Component -->
{{#request src="http://localhost:8000/api/get-cta-component"}}{{/request}}
<!-- Footer Component -->
{{#request src="http://localhost:8000/api/get-footer-component"}}{{/request}}
</main>
`;
const { response } = hmpl.compile(template)();
body.append(response);
</script>
</body>
</html>
I also take all the components to the server and load them through requests via fetch
under the hood and directly in the markup.
π Advantages of the approach
Now, let's look purely at the result that we got in the application when we changed the basis from Next.js to HMPL.
And, also, this size taking into account the server on Express.js and all the files with it. The result of the reduction is visible to the naked eye, the size is around 90-100 times smaller.
Yes, it is clear that I could have done everything in pure HTML and the result would have been less than a megabyte, but the point is different. For simple projects, such a system is valid, as well as for partial replacement of client components with Next.js
We are looking for a simple basis that will allow us to replace SSR from there with CSR but with a focus on the server. We also write all components on the server, like Next.js (Node.js), but the thing is that we do this with markup by connecting one package, and there we do it with a whole system, which is just intended for monumental sites.
β Conclusion
This method will allow you to reduce the code base of your application several times (literally), but it is also worth remembering that this is suitable for medium-sized applications, or like with webpack module federation, when one part is Vue, another is Angular and the third is something else.
Thank you for reading β€οΈ!
Useful links:
- GitHub repo - You can give a star :)
- Docs - More about the template language
- Next.js Starter Page - from there I took the command for the terminal
Top comments (23)
You do realize that this is deceptive, right?
The folder size on your device might be smaller, but you still have to load resources from the URLs when the page loads.
Plus, the actual output of a Next.js build is much smaller than the size of the folder. Dependencies are tree-shook, compiled, minified, etc.
Peak find π
Hello! The fact that the
script
's are connected like this does not give anything. I am not going to lie about this - it is pointless. If I had installed them it would have been not 3.6mb, but 3.7mb - it would not have changed anything. As for the Next.js assembly, I do not argue, it is not 300 mb, but it also weighs normally. Imagine, one normal application has about several thousand modules, to make a normal site - this is literally gigabytes of disk space.Thank you very much for your comment! I changed the code and loaded the modules. It turned out to be 4.4mb instead of 3.6mb, so that there would be no feeling that I was misleading. This topic has been discussed for a long time on Alpine.js and HTMX, you can take their examples. There is no point in repeating myself. This is only a possible alternative in some tasks.
Wow, been thinking about framework bloat myself - you actually switched it up and got a lean setup, respect.
Thank you! Yes, modules bloat the project a lot.
Are you a a bot? I see you commenting on every post LOL
Love seeing someone actually ditch the usual framework bloat and prove it works - makes me rethink SSR vs CSR for my smaller projects. Curious, what limitations did you hit with HMPL compared to Next.js in a real-world scenario?
If it worked in 2010 why shouldn't it work in 2025? What's to prove here?
Serious projects like Spotify will be very difficult to build, but simple landings and modules for real projects are quite possible. That's the difficulty.
Great breakdown of the early experience with Next.jsβespecially the realistic look at how quickly project size can escalate even before significant development begins.
[ I appreciate the honesty around installation weight and the practical insight into what happens when you start adding state managers like RTK Query or building more components. Itβs something many devs overlook until the project starts ballooning.
Refer Style Guide - Click here ](rkoots.github.io/styleguide/)
Well! This is interesting.
I think so too :)
I recently moved to NextJS (fully) and just posted nextjs pros over reactjs. And just after I got yours this post. Another minor shift to use this new module ig π.
Good article! Web components are also said to be good
Thank you! Yea.
Nice!
Good discussion! Thank you for your effort.
excellent work
Thanks!
Good information provided