Get the latest AI workflows to boost your productivity and business performance, delivered weekly by expert consultants. Enjoy step-by-step guides, weekly Q&A sessions, and full access to our AI workflow archive.
Summary
In this insightful discussion, the creator delves into why Next.js applications, particularly those utilizing server components, may appear slow compared to traditional single-page applications or multi-page applications. The creator argues that the blame for slow performance does not lie with the developers of server components but rather with those who may not fully understand how to effectively use these components. With a historical approach to web development, the discussion covers the different ways of rendering web pages, highlighting the benefits and drawbacks of single-page apps, server components, and how their misuse can lead to poor performance. The solution lies in better understanding server components and using them appropriately, employing techniques like loading states and suspense tags to improve the user experience.
Highlights
The creator argues that the slow performance of server components is due to misuse, rather than issues with the components themselves. 🐢
Understanding the relationship between server and client-side rendering is key to optimizing Next.js apps. 🔄
Single-page applications (SPAs) offer quick responsiveness but may lead to unnecessary data requests. 🚀
Server components can provide the benefits of both SPAs and MPAs when used effectively. 🧩
Using loading states can make transitions feel faster and smoother to the user. 🌟
A fundamental shift in how responses and loading behaviors are handled can significantly enhance user experience. ⚖️
Key Takeaways
Next.js apps can feel slow due to misuse of server components, not the components themselves. 🐢
The importance of understanding both server and client-side rendering is emphasized. 🔄
Single-page apps offer immediate response times but may fetch more data than needed, whereas server-side rendering might be faster in full content loading. 🚀
Server components offer a hybrid solution, combining benefits of SPAs and MPAs when used correctly. 🧩
Introducing loading states and suspense can enhance user experience and perceived performance. 🌟
Balancing immediate user feedback with efficient data handling is crucial for better app performance. ⚖️
Overview
In this comprehensive breakdown, Theo discusses why some Next.js apps might seem sluggish, focusing on the misuse of server components rather than the components themselves. The conversation digs into the history of web application development, comparing traditional server-side rendering, single-page applications (SPAs), and server components.
By illustrating the pros and cons of each method, the creator explains how a proper understanding of server components, alongside implementing features like loading states, can optimize application performance. Emphasis is placed on the need for developers to bridge the gap between server-side efficiency and client-side responsiveness.
With practical insights into how to utilize these modern tools effectively, the creator envisions a future where apps feel as quick as they are complex, leveraging the best parts of SPAs and MPAs. This discussion encourages developers to rethink web app architecture for better performance and user experience.
Chapters
00:00 - 01:00: Introduction to Server Components The chapter discusses the use of server components in web applications, specifically focusing on the experience and performance of these apps. The narrative suggests that server component-based apps often experience slow page navigation times, approximately around 1 second, which impacts user experience negatively. The author mentions some skepticism about the overall effectiveness and adoption of server components, and while acknowledging criticism from a figure named DAX, argues that the issues presented may be slightly exaggerated or not fully representative of the situation. Despite agreeing that many server component apps are not performing well, the author maintains an opposing view to DAX on certain points, suggesting a more nuanced discussion is needed on the topic.
01:00 - 02:00: Blame for Slow Server Component Sites The chapter addresses the common perception that slow server component sites are largely due to the server components themselves. However, the argument suggests that the responsibility lies more with the developers who need to fully understand how these components operate. The chapter signifies that it's imperative for developers to grasp the intricacies of server components to avoid slow website performance, rather than placing the blame on the Next team, Verscell, or the React team. The final call to action is for developers to take accountability for performance issues.
02:00 - 03:00: Challenges in Building Fast Websites The chapter addresses challenges in creating fast websites, exploring reasons for slow site performance, and solutions using server components to improve speed while maintaining a good developer experience with tools like React and Next.js.
03:00 - 06:00: Sponsor Segment - Savala The chapter titled 'Sponsor Segment - Savala' discusses the features and benefits of using Savala for hosting real servers. It highlights the complications developers face with current hosting solutions, such as needing a CDN, DOS protection, file storage, database management, and automatic builds. Savala simplifies this process by providing an easy-to-use dashboard for deploying server instances and managing necessary infrastructure such as Cloudflare for protection and CDN management. The chapter underscores the efficiency and ease of use Savala offers to developers.
06:00 - 07:00: The Problem with Server Components The chapter discusses the challenges associated with using server components in application development, especially when working with frameworks that are traditionally hosted on servers like Elixir, Laravel, and Rails. The process becomes tedious in front-end applications, thereby complicating life significantly when deploying non-JS based applications. However, the chapter highlights a feature called 'pipeline,' which significantly improves this process. The pipeline allows for setting up various environments such as preview, development, and production, and it supports creating a preview app on pull requests, enhancing workflow efficiency. This system, therefore, works effectively across different development stacks, offering a cooler and more streamlined approach to handling server components.
07:00 - 14:00: History of Web and Single Page Apps The chapter discusses the evolution of web development, including the transition to more integrated platforms for hosting and managing applications. It highlights the complexity of setting up development environments in the past, with dedicated teams required to build systems for better code review experiences. Platforms like Savala have simplified these tasks by integrating services such as object storage and databases, supporting a variety of applications from static sites to complex frameworks like Next.js. The chapter notes that this shift is part of a broader trend where hosting services become more versatile and accessible, thanks to initiatives from companies like Kinsta, known for making WordPress easily hostable.
14:00 - 20:00: Handling User Interactions and Responses The chapter discusses the challenges and issues surrounding server components in web development. There is a debate over their effectiveness, with some developers like Michael Jackson from the Remix team expressing concerns about their practicality, while others see them as beneficial despite the additional complexity they introduce. The narrator acknowledges these perspectives and shares their own insights on the matter in response to online discussions, aiming to clarify and understand the overhead associated with server components.
20:00 - 23:00: The Role of Server Components The chapter titled 'The Role of Server Components' begins with a discussion on the evolution and current state of web applications. The speaker contemplates the idea of simply reading a pre-prepared script due to past positive feedback. However, they prefer to delve into the details of the process that led to the current situation where apps are notably slow. A brief history of the web is provided, complemented by a mention of a more comprehensive video they have previously created, which they deem highly valuable though underappreciated. The video explores the technical journey of HTML from server to browser.
23:00 - 37:00: Building with Next.js and Loading States This chapter provides a detailed overview of web development, beginning with the traditional method where a user sends a request to the server for a web page. The server processes the request and responds with HTML content. This HTML often includes link tags for interaction and might also contain forms. The chapter aims to improve the reader's understanding of how web applications function by comparing old and new methodologies.
37:00 - 44:00: Issues with Server Rendered Components This chapter discusses the behavior and issues with server-rendered components, particularly focusing on how traditional web interactions function. When a user fills out a form and submits it or clicks a link, a new request is sent to the server to either fetch new HTML or perform a POST request with form data. Subsequently, the server responds with new HTML. The chapter aims to highlight some critical catches or limitations associated with this interaction model.
44:00 - 52:00: Using Suspense and Loading Components The chapter discusses the delay experienced in web applications, specifically when a user interacts with an element and waits for a server response to update the browser. Unlike modern JavaScript applications, traditional web applications relied heavily on server control. This meant any page content changes required either a server request for new HTML or using animations like marquees to create dynamic text movements on the page.
52:00 - 59:00: Improving Server Components with Next.js Optimizations The chapter discusses the evolution of web applications, noting how they have become increasingly interactive over time, especially with the rise of JavaScript. It mentions past technologies like Flash and Java, but focuses on the emergence of app-like behaviors in browsers. This evolution has led to the development of Single Page Applications (SPA), which load HTML once and allow users to navigate to any page. The chapter highlights the efficiency and improved user experience SPAs offer compared to traditional web applications.
59:00 - 64:30: Conclusion and Final Thoughts on RSCs The chapter titled 'Conclusion and Final Thoughts on RSCs' discusses the irrelevance of certain URL components, specifically noting that what follows the domain in a URL does not impact server response in a single-page application context. This is because such applications fetch only a single HTML page from the server, regardless of what the URL appears to specify. The server or CDN sends this singular HTML, which includes crucial elements in its head section. The final thoughts likely emphasize understanding and focusing on these essential components for effective rendering and client interactions.
Why is Next.js so slow?? Transcription
00:00 - 00:30 it's getting to the point where I can just feel that an app is using server components when I use it nearly 1 second page navigations i'm sure it could be improved but I've yet to come across a server component app in the wild that feels good it's about to save Vzero but I just checked and I'm not even sure they're using them anymore as per usual DAX is mostly right slightly inflammatory and not showing the whole picture in this particular instance i think there's a lot to dive into here i agree with him that most of the server component apps I have seen have been really really rough but I don't agree
00:30 - 01:00 this is the fault of server components i'm going to say something a little controversial on this one i think the blame for the slow server component sites falls less on the next team on Verscell and certainly less on the React team and the people working on server components directly and more on people like me in order for this to work and work well we need to deeply understand how server components behave and what they mean for us as developers because there is no excuse for any website to be as slow as this one is it almost feels
01:00 - 01:30 like we've gone back in time to the way pages worked before i want to break down what makes sites like this so slow how we got here in the first place and most importantly how to use server components correctly so that we can have the fastest possible websites while also matching the great DX that we expect from tools like React and Next.js sadly developer experience doesn't pay the bills i've learned that lesson enough times so we're going to do a quick word from today's sponsor right before we dive in building apps has never been easier thanks to all these AI tools and deploying them has never been easier too
01:30 - 02:00 at least until you need to add a CDN a DOS protection layer file storage a database automatic builds during CI and pull requests and all these other things that we expect now as developers in order to keep moving as fast as our editors let us that's why today's sponsor Savala has changed the game for all of you guys that need to host real servers once I saw this dashboard I immediately got it because Savala makes it so easy to deploy an actual server instance and throw the right infra in front of it setting up Cloudflare in order to handle DOS protection CDNs and all of that stuff that you really should
02:00 - 02:30 be doing in front of your app is particularly annoying especially if you're using frameworks that are expecting traditional server hosting like you know Elixir Laravel Rails etc this has made my life significantly easier when deploying things that aren't my usual JS stack not that it doesn't work with that stack it actually works really well with all that stuff too where things get way cooler is the pipeline feature where you can set up preview dev and production environments s plural yes so people can file a poll request and automatically spin up a preview app that will sleep after not being used for a while these workflows
02:30 - 03:00 are obnoxious to set up and we had whole teams at Twitch building all of these things so that we could have better code review experience all of a sudden it's just a feature built into the platform and as I said before it's not just servers and it's not just the Cloudflare integration it's so many more things like object storage and databases too doesn't matter if you're trying to host a static site an Nex.js app some crazy stuff in Python some weird side project you built in Rails 8 years ago pretty much everything you'd ever want to ship is going to work on Savala and I know that for a fact because this is built by Kinsta the company that made WordPress actually hostable check them out today
03:00 - 03:30 at/savala and you'll get $50 of free credit applied to your account this video is inspired by a lot of the push back I'm seeing on server components obviously this and the performance side that's the most important piece but also complaints like Michael Jackson from the Remix team saying that server components are nice in theory but they're not working out evan here saying that server components aren't necessarily a problem they unlock cool patterns but the overhead is the issue here and me responding with probably too many words to Dax's post trying to break down what
03:30 - 04:00 happened and how we got here i could just read this to you and believe me part of me was tempted to just read this out considering especially how positive the attention and feedback was to it but I'd rather go in detail on how we got here and why these apps are so slow i'm going to do a real brief history of the web if you want a deeper version of this I have a long video that I think is genuinely super underappreciated all the ways HTML gets to your browser i think this is one of my best videos even if I don't look like that anymore if you want
04:00 - 04:30 a deep dive on all of this check that out going to do an overview and then focus more on how to do this stuff better the way the web used to work was pretty simple the user sends a request to the server for site.com/index.html html and then the server processes that request and sends a response which is the HTML content this is hopefully something we all understand once this HTML goes back it will have link tags in it which are the primary method of interaction it might also have forms and
04:30 - 05:00 whenever you fill out a form and hit submit or you click a link it sends a new request to the server either requesting new HTML so site.com/new.html HTML or it will do a post request to a given URL usually the one it's on with traditional form data where it will post to site.com some form data and then the server gets that data and it again responds with new HTML this is how all interactions worked there are some important catches here though there is a
05:00 - 05:30 big delay from when a user clicks on something or does something and when they see a response on the browser because the server is what controls what's in the browser not the browser not the JavaScript none of those layers when you do something in the browser you have to wait for the server to respond with the updated HTML the only way the content of your page changed at this time was either you sent something to the server and waited for new HTML or you used a marquee so you had text that scrolled around but that was effectively
05:30 - 06:00 it over time web apps got more and more interactive in particular with JavaScript getting more and more popular we had the weird Flash and Java era not going to go too deep in those right now thing I want to focus on is more app-like behaviors in the browser which eventually led to what we now affectionately refer to as single page apps SPA the big difference with SPA is that the user only requests HTML once so the user can go to literally any page so unlike previously where the URL
06:00 - 06:30 mattered because I would go to site.comindex or slash user info none of that matters so literally mentally block out whatever comes after the domain because it doesn't matter in this case the reason it doesn't matter is because the server only has one page to send that's what single page app means sends only HTML this HTML page that is being sent from the server or from a CDN or something else has some things in it that are important this HTML has a head
06:30 - 07:00 tag this head tag has the things that actually matter the one that we care about is the script actual or actual app.js this is what most React apps roughly look like HTML wise there is no actual content in the body they might have bothered with a real loading state most don't because the thing that matters is this head tag in the JavaScript this single page is what's served by all the URLs on your site when a bot crawls your site or a user goes to
07:00 - 07:30 a page or someone types in a URL all of those things are going to resolve to the exact same tag to the exact same HTML if you go to any page on Twitch any page on Excaladra any page on most React apps it's the exact same content this kind of sucks because it means when the user gets back the HTML they get an empty state it has to run the JavaScript code the JavaScript code will then make its own additional requests going to make
07:30 - 08:00 one subtle change here which is instead of calling the server I'm going to call it CDN the user will then after they've load that HTML request app.js or whatever else they need to run the page the CDN will send that back and now the user can run all of that and more importantly they can start generating the actual page content so once that is all happened God I wish I didn't bind all of these because now it's going to be annoying to stretch this cool you get the idea user requests from a CDN on the site they get back the static HTML file
08:00 - 08:30 which has the tag for the JS in it CSS and all those other things too they get back that code they run it and now they need to get some data from the API so we have a separate thing here which is the actual server not the CDN cdns are only holding static content and this is the actual server that does the actual work so the user has to go to I don't know SL API/ some data and then the server parses their credentials checks who they are figures out what they're requesting and then responds with whatever the hell
08:30 - 09:00 they were asking for in this case probably going to respond with some JSON data you get the idea now your app has that data now your app can turn that into the React components and eventually the HTML that appears on your page there's an important question though what's going on right there in between this section once you get the HTML and once the data is being requested and then eventually is being shown to the user but more importantly basically from here to here what is going on the reason
09:00 - 09:30 I ask about this section is it's actually a thing single page apps do really well if your components need to request data you can do that in the component which means in that same component you can render a loading state that is nice because now when data is loading the user still sees something on the page and the developer has control of it it comes at the cost of you can't choose what they see from here to here you can give them some static HTML but no one ever bothers but once the JS is loaded you have full control of this loading state and what's even cooler is
09:30 - 10:00 since every page has the same HTML most of them have the same JS and you can prefetch the JS that's page specific if you choose to now when a user clicks on a different page you don't have to wait for the server to respond because a single page app doesn't do server side navigation it does it all on client when a user clicks on a link in a single page app it doesn't have to make a request to the server i almost want to make a quick demo to show this but you could imagine you have a traditional website that has three HTML pages you open up the network tab you go from page one to page two
10:00 - 10:30 you'll see it going to the server to request that page if you're doing a single page app it hijacks the routing and the history in the app and now what it does instead is when you click a link it uses the JavaScript from the React bundle to update the HTML instead no longer do you need to do a server request on every single navigation that said most pages are going to need to make API calls when I go from a tweet on my homepage on Twitter to my profile data has to be loaded to show my profile
10:30 - 11:00 correctly traditionally that would be a whole new HTML page being sent and when you're waiting you would get a loading state from the browser if even the browser's loading states generally speaking kind of suck and users don't expect them we'll come back to that in a bit don't worry this is positives and negatives the cool thing here which is again the important piece I want to emphasize is once this JS here loads once you have successfully gotten this JavaScript into the client from that point forward everything is going to feel immediate simply because when a
11:00 - 11:30 user clicks on something the response happens instantaneously because it's happening on their device it's not waiting for a server to make that change in the old model that wasn't the case anything the user did would require a server call with single page apps it doesn't it takes longer overall for the user to see the right content but when you feel the page change instantly it feels faster and I'm not the only one who thinks this this is a very wellstied phenomena if you have a website that takes 1 second to go from load like the user requested the page user clicks link
11:30 - 12:00 and then 1 second later you have the full content this isn't necessarily bad if this takes 1 second to do you're not necessarily building a website that feels awful i know this doesn't feel that bad because I've built websites where the time for loading full content is more than 3 seconds some are like five or six but it doesn't feel that bad because I would respond as soon as the user clicks so within a very very small number of milliseconds I'm going to kill
12:00 - 12:30 that and instead put one here which is like 0.013s at this point here really really early on I changed the content of the page one more important detail of this is wherever the user clicked you need things to change there as quickly as reasonably possible when a user clicks on a link ideally you should be able to show on the link and the page that something is happening as soon as they click because otherwise they're not going to be sure they're going to click it multiple times they're going to do a
12:30 - 13:00 lot of other things i'm not saying throw loading spinners everywhere i'm saying that the point of interaction needs to change if you have a sidebar that has a whole bunch of links in it something like this you have like link one link two and link three you're on link one you've already loaded that page and you click link two if your loading state is just here it's better than the weird little bar in the browser but you clicked right there so you need to show on that that the click applied and
13:00 - 13:30 something is happening if you don't it will still feel slow this is the case on a lot of websites that are built this way and for better or worse sad to say but this is the case for a lot of sites using technologies like Laravel and Rails that aren't taking advantage of single page app behaviors there are exceptions in particular if you're using inertia with Laravel your site's going to feel great because Laravel with inertia is literally using reactor view as the runtime on the client side laravel has now been relegated to server
13:30 - 14:00 duty this is how things like the whole Laravel cloud platform are being built and the reason they feel so good is because they're using React for its strengths which is the client side behaviors and you can handle all your API stuff in the Laravel side or whatever other language you want to use that does touch on one other important piece here which is that there's a clear line here a division between the client and the server and instead of the server telling the site what to render and what to show JavaScript devs can handle all of that themselves all of the dynamic behaviors all the interactions all the
14:00 - 14:30 everything happens in the JS bundle now not in the server code which has allowed for JS devs to kind of lock in on that client side and not leave which has benefits but it also has some negatives we're going to get to back to this loading thing here though before we had single page apps you wouldn't have this immediate indication you might have your site set up in a way where it blank pages immediately when you click the next site but most didn't most browsers would hang on the page you were on as you wait for the next one to load with
14:30 - 15:00 no good indication that this transformation or this change is happening somebody said that you can use view transitions with help with page full page reloads if the page is already loaded but a view transition doesn't help if the new page isn't there yet a page transition takes new HTML and old HTML diffs them and makes an elegant transform from one state to another but if you haven't loaded the full content yet a view transition can't help you at all the thing that matters here and it's really important is that you get the
15:00 - 15:30 user feedback as quickly as possible there are some measures of how quick before a user feels like it might be slow less than 50 milliseconds feels really fast generally speaking if you can show the user something happening in less than 50 milliseconds it feels really fast if it takes more than 150 milliseconds it feels unresponsive it takes more than like 17th of a second to see something happened our brain just assumes the site isn't responding well there's a bunch of research that gets
15:30 - 16:00 these numbers i don't feel like finding it and citing it take my word for it or don't if you use a website where these things don't happen you'll understand and if you use T3 chat and then compare it to our competition you'll understand even more so and they're also doing this they're doing things to get you a response immediately so when you click a thread on the sidebar it immediately indicates there that you're navigating hopefully I've drawn the point home here single page apps make it way easier to respond immediately to a user interaction and when users are interacting more they're clicking more buttons they're changing pages more often they're exploring the site in a
16:00 - 16:30 different way than how we used to in the past where we would load a page stay on it for a while then click a button and go to the next page spa work differently and they're meant to feel more like apps not sites that's a big big difference i don't think people appreciate the reason apps on the web have gotten so good isn't because servers are fast it's not because browsers are better these things all help the main reason is because single page apps as a paradigm allow for better app-like experiences in the
16:30 - 17:00 browser everyone this is going to be a short overview so much for that part so where does server components come in with all of this server components are very interesting there was another stage that you're gonna have to go to my HTML video if you want to learn more about which was the idea that a different URL could have different HTML that was just the React code run on the server once to generate a better page as a starting point server components go a bit further and I just took the same diagram this part matters again the / user info or whatever URL you're going to matters
17:00 - 17:30 again because it will generate different content it will check the CDN first to see if there is a cached version of this page if it's a static page if there is it will send static page but if the page isn't static and it can't do that it will then forward it over to the actual server so this then sends to the server the server will generate the page and then that generated page gets sent down to the user this is a very different paradigm it's also worth noting that you
17:30 - 18:00 need a CDN that's smart enough to do this two-step layering where it uses the cacheed asset if it can or it goes to the server if it can't and if you're just hosting a server component-based Nex.js app on Docker it's going to have much worse performance characteristics than a single page app simply because you're not using a CDN if you're building a single page app then when you run your build command it generates one HTML file and a handful of other assets and then it dumps all of those into a
18:00 - 18:30 place where you can access them really quickly that is static and then when a user navigates it hits that but when they call the API it'll instead hit their server if you're using server components without some type of CDN between the user and your server you're using server components wrong you're going to have a bad time it's going to feel slow as especially compared to a single page app that's just first page load though where things get frustrating is when you start navigating so if I go to / user info and then I change my mind or I click a link and I want to go to
18:30 - 19:00 /dashboard when I make that navigation it now checks the CDN see if that content exists if it does it sends it down if it doesn't again round trip to the server before sending it to the user that means you're no longer getting those instant navigations right this is where the nuance comes in kind of i think React devs got a little too used to waiting for some data showing a loading state while it's loading and showing the result when it's done and that pattern did work great for most of the apps that we built it also means
19:00 - 19:30 that everything that happens from here onwards kind of doesn't exist in the React developers brain this is a frustration I've had for a while it feels like web devs don't understand servers not necessarily as a generalization where like every web dev doesn't get it but like my history is backend and this is when I really feel like I'm not a traditional front-end dev as much as you guys stereotype me as one because I very deeply understand this and have had to go as far as like explaining what cold starts are to Dan Abramov because not everyone gets it and
19:30 - 20:00 that's fine until you need to write code that runs on servers and here's where the problems come in i built us a mock app to try and showcase where things fall apart this demo app is a dashboard i'm going to open up the network tab so you guys can see what happens as we navigate around i am going to click second page right now and it loads almost immediately with no network requests i'm going to click third page and same deal no network requests now I'm going to click first page that took 576 milliseconds it took
20:00 - 20:30 way too long to respond and if I go back because uh Shane found the response time limit study the barrier for feeling instant is.1 seconds 1 second is above the limit for a user's flow of thought so if it takes more than a second then you've stopped thinking about the thing you're doing and your brain is starting to wander 10 seconds you lose their attention entirely so ideally you respond as close to.1 seconds or less as possible so that it feels instant so
20:30 - 21:00 there is nothing you have to do to handle the user behavior if it takes longer up to a second then you need to be real careful to not lose the user's attention and if it takes over 10 seconds you're kind of so as we just saw on that page load it took 600 millonds it's not quite over the 1 second limit but it's enough that it feels way slower so I click here nothing i click here nothing i click here wait then it shows it sucks let's look at the code that causes this i made a simple mock app here we have the dashboard
21:00 - 21:30 layout as use path name different links each of those links shows uh underline if you're on a certain page or this outline there when you go to one not bad overall but that loading time there like watch I'm clicking moving the mouse and it looks like nothing happened it feels really bad the reason that component is so slow to be fair is because I put a wait for 400 milliseconds there i intentionally slowed it down because I'm fetching data from this like JSON blob locally so it's going to be fast but I
21:30 - 22:00 wanted to to make it feel slow because real API calls real servers real round trips real distances between the user and the server all of these things will make it actually close to 400 milliseconds i've had services where the database calls can take multiple seconds especially once the databases get big enough things can get chaotic people get really mad at me when I say database requests can take a second and that's fine and that just kind of says they don't use real data anyways the point here is that this one particular page takes 500 plus milliseconds to load and
22:00 - 22:30 show to the user the app structure here is pretty simple we have the layout which is the wrapper for the main dashboard page as well as first second and third these components aren't asynchronous they're synchronous and these components don't have any data fetching nor do they have the dynamic flag at the top i had to tell Nex.js JS to force this page to be dynamic because by default nothing was using cookies and nothing seemed user specific so it had no reason to make this page dynamic it would just build it at build time and serve it from the CDN so if you're able
22:30 - 23:00 to do that if you can have pages like these two that don't have user specific content they don't need an off wall they don't need any of those things you can just have it build out as static pages and it's not even going to request them when I click these these are all content that was loaded in the JS bundle that now is there and ready to go when you click the links that's really cool in my opinion the fact that once the page is loaded once this whole site is loaded and the JS is there too most of the
23:00 - 23:30 pages aren't going to need extra work to get to they don't need a network request they don't need to do anything they're static nex.js knows that and Nex.js will load those pages immediately the way we expect with single page apps because RSC's are true hybrid it's spas when they can be and MPAs when they should be so how do we fix this awful loading time i'm going to show you a build where I already fixed it and then I'm going to show you how I did it watch what happens here when I click first page i'm clicking it now oh that was immediate
23:30 - 24:00 why is that that shouldn't have been immediate immediate we'll refresh and try again clicking now huh it showed me something instantaneously that time if we clear this and you watch the network tab I'm clicking now the moment I click we get that loading state it wasn't a good loading state but it was one and that meant that most importantly this sidebar where I click as soon as I click second page isn't highlighted anymore and first page
24:00 - 24:30 is that's a huge win for the expectation a user has when they navigate that when they click things happen immediately but that was a server component that was doing a bunch of complex server side logic the loading state must be complex too then right because I'm not checking on the server and sending something down different when I'm loading i'm not even doing pre-fetching here or any of those other hacks so what's going on why is this so much better already well I made one small simple change all I added this one file loading tsx in Nex.js this is
24:30 - 25:00 the easiest way to add a loading state there are other ways I could in my layout wrap a suspense tag around the children so that they don't have to be rendered before that like content loads but the loading tsx is the easiest way in order to understand how loading tsx works you need to understand a bit about the next rendering hierarchy if I have a page like /dashboard first next.js has to resolve this in a couple layers first we have the root layout which is an app/ layout
25:00 - 25:30 tsx that file is the one that has your metadata usually for your main homepage on your site it has your HTML tag your body tag any providers you might be wrapping your app with all that goes here this is the entry point for your app using app router and server components with Nex.js as we go through each of these steps because our goal is to get to a specific file the file that we want to get to the one that matters is app dashboard/first/page.tsx this is the one
25:30 - 26:00 that has the actual content but as we start from slash and go all the way to first we're collecting things on the way if we had an app/loading tsx we would collect that at that point but we don't so we do end up collecting is app/dashboard/ layout tsx then app/dashboard/loading tsx what's happening here is as we go through the UI and as these components get mounted this mounts as like the wrapper so this
26:00 - 26:30 whole section is app/ layout tsx since that doesn't render any real content the next layer is basically identical i wish I had an easy way to indicate that here make it like slightly smaller but know that this layer is still the same content HTML wise it's just a tag inside but what you see as the user it's identical i almost want to sketch this out as HTML actually that might be easier so the app layout covers all of this within here we have that body tag
26:30 - 27:00 this is going to have the sidebar and it's going to have the first page content this section here the content of body is going to be wrapped with the next layout and then this first page piece in there is one of the components being passed as a child what matters about this is as we go down the tree we're looking to see what is or isn't static and we're doing this during build so at build time we know that app
27:00 - 27:30 dashboard first exists so we're going down the path to get there and seeing what we hit along the way what we notice when we hit first page specifically since this component is dynamic since this element requires something that is unique to this request we can't generate this whole page statically so what we then do is we climb up looking for a wrapper of some form if I was to make this not HTML and make it the actual like names of the components it might be a little easier to understand app/
27:30 - 28:00 layout is this root wrapper there app layout is all of this stuff in body we have app/dashboard layout and then we have inside of the app dashboard layout component the sidebar because as we saw in here that's what I mounted i have div class name whatever sidebar and then this main element that has the actual content we could even show that here i then have main and this is where children renders so what happens if children has to do
28:00 - 28:30 more stuff well we'll go down the tree app layout static cool html static cool head static cool body static cool app dashboard layout static cool sidebar static cool main static awesome children oh children's dynamic we need to find a way to render this page if we can so the next step is we go up the chain looking for a barrier or a stop gap at some point that tells the build step
28:30 - 29:00 this can be static so if we go back here when I made this loading tsx what this loading tsx does is it introduces one additional barrier it introduces here app/dashboard/loading tsx now when we are loading the dashboard right here we can fall back to whatever's going on there if you're familiar with suspense you could effectively also put a suspense tag here to do the same thing the point I am trying to make as I draw all this out is that as you go down the
29:00 - 29:30 tree once you hit something that requires data from the server that's unique to the user's request this whole tree can't be sent until all of it is generated but if you put things like loading states above the dynamic content or you wrap things in suspense now we can build a version of this page we can have a static HTML version of this page that doesn't include the children it just puts the loading state in and now when a user makes a request to go to the page when they click the button we can
29:30 - 30:00 immediately show them that built bundled static version that is the loading state is we wait for the server to generate and send down the content to fill in to replace that loading state with the reason that people are doing this wrong is that it's very different from how we did before previously when we wrote a component it was pretty simple here's a real traditional basic boring React component that we've all hopefully written something like before in here we have data it is loading we request the data we check if it's loading still if it is we return the loading state and if
30:00 - 30:30 it's not we return the data this is great simple awesome also only works on client side the problem here is the data loading is now done entirely differently because we're doing it on a server side async component i can't go into first here and do something like I don't know instead of awaiting here I can't return something different while this is going on and then return the rest later because functions don't work that way react works that way but functions don't and once you're calling async functions
30:30 - 31:00 you can't send a response down and then send another one later and that certainly won't work at the build step either because we need to know what HTML each page points to the only reason this model works for React as a single page app and as React that we know today is that all of this code every single line of it all of the functionality all of the everything lives on the client this code runs on the server i'm hitting file system so does it even matter if theoretically I could return something different early and something else later simply because this code can't run on
31:00 - 31:30 the client so the client won't know what to do with any of those different states as they happen thankfully the React team accounted for this as did the next team as a quick demo I just replaced the loading tsx with this suspense fallback instead there's a reason for this when I go back to my page here and I refresh you'll see we get the loading state and then we get the dashboard if I go bump up the amount of time it takes it'll be even easier to see i'll make it 4 seconds instead of 400 millonds so refresh 1 2 3 4 there we go when I
31:30 - 32:00 refresh again one two three four cool there is a catch though i'm going to click on first page again huh that's taking a while again the reason is that the next.js JS build step the compiler that actually generates the pages that each of these things goes to in the JS that can navigate for you isn't smart enough to know that that suspense tag we
32:00 - 32:30 have here means it can generate up to this point as a static page next isn't smart enough to make a static page for this that is then bundled correctly and that's why they introduced two patterns to to solve this the first one is partial pre-rendering where it will go all the way down until it hits a suspense tag and then generate that as HTML the other is one that I'm really excited about dynamic IO these are not ready yet so make sure you understand as I show these they are very very new server actions are not anymore but if we
32:30 - 33:00 hop in here PPR true for partial pre-rendering and dynamic IO true for these new IO behaviors i also have to go hop in here and delete this force dynamic the thing that makes dynamic IO cool is it's smart enough to look for the first async boundary and then treat that as dynamic dynamic IO literally means on IO which is asynchronous work things that hit file system databases network stuff like that at that point opt into a better build step and loading pattern so with that all on if my understanding is correct going to
33:00 - 33:30 restart the dev server to be sure reload we get the loading state second page first page huh is it really not smart enough to do that that's annoying i really thought that would be smart enough to handle this case i guess it is not if I build it will it be loading dynamic IO and if anybody at GitHub is watching this I will do whatever I must to get you guys to change links that aren't to GitHub to
33:30 - 34:00 be target blank i should not click on a link and have it update and override the tab I am in clicking a link should open a new tab this behavior has never once made sense it never will make sense fix it i just built this with the suspense and dynamic IO turned on to be sure and sadly enough now when I click first still has the same problem the reason for this is because layout doesn't rerun on client this has to be run on server the first time so when
34:00 - 34:30 we're going down the path this has to hit the server to run again because it knows that specific route is dynamic so we need a way to tell it when that changes and you can't do that in layout tsx so let's move this suspense a little bit change this from the default async function to just be async function first page content at the bottom here export default function first page wrap that with a suspense and now that we move the
34:30 - 35:00 suspense there there we go now we get those immediate behaviors so the gotcha that I just hit and I'll be honest I wasn't sure if I would hit this or not part of why this is all so confusing is if you're doing something asynchronous that requires data or is checking a user's information at any point during your render process ideally you show next a clear path on how to get there statically since I moved that
35:00 - 35:30 suspense here the component first page which is what gets thrown into layout tsx that is static so at build time we can identify that this route is static up until the page loads this component because then its child first page content that is now dynamic and that will be fed in when it's ready and the build step the static HTML and JS that's generated for this route will go up to here and will include this loading state
35:30 - 36:00 instead but as I was trying to hint at earlier you don't have to do that because all you have to do to get this behavior is add that loading tsx file why my editor keeps doing that loading tsx and now in here if I export default loading I don't have to worry about anything anywhere else i just export that and I'm good to go since this is exported here it automatically is inserted inside of the layout as the loading state wrapper you shouldn't be doing dynamic stuff in layout if you don't have to and you certainly shouldn't be doing loading data patterns
36:00 - 36:30 in it if you can at all avoid it the existence of loading tsx helps you shortcut all of this and as silly as it might seem we go back to the demo DAX had here this absolutely could have been solved simply by adding a loading tsx file wherever the layout that shows these are and it's annoying that you have to know that but you also had to know that on the client side too you had to know that when you get data it has this loading state and you have to return something for it there the difference here is simply that we get
36:30 - 37:00 type safety with all of these so if you try to access data before you verified it exists you get an error so now we have to return the right thing before we can use that data that's awesome it's a really cool feature of TypeScript and it's a big part of why I love it so much there isn't really a similar way to do that type of type safety with these servertoclient interactions there is no way for us to use TypeScript to check and say "Oh the component you just mounted is dynamic make sure there's a
37:00 - 37:30 loading state somewhere above it so that we don't block the URL and we don't block the page." What I've considered doing is building a plugin for the next build step or lint step of some form that checks the outputs and makes sure that none of the routes that are built can't do these things and thankfully Verscell's given us relatively good tools for checking these if I hop over to my inspector here we can see what was built and most importantly at the bottom here you can see what type of page each route routes to the empty circle means static so all of these pages are fully
37:30 - 38:00 static routes but then we have dashboard first which is dynamic they also have a cool partial pre-rendering indicator if you have that set up properly where it'll be a half circle we're not using PPR here my ideal world would be one where when you have this and it's not on slash API you get an error of some form so the team can take a look and make sure that this should indeed be a function and not something static you can also see here that each page gets its own JS and we have this loading js too these all being embedded mean
38:00 - 38:30 they're all on client so when you click something it can render the right content accordingly really nice having this output and seeing what is being generated it would be much nicer if I could clearly indicate here that this does have a default state that it falls back to in the interim and now we can see clearly here with the dashboard first that it's partial pre-rendered which as they say means it has static HTML with dynamic server streamed content so the user on navigation can immediately see the static content and
38:30 - 39:00 then also kick off the stream for whatever parts are unique to that page and that user it's so nice and I am very excited for this to become the default in Nex.js ppr was announced two years ago roughly when I talked to Verscell they're still hesitant to tell me to recommend it and even hesitant to tell me to use it but in a nearcoming future this will be what we want to do on all dynamic routes so that they all have some static HTML that they can immediately load and then bring in the dynamic part when it's ready and this all results in our ultimate goal which
39:00 - 39:30 is user clicks link immediately has something happen and then when the output is ready it shows it when it's ready to go back to my long post here there are important considerations to make and I don't think modern web devs are equipped to have these considerations because the intricate relationship between the server and the client is something that most people don't understand both the client side people and the server side people i saw both making fools of themselves throughout this the client side of people saying it was so much better when
39:30 - 40:00 it was a single page app you're making everything harder for no reason and slower too and the server side people saying just send HTML why would you send all these other things instead both sides are wrong here because client side navigation is objectively better it makes it way easier to hit these latency expectations that users have it makes your apps feel significantly better but on the other side if you're doing it 15 plus requests per navigation you're now offing the user 15 times every time they click a button it makes the backend characteristics much harder to get right
40:00 - 40:30 and the performance expectations much harder to land it makes the load to the complete page way slower it's funny how a page taking 2 seconds to load is fine if you see something immediately but a page taking 600 milliseconds sucks if you don't see an interaction immediately single page apps let you get that 4-se secondond load time but also that immediate response source side rendering lets you get the optimal time to complete page at the cost of that loading state rsc's are this magical in between where you have the traditional
40:30 - 41:00 client behavior and you have the server loading all the dynamic stuff together as one so to summarize the world before RSC's looked something like this if we have left to right we'll say it takes 3 seconds to load this page the traditional MPA which is traditional server assuming that the user is clicking on a link here the traditional MPA isn't going to show anything until you get to the end of the load but it can do that load really fast because it only has to request the data once it
41:00 - 41:30 only has to off you as a user once it doesn't have to wait for a component to load before loading the next data it can just load everything at once so page loaded we'll say the page loaded completely assuming they made it like optimal data queries they fetched everything with a single SQL call say it took 0.7 seconds if we take a traditional single page app it will probably take a hell of a lot longer to actually load the content and we can't say page loaded anymore because the page is always loaded you're not loading a new page so we'll say content fully
41:30 - 42:00 loaded the content fully loaded might take a lot longer it might take 2.5 seconds especially if you have a component render and then it mounts a component that then has to go get additional data then it mounts a component has to go get additional data you get all of these waterfalls back and forth the difference with a traditional single page app is when the user clicks you can immediately do something different as I've been saying this whole time so the first response will happen significantly faster like literally 0.05 seconds so the user will see
42:00 - 42:30 something way earlier the page will finish way later this still feels better than this does as crazy as that might sound I didn't believe it either but I've seen it i have built a lot of apps in all of these ways most users will perceive this site as faster i know that because that is what happened with Ping the Ping GG site is not fast saw how long it took for all that to pop in if I hop over to my actual Ping dashboard I'm
42:30 - 43:00 signed in here i'm going to click the dashboard button now instantly get a response and then the rest has to flow in there were points where our infer wasn't in a great state and that next state it would stay in that loading spinner for like two plus seconds that's not the case anymore because we optimized it but it didn't matter cuz when you clicked a link it would immediately go to the thing if I click join room immediately get a loading state if I go back we immediately go back to where we were because that's all cached if I hit options immediately loads the next page even if it shows
43:00 - 43:30 that loading state it doesn't matter because when I clicked something happened instantaneously that expectation is key oh good context from Lee here part of the reason that partial pre-rendering isn't stable yet is some of the warts that I just stumbled onto in the video they want to get the model right with use cache and dynamic IO before you can have a good time with partial pre-rendering it's then a switch that you'll flip for faster initial time to first bite mostly agree the piece that I think is more important than TTFB is immediate navigations i want not just
43:30 - 44:00 when a user types in the URL and hits enter to have that show something as quick as possible what I really want is when they click a link once the site's loaded that they don't have to wait before seeing something change and right now the loading tsx file helps a ton with this but not quite enough if you don't know how to apply it properly i really want a world where every click has that spa magic of instantly showing you the next page in some state even if it's entirely empty but I want a reaction to my click immediately then
44:00 - 44:30 the data when it's ready the traditional SPA now I do something controversial spa dev building RSC's so you take a single page app dev that is just not familiar with server load patterns or the nature of how RSC's work here it'll be faster Because if you took the exact same code with those nested components doing the waterfalls on the server will be a hell of a lot faster than doing it on the client it might even be like half as
44:30 - 45:00 slow we'll we'll say that it's possibly more possibly less we'll say half as bad 1.2 seconds this still sucks this still is a really unpleasant experience you get much closer to the traditional multi-page apps performance and honestly if you built these exactly the same it would be identical however you also have the same problem that traditional MPAs have which is that you don't get a response when you click and that's to go back to Dax's post why this site felt slow if you built this demo with
45:00 - 45:30 traditional technologies like Laravel or Rails without any client sidejs it would feel pretty much exactly as slow as this does plus the cold start hits and potentially JavaScript being slower but in the end it's all data fetching it won't matter the point here is that this feels slow because each page navigation each click requires the server to respond with some content this is also why HTMX doesn't solve the problem as much as I love HTMX it doesn't solve this but there is a win here there is a
45:30 - 46:00 way in the way it's what happens when a back-end dev gets RSC's when somebody actually understands the RC patterns or maybe they watch my videos and learn about it that way or they've been paying attention to all the Versel change logs and release notes and all of that stuff it is harder to get here than it should be but once you are you end up here with the best of all worlds you get a first response just as quick as you do in a single page app and you get a full content response roughly as quick if not
46:00 - 46:30 just as quick as you would in a traditional MPI these two terms are usually TTFB which is time to first bite and FCP which is full content paint the problem with MPAs as well as RSC's if you do them wrong is it makes TTFB the same as FCP if time to first bite is the same as first contentful paint then you end up with that awful loading window up until then i'm going to draw these in with two different colors red is for the bad loading state which is the user is
46:30 - 47:00 relying on the browser's loading to see that anything is happening and with a traditional MPA you get that state up until the page is loaded with a traditional SPA this loading state gets resolved almost immediately and now you the developer can have a nicer loading state we'll make it yellow i was going to make it green but I'm scared people will make that think it's good it's still not good to be loading for this much time but it's a hell of a lot less bad than being in the terrible browser state where it doesn't feel like anything happened problem here is
47:00 - 47:30 this and this is what Dax experienced this is why it felt so bad he was in the bad loading state the entire time until the response came through in my opinion the goal is get this red bar as close to zero as possible and get the yellow bar to be as short as reasonable in an ideal world there would be no red bars and short yellow bars and the option here that has the shortest red bar without massively increasing the yellow bar is definitely server components done right
47:30 - 48:00 if we took all of this and flipped it you'll hopefully see what I mean tada and you'll say we screwed up moving all this JavaScript to the client this is what they mean the lowest number here by far is the multi-page app it is the one that can load the content to the user the fastest because a request comes in it immediately gets resolved with a specific pages content and the user sees it when it's ready but they get nothing until it's done this line here is a good response time for when the user clicks and the MPA doesn't hit it and the
48:00 - 48:30 server components without good loading behaviors also doesn't hit it if RSC's are done right it should get the best part of a single page app as well as most of the performance characteristics we expect for multi-page apps without the negatives it's kind of going for a best of both and in my opinion it does a very good job at it as long as you know the quirks and gotchas this is the easiest way I could summarize all of this is this chart the goal of RSC's is to take all these bad data loading patterns we use in single page apps and squash them into a much faster
48:30 - 49:00 serverside on request data load and it does a great job at it if you know how to use them and you take advantage of tools like the loading file like suspense and use them all properly and carefully but if you don't use those things you end up with a slightly worse version of what we're used to in the old multi-page app era so you got to be careful when you use these things make sure you're putting loading places make sure you're putting loading states in all the places they make sense it's really really nice behaviors and characteristics overall it's not a proper server component video if I don't talk about HTMX for a bit so this is one
49:00 - 49:30 last tangent because I did mention HTMX in my post what HTMX had to say is most clicks on a web page do need to make at least one round trip to the server i agree when you navigate to a page it will likely need some data that is from the server the only thing I disagree with is this part is it really better UX to replace the browser's reliable informative batteries included loading bar with a spinner assuming the dev even bothered to yes it absolutely is it is significantly better and it sucks that this is the case but the browser loading
49:30 - 50:00 behaviors are they are garbage they are really genuinely bad no one understands when the browser is loading something they hit the button four times instead is what ends up happening there's a reason that rage clicks are one of the most important things we track on our apps through our analytics tools and our error management tools if the browser doesn't show you on click that something is happening right where it happened the locality of the response is important if it's a bar at the top of the page it doesn't matter if it's a
50:00 - 50:30 loading status at the bottom of the page in the bottom left corner it doesn't matter and it's sad that I am the only one who's like in between here because as you guys know HTMX was built by and for backend people and it is so correct most of the time and this is why I am regularly stuck in the middle is I have to explain to front-end people why HTMX is good but now I have to explain to the backend people why the browser sucks i'm stuck in these two places where I have to explain to React devs that not everything should be JSON and I have to
50:30 - 51:00 explain to HTMX devs clientside JavaScript for loading states is actually a beneficial thing it's a good thing to not wait for the browser to decide what it will show you and when to actually control that state it makes things feel faster when you click and you immediately are somewhere else even if the page is empty if I own the loading state it does feel better browsers are incredible but they're also terrible and the user experience built into the browser by default is not a good one we should stop pretending it is because we will end up with many more
51:00 - 51:30 slow sites and it is this exact mindset that results in the problem that I was quote tweeting in the first place if you think this way all you're going to end up doing is building more terrible feeling sites like the one that started this video in the first place we need to make things that feel good hopefully this was a useful deep dive on the performance characteristics of different ways of rendering and maybe just maybe a useful way to think about server components let me know what you guys think are RSC's way overrated or is all this drama being a bit overblown let me know in the comments and until next time