Guillermo Rauch — Client rendering, server rendering, pre rendering

In this Holy.js talk, Guillermo Rauch, founder of Zeit (now Vercel), explores the landscape of web rendering strategies—client‑side rendering, server‑side rendering, static site generation, and hybrid approaches—through the lens of essential versus accidental complexity. He argues that most past "silver‑bullet" solutions only reduced accidental complexity, while essential complexity remains. Rauch recounts the origins of Next.js as a tool to eliminate accidental complexity (webpack/Babel configuration, routing) by using file‑system conventions and zero‑config defaults. He then compares the trade‑offs of static site generation (cheap scaling, predictability, security) against SSR (dynamic data, higher operational cost) and introduces incremental static site generation (ISSG) with getStaticProps/getStaticPaths, enabling per‑page rebuilds on demand. The talk covers Next.js API routes for headless CMS integration, the philosophy of conventions over configuration, and upcoming performance features like progressive hydration and smarter code‑splitting. Rauch also shares his vision for the future of JavaScript frameworks—templating‑centric, visual UI design tools, and the rise of Svelte—while fielding audience questions about folder naming, pagination, and CMS choices. The overall message is that a hybrid Jamstack model, powered by Next.js, can tame essential complexity and become the default way to build fast, scalable web applications.
Chapters
Thank you so much for that fantastic introduction, and thanks for the organizers. Thank you to Tanya and Dmitry for having me here. Thank you so much. It's a wonderful city, it's a wonderful opportunity. So as per my introduction, I'm the founder of Zeit, and something we're on a mission to do is to empower the frontend developer. We want frontend developers to build and deploy powerful and fast applications. So it's really great to be here at Holy.js because we think that JavaScript has been the fundamental technology that has enabled this transition towards client-rich, powerful web applications. And JS is the lingua franca of the internet. It is really a great time to be here today, and it's a really great technology to develop an expertise in. But when it comes to developing and deploying applications with JavaScript, we've been faced with a lot of complexity over time. So you've probably heard of solutions like static rendering and static site generation. Dynamic rendering, server-side rendering, streaming. There's a whole slew of technologies involved when it comes to choosing and deploying and developing the right application. So when do I need to do client-side rendering? Where do I need to do server-side rendering? How about pre-rendering, like static site generation? When, when do I use each of these techniques? So when I was writing this talk, I thought about a paper that has been very influential in the software industry. It's called "There is no silver bullet." And when I think about a silver bullet, in case you don't know the reference, silver bullet, it was the magical technology that would kill a werewolf or a vampire or a monster. But we're not going to talk about this silver bullet, which doesn't exist, and neither does the software one. So we're gonna talk about essence and accident in software engineering. So this paper is super simple and actually very approachable. It's not a paper with formulas or proofs or anything like that. It just talks about this idea that there's not a single technology or feature or software application or methodology that'll make you an order of magnitude better. Meaning there's no such thing as 10x technologies, or 10x engineers for that matter. And one of the things that this paper talks about is essential difficulty and accidental difficulty. So us all here in this room, because we deal with JS and Node modules and all that stuff, we love accidental difficulty. So I'm going to talk a little bit about that. So essential difficulty, or sometimes essential complexity, is inherent to the problem that you're solving. So if you were implementing an algorithm or data structures, it's really easy to understand what the essential complexity is because you start thinking about space trade-offs in terms of memory allocation, or you start thinking about how many cycles of compute I'm spending spending on solving this problem. Accidental, on the other hand, is not something that is required to solve the problem. We added the accidental difficulty. So as I was researching a good image that would portray this, I thought about— we've done quite a bit of damage with JS over time. I don't think it's quite a scam to sell more RAM, but you kind of get this idea of where we're going. So one interesting argument that the paper makes is that in order to solve this quest for making software engineering better, most of the breakthroughs that have happened have not really tamed essential complexity. They've only tamed accidental complexity. And he mentions, for example, high-level languages, time-sharing computing, and unified programming environments as examples of this. And then he mentions, what are the contenders for silver bullet type solutions? High-level languages, like at the time, for example, we heard Java and C++ are gonna solve every problem that you have in the universe. Object-oriented programming was the same exact thing. All your problems are gonna solve, just go OOP. Just, it's the solution to every problem that you have. Artificial intelligence is like this nowadays as well. Like, oh, just throw AI at the problem and you're just going to be an order of magnitude better. It reminded me of this quote of, if it's written in Python, it's machine learning. If you're pitching a deck to someone in PowerPoint, you probably call it AI. So AI is kind of this thing that has been called a silver bullet. It's going to replace all programmers tomorrow. Just let's all leave this room. JS is going to cease to exist. And he mentions just a ton more of these systems like expert systems. There was a thing called automatic programming at the time. In fact, this paper was written like decades ago. So I wouldn't be surprised if this returns like next year. Oh, automatic programming. Even graphical programming, he makes a very compelling argument against, he says, which I think in some ways is coming back as no-code today. He mentions, you know, software complexity is incredibly difficult to visualize. And actually, when you portray software complexity into a 2D representation, like a flowchart, you're actually doing a disservice to solving the problem. So this, I think this paper kind of, like I said, it explains a lot of what happens in the software engineering industry. And I think there is hope, actually. So it's not that silver bullets are entirely impossible. Toward the end of the paper, he proposes ideas of what, what could be the true things that solve essential difficulty. And actually, one of the things that he mentions is, for example, great collaboration and mentoring great software designers, which is a really nice thing. So for us, and we spend a lot of time at our company perfecting and creating developer tools, our quest is therefore to tackle essential complexity. And in the way to tackling essential complexity, we've had had to tackle a lot of accidental complexity in the way. So what this project that we created, Next.js, we saw this opportunity because there was a lot of accidental complexity in the space of React application creation, right? So in 2016, we saw this, okay, how can we get people started creating React applications really, really quickly and easily. So in 2016, we launched Next.js, which was, I think, looking back, one of the primordial innovations was that you didn't have to configure Webpack, which looking back again, it's a source of gigantic accidental complexity because every developer that was going to start a project was going to have to configure Webpack. And configure Babel and the whole spiel. So when we announced Next, we talked about a couple of things, right? So we said, we're very proud to introduce Next.js, which is a framework for server-rendered universal JavaScript web apps built on top of React, Webpack, and Babel. Because again, there was this notion that if you needed to start with React, you're basically doing this thing every time. You were connecting the webpack piece to the Babel piece to Gulp to Bash scripts to makefiles every single time. And I think we haven't really finished off the battle with accidental complexity. I think Node modules is one of the places where a lot of accidental complexity has been hiding recently. And I think we still need to make a lot of progress towards improving the actual things that deliver business value inside a React application, like data fetching or submitting a form and things like that. In fact, when you hear talks about performance, one of the issues even is that we ship too much JavaScript to the client. So some of the trends that I'm gonna talk about today, especially for example, static site generation, are all in this direction of even reducing the amount of JavaScript that's needed for certain tasks. So this was my contribution to that phenomenon. So if we look back on this introduction of the framework, like one of the things that we talked about was, oh, it's only for server-rendered applications. And at the time we had this view of the world that like that was going to be the thing. And this is the one tool that solves all of your problems. And funny enough, we talked about how we were dogfooding the product for building our own blog and website and dashboard. And actually, as time has passed, we've evolved from that thinking and implemented better and smarter and faster ways of delivering content. So when it comes to Next.js, we think that frameworks are never going to be silver bullets. But if we take a step back and we become a more hybrid approach to empower you to make the precise decisions on a per-situation and per-system basis, to tackle the essential complexity of the problem that you're solving, we think that we can approach this dramatic exponential improvement in software engineering quality and performance. So one of the things that we did really well with, with Next.js is that we took a step back and we said in order to get started with a Next.js project, you're using the file system as the primary API. And now this seems obvious in retrospect, but the file system is the very first API that you're always in front of. So you boot up VS Code and you have the file system API on your left-hand side. You boot up Finder, you go to the terminal, you're always interoperating first and foremost with the file system. So we said, okay, the only thing that you need to do is create a pages directory and then you introduce the entry points into your system. So index.js becomes the root path. So you export a React component inside that and you get this automatic routing. You could create a blog. And this is an interesting sort of evolution of your project because in a lot of cases, people were like, no, no, no, no, take a step back, create a new repository for your blog, ship it under a different subdomain and start separating the systems. So Next.js has actually brought a lot of coherence and union and a single sort of view of your application and your website into one place. And then we actually introduced this capacity for dynamic routing. So we took this file system as an API idea further. And we said, OK, you can define dynamic path segments. So we realized, OK, you know, most applications out there in the wild are going to receive some sort of special dynamic input. In the URL. So what do we get from this sort of file system investment? We got a zero configuration start. So you create your Next application, you only create a pages directory. The exploration of the program became dramatically easier and faster and better. So when you join a Next.js project, you kind of already have the map for the territory right in front of your eyes. And again, this seems like something that we take for granted, but I've seen so many projects where I have to navigate a Makefile that points to app.js, that points to server.js, that points to a list of routes, and I've lost the map for the underlying territory. It gave us, of course, automatic routing, which is a feature that, you know, PHP had since the early 1990s. Built-in code splitting so that each entry point would only ship the necessary code that the user is actually interested in. But I think one thing that's kind of interesting here is that in some ways we were fundamentally still solving accidental complexity because way back in the day, all of these ideas were already— like, these were problems that were already solved. I looked up this funny photo of how a developer would approach the problem 20 years ago. Boot up your FTP program. On your left-hand side, you have your local. On your right-hand side, you have your remote. And there is this, again, inherent map. Because if you're in that cgi/bin directory, you drop a file. And when a request comes in, boom. It, it just works. This was pretty close to the essential difficulty of the problem. In fact, it was very tightly rooted in C and the Unix API and so on. And it's actually funny that I found this on Google Images and they call this traffic magic. It was pretty magical. I think it was pretty easy and awesome. So, but the caveat that existed back then is that you only had two choices. You could serve a static HTML file or you kind of could define this like CGI bin kind of weird things. But these are very fundamental things that are at odds in terms of what benefits and performance profiles are giving you. So I wanted to quickly go over what are the advantages of each rendering paradigm at a very fundamental level. So when you're operating with a static system, something that is comprised of, you know, a bunch of HTML, CSS, or CSS files, or something that has a build process and generates those, you immediately get a set of very fundamental advantages. So one of them is very cheap scaling. You put it in a directory, you get all your traffic, you serve your files. Boom. You get high availability because if those files needed to talk to a server or something like this, every request hits a hot critical path. So if anything went wrong with your backend, you kind of like, you know, all bets are off. Therefore, because this is static, there's no computation that is required to serve you the file. It's a very simple, straightforward, pipelining of an asset that lives in a bucket somewhere to the end user. There is no Turing machine that is being fired up to serve that request. Something that's really interesting that I like to talk about is this idea of constant time, time to first byte. And obviously, it's not quite exactly constant time because it depends on the size of the input. The larger the file, it might take a little longer to stream. But the idea is that when you have a static file, the user, you know, will get it in a quite predictable time span, which is actually very difficult to do when you're executing a program instead. Some users, it might be fast, some users might be slow, garbage collection kicks in. You kind of go back to that Blackboard gigantic sort of scientific approach of looking at monitoring dashboards and stuff like that. You get this idea of all-or-nothing code rollouts. So your build process works. Boom. Like, all your static files go to production. Your build process doesn't work, production is not affected. So it's kind of this all or nothing, which we're going to talk about could have some downsides. And then very high throughput, like I said. So if it's easier to scale, you kind of can scale this to massive amounts of traffic very, very easily. Something that doesn't get spoken as much about is the security model. That when you're dealing with user-sensitive data, when you're dealing with regulations such as GDPR. It creates a very sane security model because the edge servers and the web servers serve your static assets, don't have any user identifiable privacy sensitive information. They're just giving you the same app every time. And like I said, the failures are contained at build time. So very little can go wrong in the production and deployment phase of this. But there are some also fundamental shortcomings. So the build process can get very lengthy. A small fix triggers an all massive invalidation. So the typical example here that I like to talk about is you fix one typo in one page and just usually all bets are off. And it typically scales well until a certain number of data points. So you can think of your system as having a set of data points, and that set has certain cardinality. So if you have an e-commerce website with 10 million items, producing all of those at build time can get quite tricky. SEO suffers when you delegate the computation to the client side because, again, going back to that high cardinality example, you're deferring all the kind of work to the client side, and SEO typically suffers by Google or Other search engines delaying the crawling of your pages. Performance suffering in a lot of cases because if I'm after the content, I could get the content in one shot or you can give me a bunch of JS that I need to load up just to get the content. And in a lot of cases, like this constrains static websites to just not being dynamic enough. So one naive approach to solving this problem is just, oh, just SSR all the things, just go all in on server rendering, which was kind of the strategy that we started with because we thought, okay, like lengthy build, no more. You just build it once and then kind of all your data is dynamic, comes from a database and whatever. Small changes, no problem. You know, you just SSR the new data upon request. Infinite scalability from 1 page to a billion pages. SEO is great. Performance is great. It's dynamic. It just seemed like it was that silver bullet that I was talking about. So silver bullet alert. But in reality, in practice, when you put such a system into production, you start facing a lot of fundamental shortcomings. You duplicate your business logic, which a lot of frameworks like ours do a good job at, just try to, like, do this isomorphism kind of thing. But in practice, it creates a lot of problems. Operations and maintenance overhead goes up because, like I said, you now go back to thinking a lot about the stability of a long-running system that executes code for every single request. That makes it very expensive. So typically you assign a fleet of servers that are always running that you have to carefully maintain and orchestrate and debug. In practice, we see that people get stuck to server rendering from one specific point. And that can be problematic because Russia is a gigantic country, right? So all your requests go to a single place that kind of becomes this bottleneck for failure as well. It's not ideal. When you run a Node process, for example, for a very long amount of time, at some point, I can guarantee you, you're going to run into all kinds of weird stability issues. From the typical DNS errors to memory leaks to CPU leaks to just weird things. And actually, to make it scale, we talk about that idea that for SSR, you run code for every single request, right? So like something's got to give. So my previous company got acquired by WordPress. When we came into WordPress, one of the fundamental scaling challenges that WordPress was facing was this error establishing database connection kind of pitfall. Why? Because by default, WordPress would SSR and every single user request would be directly connected to a database request. That meant that you had to scale your WordPress fleet as much as you had to scale your database capacity. It was nuts. So you have to start thinking a lot about caching in order to make SSR work. It increases the security surface massively because we talked about earlier, you just ship some static stuff to the client side and that's your security surface. Well, no. Now you're dealing with the security surface of your JavaScript running in the cloud. And you kind of have to duplicate everything. So this is something that is, I think, underestimated sometimes. But the critical thing here, for example, is exception logging. So when an exception happens on the client side, you need to report that, right? So you might use a service like Sentry to say, hey, there's an exception. Let's— if you've developed native apps, you've probably used Crashlytics or software systems like that. Now, if you also have a server counterpart, you now have to double that, which goes back to this duplicate business logic problem as well. So you're now duplicating everything— tracing, monitoring, exception reporting. Everything is doubled. The time to first byte that I said earlier was going to be constant for a static website is now unpredictable and unstable. And people tend to think of this now in terms of percentiles because they can't even wrap their head around the inherent essential complexity of what the JavaScript VM is doing for every single request. And failures tend to be all or nothing. So there is a theory of streaming systems that would prevent this problem, but in practice, when you're using SSR, it's an all-or-nothing type of failure. One data point that was required to produce a page yields a total 500 error page for, for the user. So what are the, what are the options for still maintaining that ability to serve static data without absorbing all these problems that I would argue most of these problems are pretty essential. So it's not that, you know, I listed stuff here like I had to configure Webpack. This is the reality of the responsibility that you acquire. So one of the solutions that has been proposed that we really like is this idea of Jamstack, which is basically you use a lot of JavaScript to do all your dynamic stuff. You query an API from the client side, and you ship some markup to the client. And what's interesting about this is that you retain the static model with all its simplicity and all its benefits, but you're deferring a lot of the dynamic computation to the client side, specifically everything around rendering. So in terms of advantages, well, we just acquired all the benefits of static, right? Beautiful. The error reporting surface becomes smaller, like I mentioned, or debugging, you know, in terms of, whoa, an error happened. The only thing they need to look at is the DevTools. Whereas when you're thinking about a dual system, you have the DevTools and then you have some remote log that someone in your team needs to give you. There's a great local dev story usually because you could even develop in the web browser, like with CodeSandbox. You can just like run all the code on the client. And it plugs into any backend. So the A is whatever system, even legacy systems, you already have. So the typical solution to then do a lot of dynamic stuff is to ship a shell or skeleton of your system. So when we were rethinking our dashboard, we said, okay, each page that we define in Next.js that becomes the entry point to all this dynamic data will have a shell that resembles the end user sort of outcome. So you boot up immediately to this static version of the page, which again happens really fast, and you get an immediate reaction in a predictable amount of time that is globally replicated. And then you kind of start loading all your data with— by using JavaScript and querying your APIs. And the interesting thing here is that it is possible, actually, to achieve great performance. So a lot of the systems tend to show you a big spinner, and they just wait and wait and wait. So kind of that has been traditionally the trade-off. But we've been exploring a lot of solutions, one that we published recently, for how to massively parallelize and preload using HTML link preload tags, actually. At the beginning of the HTML prelude, sort of the beginning, we can start loading the data even before the JS VM happens to boot up entirely and React and all that stuff. So I was sharing a video the other day of what our new system looks like in practice. And we can benefit from local caches, which make page transitions very, very fast. All the data is parallelized from my login state to the teams that I'm part of, to the projects, to the events, everything is parallelized. But we said, okay, the markup looked like this, right? So this is what the markup looks like. This is not quite acceptable for a broad range of products, right? So marketing pages, e-commerce, blogs, In those cases, we actually want the markup, the M, to contain the content. And I think this is a— we can't get rid of this essential complexity. I don't think it's okay to— you go to our blog and you see this stuff. Oh, wait, we just rolled out a new architecture. Wait, no, not gonna work. So what you actually want to see as a user is just give me the content, right? Like, just give me the pre-rendered content. So another interesting thing here is that as this sort of headless CMS industry and idea proliferates, we're now making all of our pages that were seemingly static get dynamic data. So our landing page under this hypothetical world that is really bad would look like this. Like, we don't have a tagline. We don't do anything. We're just— loading the content from our headless CMS, ship it, promote it. No. So we actually want the user to just go to our website and see this immediately, right? There's no other acceptable thing other than the markup already containing the data. So really the solution is a hybrid of these two things. You combine static site generation and you also load data on the client side. So a very interesting thing we did is for our dashboard to be able to render the login and signup buttons in a way that actually makes sense. So if you're in our dashboard, which is Zeit.co/Zeit, in this— for my team in this case, I'm seeing that I'm logged in. In the incognito session underneath, I'm showing that I'm logged out and I'm not going to have my login state. So Let's wait until it shows again. Yeah. So when I load this page, I also lazy load on the client side to see if I'm logged in or not. So this is the case for the hybrid approach. We pre-rendered some content and then we're dynamically loading some other content on the client side. Okay. So if this is so great, let's go back to what we mentioned were the drawbacks of static, right? What are the shortcomings? So we said lengthy build process, full rebuild for every change, doesn't scale well to lots and lots of data points, SEO can suffer, performance can suffer, and it's not dynamic. So with the initial solution, we solved that part. It's like, oh, load.js to sort of do the dynamic part. But we haven't solved this problem of what happens when I have a lot of dynamic content and I don't want to rebuild everything when one little data point changes. So we're introducing a new technology into Next.js that is already in a— under a flag in the Canary channel. And it hasn't really been publicly announced, but I'm gonna sort of share a sneak peek of it today. And it's what we call incremental static site generation. So let's go back to what a Next.js application looks like. You typically start with a bunch of pages in this directory. Directory, right? So you have index, blog, blog post, you might have, I know, an RSS feed, you might even have an API. So the output of these pages is what's changing for Next.js. And a lot of those optimizations are already in the stable branch of Next.js. So for example, going back to my landing page that has no dynamic data whatsoever, for the markup production. Why would I accept anything other than index.html as the output, right? It's fully static. So Next.js will do that when you don't include the getInitialProps hook. So for those that are not familiar with all the intricacies of Next.js, when you define a page, you can say these are the properties for my page that are needed to render the content. So if you just exclude include that today and then you run next build, you're gonna get just HTML. Very powerful stuff. The same is true actually for my blog index, but we're introducing now is this other hook called getStaticProps. So getStaticProps is the exact same thing as getInitialProps, but what it tells Next is that it needs to get data at build time for only that specific page. So the blog will, for example, retrieve the latest 20 blog posts or something like that. It will retrieve your categories, your tags, your authors, and things like that. The one that follows is the most interesting one because now we go into the big data set problem. So you can define, we mentioned earlier, this dynamic path segment. But what we're introducing that is super interesting is that we're giving you the ability to supply at build time what are the data points that you want to produce. So it's completely up to you. Going back to the idea of thinking about how many data points you have, if you have only 1,000 blog posts, maybe you'll tell get_static_path, let's just do everything. If you want to get more fancy, you might involve your Google Analytics in the future to say, oh, my most important 100 products that define the top-line revenue of the company need to absolutely be built at build time because they cannot afford to roll out broken stuff to prod. Or you might do nothing at all. So notice that in this case, the example that it produced is we produced 2 blog posts. But then what Next.js is gonna do is it's gonna produce a function. And for those that are not familiar with serverless as much, this is just a little bit of code that we can hand to platforms to recompute that page. So that recomputation will happen at any time. Could happen at runtime, could happen a million times, it could be ignored altogether, but the next build process will produce that. And then we actually can have the regular SSR stuff. There might be some use cases that you have where every single request, like you said, has to hit this kind of server every single time. So going back to, if you use getInitialProps, we'll just produce a function. And then we also introduced API pages, which is super cool. So we noticed that for the Jamstack to work, you need the A, and that's the API. So we think that Next can actually make inroads into the API problem space. So we introduced the API directory that as the name implies, will allow you to define just request handlers, basically. So the Y column, again, explains if I define any of these things, then the output will be all of those things. So I'm gonna do a little demo, and I hope that I have an internet connection here. And if not, I'm ready to— tether from my Russian LTE that I got at the airport. So this is very high risk. Right? So I'm gonna show you how our blog gets updated dynamically, even though it has been built statically at build time. And we don't have to rebuild the whole thing when a single data point changes. So let's see if the internet collaborates. Okay, very cool. So again, when you go to our— oh, we're looking at a mountain. There you go. Okay, so when you go to our blog, as I mentioned, like, we're not accepting the trade-off that we're going to render a shell to get dynamic data from our headless CMS, right? So when you refresh the page, it's loading instantly. From the nearest region that is closer to Russia, which is— let's see. I have a gigantic resolution here. So let's see where we're hitting this page. So like I said, one of the benefits we love about static pages is they will be distributed— and I apologize for my slow internet here. They will be distributed from the nearest location. So in this case, it's ARN, which I assume is Scandinavia. So what happens is my blog got built and it got globally distributed. But now what happens when you, for example, you shipped a blog post and you're very happy with it and it works really well? If the headless CMS backend goes down, if anything happens, you know that your blog is always fast and always online. But what happens to the underlying data, right? So like, what— how can I change that? So we love this product called Notion, where it's become sort of the brain for our organization, and we keep all the data about everything we do in this thing. So it acts— we sat around, it's like, okay, if we save every document about the company here, why don't we also save our blog? So I'm going to open it really quick. So we basically bootstrapped our blog off of this quote unquote headless CMS. And as you see here, we have this default production domain blog post and have my metadata here for the data that I'm working with. So the dream here was, and this is what WordPress used to do, is that if I edit my backend and I, if I have to fix something really quick, I can, for example, come here. Let me unlock the page. And let's say that I want to make this little paragraph bold. So here's what's going to happen. I'm going to refresh the page, and it's going to do absolutely nothing. And you might be like, wow, that's really terrible. Why is it doing absolutely nothing? The reason that it's doing absolutely nothing— and this is the killer feature— is that the reprocessing of this only page is happening in the backend. Asynchronously. So when my visitors are hitting the blog, they're never actually hitting any server. And yet when I went to it, I'm getting these benefits of like immediate loading. So the way that it's working is as traffic comes in, what's happening is I'm triggering a backend computation that recomputed only this page and produce a static output from it. That got globally distributed. So I'm now back to this page is in Scandinavia. And if Notion goes down, which it doesn't, it's a great product. But if Notion disappeared or someone pulls the plug of my backend, this page retains all its properties and all the benefits of static site generation. So what are the advantages of what we called ISSG or incremental static site generation? Static site generation is, well, obviously it's inheriting all the advantages of static site generation. It's highly available, tolerates backend downtime. It's always global. This is very interesting, right? We talked about SSR. Like you typically set up one box, one server in one place and boom, all bets are off. But not in this case. It's always fast. It's not just fast because there's a CDN. It's also fast because the data is in it, right? Going back to the idea of the skeleton, the data comes in the first hop of the download of that page. It scales infinitely because of the properties that we talked about. Like, if you put a static file in a web server, it tends to scale infinitely, and it's very, very cheap. It's very cheap for the maintenance, and it's very cheap for the scalability of it. So one thing we realized is that Once we have this technology, what's actually left, right? Like, it seems to me that you can actually solve every, quote unquote, every problem in the world with a combination of these two technologies, doing static site generation, ideally incrementally, and some client-side JS. So really what we're facing is that static really has become the new dynamic because that word static doesn't really portray or entail what actually is going on because we're all getting dynamic data at the end of the day, right? Like I just changed it. So a friend of mine, John, he's a designer and a few years ago noticed that every designer in the world was building one version of two landing pages. So there was like no creativity whatsoever. Everyone was building either the left-hand side or the right-hand side. So he was like, hey designers, which one of these two are you building? And obviously it went viral because everyone was like, yeah, guilty as charged. I have been designing the one on the right or the one on the left. So I'm gonna propose that when you go out and you start building your Next.js pages, you're gonna build one of these two. So you're gonna build the very, very dynamic that the M of Jamstack is just the markup of a shell. And we can get fancy later on with React Suspense. And some users, if your API is fast enough, might never see the shell actually because we suspend until we get the data. And on the right-hand side, we have all these pages that I mentioned earlier, like marketing and e-commerce and, and blog posts. Another way of looking at this is that you will use the left one when you're querying REST or GraphQL, like when you build your own REST backend or your own functional backend or your own whatever backend. And you're gonna use the one on the right-hand side when you use a headless CMS. Or if you wanna get more fancy in terms of distributed systems and databases, you're gonna use the left when the user needs to get a strong read. Meaning that it's not acceptable to give the user a cached version of the data. So an example of this is imagine that I cached at the edge all my customers' deployments HTML, and one day my edge gets breached and I go to jail. So no. So left is strongly consistent, and right, as I said earlier, the killer feature of the demo that we did was that it happened eventually. And that's actually a very interesting property that you should harness, going back to the essential complexity. Another way of looking at it is that on the left-hand side, you're gonna have things that are heavier on the user-personalized, privacy-sensitive, nuclear codes type page. And on the right-hand side, everything where, you know, it's just publicly cacheable. Another way of looking at it is that on the left-hand side, we're making an explicit trade-off of latency. And actually, if you really peel off the layers of this problem, you'll find that typically in order to make systems that scale really well for strongly consistent data, the expectation is that they might take longer, and that's totally okay. So on the left-hand side, it might be okay that it takes a little bit longer On the right-hand side, no. Amazon has shown that if I render a skeleton to render your e-commerce product, no one's gonna buy it or they're just gonna leave, you're gonna fall out of the funnel. So what I'm happy to report is that now having thoroughly solved the accidental complexity of Webpack, we're on to much more interesting problems. And the problems that we're solving are exposing this essential complexity to the developer And they're, they're giving you this tool to make the best decision for each page that you're building. As I mentioned, incremental static site generation, specifically the getStaticData and getStaticPaths hooks are coming very soon. We're working on an RFC that we're going to share with the community. As always, we like to dogfood our solutions. So we have been using it ourselves, but it will soon arrive to more digestible, better explained form. So it's again coming to the Next.js Canary and to stay tuned, just follow us on Twitter. We'll make this public, especially because we'd love to hear all your comments. As I said, we're building all this technology into the Next.js sort of Canary branch, but we hope to merge it into master once the RFC process completes. And you can start actually developing and deploying any website, whether it's built with Next.js, Gatsby, Hugo, Vue, whatever your choice of frontend technology is. We're hoping that you'll give us a try. Thank you so much. Yeah, I'll repeat whatever you say. We have 6 minutes for questions. 6 minutes and 52.
Just 5.
Just 5.
Would you like to join me for a little conversation?
Sure.
I'm so excited, you have no idea. So because, you know, we've been running on Jamstack, the Smashing Magazine is running on Jamstack, and we've been looking and trying to figure out the way of incremental builds. Yeah, one of the things that we have as an issue is deployment takes 6 minutes, 6 and a half at this point. And you know, you change a comma somewhere. Yeah. Ah, so I'm so excited, you have no idea. Instant. Yeah, I'm so, so excited. Um, a couple of questions that came up, and I'm going to prioritize the one that came from the audience first, is, uh, there is a question from Ilya about Next.js specifically. Why is the folder name for assembly resources not configurable and as hardcoded as _next in the Next.js source code?
So that's a good question. I, I think we tend to look at Next.js as a very conventional framework, so we prioritize convention over configuration. So in a lot of cases, we've been quite conscious about not offering customizability beyond what's reasonable. I think eventually we will add every single knob, but in the prioritization of the framework, I think removing conventions has never been a high priority. For example, like, people would always ask to rename the pages directory.
Right.
And we can do it, and I think it's now possible, if I remember correctly. But it was never a priority because we always saw the strength in the framework as having conventions that are very useful. And again, the exploration angle of the framework is really important because you want to open a project and now you find that everything's been renamed and you've lost the map for the territory.
Mm-hmm. Vlad is wondering, how does getStaticProps work with pagination? Does it render only the first page?
It's up to you. So you can do pagination. You could actually compute every page if you wanted. I think for pagination specifically, depending on the crawlability needs that the website might have, for a lot of people they might do lazy loading on the client for things like that, right?
It's also been interesting to see this all of a sudden, this rise of headless CMS. Yes, any CMS you take, it will be headless, and WordPress went headless as well. So the question that came from Eugenie is, so what headless CMS do you use for, for your blog, and which ones would you recommend?
So the beautiful thing about this hook that we're introducing is that you can literally make any API call that Node.js can make at build time or even later on at runtime. So it doesn't, it doesn't really affect you in any meaningful way. You can use whatever headless CMS that you like or even APIs that are not yet considered headless CMSs. So for example, for my next blog, I figured that I'm gonna compute a lot of my tweet storms as my blog posts because I've basically been blogging from Twitter. So I wanna generate static versions of my tweet storms that look like blog posts. So what I'm gonna do is I'm gonna use getStaticPaths and getStaticProps to just query the Twitter API. So we love a bunch of headless CMS solutions. Contentful, Datto CMS is super, super interesting. I think if you're looking for something that's really lightweight, Datto CMS is super interesting. It's based out of here in Europe. Prismic is really amazing. We have customers that have millions of data points to store with Prismic and use Next.js.
Yeah. So what do you think? So we've been been kind of spending quite a bit of time over the last few years discussing Jamstack and trying to move away from LAMP stack. And where do you see this happening? Do you think that Jamstack seems to be becoming more like a standard approach for building websites these days? I think so.
I absolutely think so. I think Jamstack will become the default. But I think what was necessary was to bridge this gap, right? Because I think the example that I gave with, like, it's not okay to just fetch all the data on the client side, right? Like, you're just gonna lose a lot of customers. You're gonna lose a lot of money for your critical pages, for serving ads or for selling products. So I think a lot— the reason I think we are not seeing that every single thing that gets put out today is Jamstack is that not everyone has been able to retain those business metrics. But with technologies like this, we're hoping that we're gonna capture 99.99. In fact, from our perspective, there is really not a use case that we ourselves have that is not covered by it.
Okay, well, it's also— it's been very interesting to see that more and more frameworks and more and more browsers actually kind of going to all these fine little details where the browser is kind of exposing internal APIs, like, to a level that you can adjust everything. Houdini uses Houdini.
Totally.
And then you also end up with frameworks going kind of really in small, small details where we discuss things like, um, progressive rehydration for components.
I think progressive hydration is a great example of a feature that if we don't have it for a lot of people, Jamstack might not work. Because if you're booting up JS and that's taking you seconds due to the sheer amount of code that you're giving the client, then it's just not going to work for you. But we're working very closely with both Google and the React team on bringing progressive hydration and dynamic code loading so that you only need the code to load that is critical for the interactions that you're going to make. So once we have progressive incremental hydration on the client side, plus smarter bundling so that you're only loading as little JS as possible, then I think that truly universalizes React. Yeah, uh, as, as a technology that just works for all use cases.
Yeah, because we've been kind of putting so much time and effort into building applications with React and Angular and all, and in the end we ended up with so much JavaScript. And right now it seems like there is a turning point. It doesn't matter who you're talking to, the teams, everybody's invested in some way into this notion of breaking things down, looking into smaller, like loading smaller chunks, you know, webpack, code splitting and all of that. So it seems like the world is changing.
Yeah, absolutely.
So in this wonderful world of ours, what are you most excited about in the JavaScript world?
So obviously I'm biased, but I'm excited about Next.js. I am excited about seeing the proliferation of new frameworks that are taking radically different optimization approaches, like Svelte. Mm-hmm. I'm a big fan of this idea of worse is better, that by removing some of the power or moving it around, you get tremendous optimization speedups and benefits. So I think when a framework gives you a templating language as a primitive, you get a lot. I think we're going to see a lot of benefits not only in performance, but I think we're going to see the benefits is also in ergonomics. So suspense and data loading with React, it still requires a lot of code and wrapping with components, and I really don't think that that's the best way to code UIs. I think solutions that use templating will see a much easier way of fetching data and suspending and managing your spinners. And conversely, I think we're going to see the proliferation of tooling for designing React apps or Svelte with GUI. So basically what Dan Abramov has been tweeting about, like the idea of like Visual Basic type programming, so that you kind of— because you kind of need to see your UI and decide what things are going to suspend for how long. So it's almost like the job of the developer becomes like kind of like a designer that's selecting and saying, oh, this stuff suspended, the tolerance is 1 second, then you get some feedback, some data, and say, oh no, this, like, we're going to change it here, we're going to do parallel loading of these 2 things.
Yeah. Oh, so that's exciting, that's exciting. I think everybody is excited to leave because many people left already. So with this in mind, thank you so much for all your wonderful insights.
Thank you.
And so please give a warm hand to Guillermo Rauch. Well done, sir.
More from Guillermo

Guillermo Rauch at Founders in Arms Live: Simplicity, Focus, and the Bet That Built Vercel

The Man Who Built a $9B Dev Platform Thinks You're Overcomplicating AI | Guillermo Rauch

Inside v0: How Guillermo Rauch Is Building 100 Million Engineers | Lenny's Podcast - EP.89

Architecting for model step-changes: A fireside with Vercel's Guillermo Rauch

Keynote Interview: Vercel's Guillermo Rauch on the Agent Era | Azure Cosmos DB Conf 2026

Vercel CEO: 70% of Our Traffic Is Now AI Agents "Nobody Was Prepared" | Anthropic, OpenClaw, OpenAI

Why being "terminally online" is more important than ever, with Vercel CEO Guillermo Rauch

Argentina Week 2026 | Argentine Talent Powering Global AI | Guillermo Rauch & Hernán Kazah


