Pau Sanchez
Programming, technology & business

Frontend SSR frameworks benchmarked: Angular, Nuxt, NextJs and SvelteKit

TL;DR

In benchmarking SSR frontend frameworks, Svelte emerged as the performance leader, while Next.js and Nuxt showed comparable results. As for Angular, let’s say it didn’t quite meet my personal expectations.

Frontend frameworks and traditional backend servers operate in different leagues. Traditional backend servers outperform frontend SSR frameworks by a wide margin in terms of performance. Nonetheless, frontend SSR frameworks offer different advantages beyond raw speed.

Overall, I’m happy with Nuxt and I plan to continue using it, but Next.js and Svelte are excellent choices.

My poor production server performance

It all started a couple of months ago when I found myself measuring the performance of one of my websites. To my surprise, it was only capable of handling 15 requests per second.

15 request per second!!

Not exactly impressive, right?

I mean, generally speaking HTTP servers perform better, regardless of the programming language.

My production server was implemented as a combination of PHP on the backend side and Nuxt v2 for on frontend side. The 15rps were from the Nuxt, frontend, side. Admittedly, my frontend was running on a very cheap VPS server, while other benchmarks were performed on my personal machine, but still, the difference was huge.

Nuxt is a nodejs framework, but even if we focus on nodejs server benchmarks the best performing server (uWebSockets) performes 126k rps for a simple text file. That’s 8,500 times faster than my production frontend server.

In fact, even the worst-performing server (express) manages 8k request per second, which is still over 500x times faster.

The worst performing backend server is still 500x faster than my produciton nuxt frontend ssr server!!

This unfair comparison means that I would need 500 frontend servers (in theory) to sustain the same level of performance than the worst performing backend server is giving me. Not only that, let’s say I’m spending $10 a month on that server… if my needs increased, I would need 500 servers of that size, which would mean spending 500x more money, which would mean I would be spending $5000/month instead of $10/month. That’s a lot of money!

Fortunately, even with the current poor performance my production server is holding up so far for the amount of traffic that I have. But still, 15 requests per second is something I’d like to address.

Apples to apples

It’s certainly unfair to compare a simple server returning a text file to a server with extensive business logic, especially when one is a backend server and the other is a frontend SSR server. There’s likely a bottleneck somewhere affecting performance.

This poor performance got me thinking…

  • How would a simple frontend SSR toy sample compare to a simple backend toy sample?
  • What’s the maximum performance I could reach with a frontend SSR?
  • How would Nuxt compare to other SSR frontend frameworks such as Anguar, NextJs or SvelteKit?

So I decided to set aside my current problem and create a benchmark to compare how a simple “hello world” performs between an average fastify backend server and the Angular, Next.js, Nuxt.js and SvelteKit frontend SSR frameworks.

Comparing fastify to Angular, NextJS, Nuxt and SvelteKit returning a simple string

If you are curious, here’s the code in github for the toy project that compares Angular, NextJS, Nuxt, SvelteKit and fastify.

Let’s start with a simple “Hello world” page.

SSR servers are different. SSR do more work than a raw js backend server does. Frontend servers manage routing, pages, components, … and when serving HTML they need to add HTML and javascript code so that the page is hydrated with data from the server, they need to add client code that takes over the rendered browser, …

There are lots of things going on on a frontend framework, but the main idea of the test remains: for each framework, let’s serve and render the same string, regardless of the HTML the server generates.

A basic HTML page rendering:

  <div>
    Hello World from Page!
  </div>

I tried as well to keep same HTML layout for all frameworks.

Fastify

For fastify this is really simple, because it only needs to return an HTML string embedded in the code, but for the other servers there migth be a bunch of logic involved from the frameworks themselves.

Frontend SSR Frameworks

DISCLAIMER: I’m experienced in nuxt, but not so much in the rest of the frameworks. Nevertheless, I read the documentation and tried to perform a standard implementation in all of them.

Results

Disclaimers aside, here is my configuration (running ubuntu 24.04):

Configuration:
  Node Version:  v22.2.0
  CPU Model:     Intel(R) Core(TM) i7-8565U CPU @ 1.80GHz
  Duration:      10 s
  Connections:   100

And here are the first results:

NameVersionSpeed FactorRequests/sLatency (us)Throughput (MB/s)
fastify4.28πŸ₯‡ 75.47xπŸ₯‡ 26907πŸ₯‡ 24998πŸ₯ˆ 10.0MB/s
svelte4.2πŸ₯ˆ 11.40xπŸ₯ˆ 4063πŸ₯‰ 1382927πŸ₯‰ 6.6MB/s
nextjs14.2πŸ₯‰ 7.21xπŸ₯‰ 25701761519πŸ₯‡ 11.9MB/s
nuxt3.113.86x1376πŸ₯ˆ 3193381.7MB/s
angular18.01.00x35616921440.4MB/s

It is clear that rendering on a backend is at least 6x faster than the fastest of these SSR frameworks for the simplest of the examples I could come up with. Honestly, svelte performance is not that far from the express server from my other benchmark, is only half the speed.

Svelte performance really stands out on this benchmark compared to the others, While Nuxt performance was less impressive than I was hoping for, managing over a thousand requests per second is still good enough.

Rendering a component

What happens if we incorporate a component into the page? Will it affect the rendering speed?

Here are some interesting results:

NameVersionSpeed FactorRequests/sLatency (us)Throughput (MB/s)
fastify4.28πŸ₯‡ 31.25xπŸ₯‡ 11955πŸ₯‡ 38738πŸ₯‰ 4.8MB/s
svelte4.2πŸ₯ˆ 11.15xπŸ₯ˆ 4265πŸ₯ˆ 48687πŸ₯ˆ 6.8MB/s
nextjs14.2πŸ₯‰ 7.30xπŸ₯‰ 2794πŸ₯‰ 71915πŸ₯‡ 13.2MB/s
nuxt3.113.78x14471415171.8MB/s
angular18.01.00x38214539290.4MB/s

NOTE: to be fair, angular implementation here is wrong, but still deserves to be in the last position. See final remarks.

When rendering a simple component we still observe similar performance than when rendering a simple page without components which is a positive outcome.

The truth is that having somewhere along the lines of 100 components, with nested relationships, would probably be a better benchmark to have. Unfortunately for you, I don’t want to invest the time, so that’s left as an exercise to the reader.

Rendering a string from a local HTTP endpoint

Getting this far got me thinking:

  • What if I had an endpoint in Fastify so that all the frontend SSR servers fetch data from that endpoint and display it on the web page?

  • How would introducing such dependency on an API call would affect performance?

Adding this dependency would require the servers to managing async calls and it would introduce some latency. This will certainly resemble more closely what a real-world application does (at a small scale, of course).

So I did, just that. Here you can look at the results:

NameVersionSpeed FactorRequests/sLatency (us)Throughput (MB/s)
fastify4.28πŸ₯‡ 42.60xπŸ₯‡ 11625πŸ₯‡ 16585πŸ₯‡ 4.4MB/s
svelte4.2πŸ₯ˆ 8.38xπŸ₯ˆ 2286πŸ₯ˆ 92637πŸ₯ˆ 3.8MB/s
nuxt3.11πŸ₯‰ 3.47xπŸ₯‰ 947πŸ₯‰ 2468561.3MB/s
nextjs14.21.42x388527451πŸ₯‰ 1.8MB/s
angular18.01.00x27215959040.4MB/s

NOTE: to be fair, angular implementation here is wrong, but still deserves to be in the last position. See final remarks.

While on the components test more or less everything stood the same, on this test we can see a significant drop in performance across all frameworks. The server has more tasks to handle, including waiting for the API call to respond, which severily affects overall performance. Nonetheless it looks like the performance of fastify server holds up (even though is doing the same).

Interestingly, Nuxt and Next.js have swapped positions. Nuxt kind of suffered a little bit, but not so much. I expected Next.js to still outperform Nuxt, but for some reason, it did not.

I’m pleased to see that Nuxt can still handle nearly a thousand requests per second (because it is what I’m using in production now).

Final thoughts

It’s clear that nothing compares to the raw performance you can achieve with a backend server rendering templates or strings. However, Svelte, Next.js, and Nuxt all showed decent enough performance.

We should always keep in mind that frontend frameworks, once they are rendered on the browser, will perform calls directly to the backend. This reduces the requirements for them performing as many requests per second as a website.

I’m satisfied with Nuxt’s performance so far, but I must say both Next.js and Svelte are tough contenders. Svelte stood out and outperformed the other SSR frameworks in all these toy benchmarks.

What about angular?

DISCLAIMER: rant approaching

Angular seems the worst framework of them all. I mean, I know on some tests are not doing what are supposed to and is probably unfair that I included it here, but still, I think it has taken me around 20x more work to get a basic “hello world” compared to the other frameworks like next.js or svelte where I had zero experience developing. I could easily sort out next & svelte, but angular structure, verbosity and complexity got me nuts.

End of rant

Back to my original poor performing server

Regarding my poor Nuxt server, given these results, I believe there is still room for it to perform better.

I’ll probably upgrade it to Nuxt 3, run some benchmarks once it’s migrated, and then address the performance issues.

The server is still managing the current load in production, so I’m not in a hurry just yet, but I’m not satisfied with the current performance either.

Based on these learnings, I think Nuxt is still a pretty capable frontend SSR server. Hopefully, I can speed up my server to perform 30 to 60 times faster if I figure out the bottlenecks (likely parallelizing requests). Only time will tell…

Thanks for reading this far!