ReactiveConf 2016 - Guillermo Rauch: What's Next? Exploring the future of React

In this ReactiveConf 2016 talk, Guillermo Rauch, CEO and co‑founder of Zeit, presents Next.js – a framework for universal (isomorphic) JavaScript applications built on React. He begins by describing the "Now" deployment service and then walks through the core developer experience of Next.js: a file‑system‑based routing API, the `next` command for development, hot code reloading, server‑side rendering, and the `getInitialProps` lifecycle method that lets pages fetch data both on the server and the client. Rauch outlines the seven principles that guided the framework’s design, emphasizing why server‑side rendering is essential for performance, SEO, and user‑specific rendering. He explains how Next.js bridges the gap between traditional websites and full‑blown web apps by aggressively prefetching links, code‑splitting per page, and providing a `Link` component for client‑side transitions. The talk also covers the framework’s handling of CSS‑in‑JS, head/meta management, and the rationale for keeping the runtime lightweight. Rauch then shares the roadmap: custom server handlers, eliminating the need to import React for JSX, support for fragments, class syntax shortcuts, a possible move toward Web Components/shadow‑DOM for styling, and making the rendering layer pluggable for non‑React renderers. He addresses large‑scale project concerns—custom routing, integration with Express or micro‑services, build‑time optimizations, and modular component repositories. The session ends with a brief Q&A covering differences with Create‑React‑App, using Reason, handling mismatched server/client DOM, and other practical concerns. Throughout, Rauch’s tone is technical yet enthusiastic, positioning Next.js as a pragmatic, performance‑first evolution of the React ecosystem.
Chapters
I was just mentioning I'm like a just-in-time compiler in that I usually show up right before my presentation, and today Uber miscalculated, so I'm sorry, Uber. So the talk is called What's Next for React, and it was sort of meant to be a pun because when I sent the presentation title, This project, Next, that I'm going to be talking about today wasn't public yet. It's been made public in the last 48 hours, so I'll be talking a lot about it today. Before I go on, I'll tell you a little bit about me. My name is Guillermo Rauch. I'm on pretty much every social media website that I could get my username on as RauchG. I'm the CEO and co-founder of a company called Zeit, and I blog at rauchg.com. I don't blog often, but when I do, it's very long essays. So brace yourselves, and I'm going to be talking about two of those today. We're known for this product called Now. You're going to be seeing this sort of scheme during my presentation. Now is a service that takes in your source code and uploads it to the cloud, deploys it, and scales it seamlessly. Your project could have a Dockerfile, package.json, or maybe it's just a bunch of HTML files. You execute this one command, now. We give you a new URL for each deployment. This is why we call it immutable deployment. And if you want to learn more about it, just go to now.sh. And this is important because this approach of just doing something with one command or expressing your workflows in this way is very critical, and it also explains a lot about this project, Next.js. Next.js is a framework for universal JavaScript web applications. Because I'm a big believer in GDD, coined by me as far as I know, GIF-driven development, I'll show you a quick GIF of how Next.js works. You start with a package.json file, you include the Next dependency, and you just run next. You go to your URL, and you start populating your application directly in the file system. So here I'm going to define the index route inside the pages directory, and all it does is JavaScript functions and components. So in this case, I'm going to return some JSX, and hot code reloading and server-side rendering and all of that is configured on your behalf. So by the time I save it, it hot code reloads. Notice that here I'm using this Link component that I'm gonna be talking about later. I made a client-side route transition to the About page. And here I sort of show off the counterpart to the stateless function component, which is defining a class that gets some data before it's rendered through this method called getInitialProps. And then we just return some JSX. And by the time I save it, this particular example shows off the capability of fetching data isomorphically. So by inspecting that request parameter in getInitialProps, I can determine if I'm in the server context or in the client context. And notice that when I server render, it's gonna say server. When I make client transitions, it's gonna say client. So that's a very, a very simple approach. To recap, We take advantage of the file system as an API, so all you do is create a pages directory and inside you declare your components. You can override this as well, and I'll talk about that later on, but this is basically all it takes to start your universal JavaScript application. There are some principles about Next.js that are worth mentioning. So easy start, obviously, you just run next. That's why I said, you know, To deploy, you just run now. To create your application, you just run next. It's small and minimalistic. Every single feature we've included has been very purposefully included, and we're very mindful about the bundle size. Because we're big believers in this idea of server rendering as a way of getting the content out to the user really quickly, we are very mindful about our runtime size as well. So out of the box, we do universal and isomorphic rendering. Hot code reloading. So we use Webpack and Babel underneath, which you'll be able to expose and configure on your behalf as well. We do lazy loading and code splitting. Basically, instead of generating a big bundle for your entire application, each top-level component creates its own bundle that gets dynamically or loaded with a server render. And then the approach to deploy this, to take it to production, is You just run next build and then next start. So there is basically— there's a very simple workflow for the development side of things, which enables hot code reloading and some other features, and the production-ready workflow, which involves producing and compressing bundles and generating basically a cache of the routes that your application exposes and so on. So before I go into how we came up with this set of constraints and designs, I'm gonna talk about what inspired us. So in 2014, I wrote this essay called The Seven Principles of Rich Web Applications. And in the end, I mentioned that if you followed the seven principles, you would have built a unicorn. So you can think of Nuxt as our approach to taking your source code and outputting a unicorn. And this is basically what it does. So the first principle, and I think the most important one here, is that server rendering is not optional when you're designing an application. The TL;DR of that is perhaps it's not as common to think that today, but at the time, a lot of people thought that server rendering had exclusively to do with, for example, Google's ability to access your content. A lot of crawlers have since improved and they can dynamically execute JavaScript and so on, But the principle that if I can, from the server, perform a lot of optimizations and output HTML, I'm much more likely to have greater performance than not. And in addition, there are several features that are critical for web applications, like including and responding with certain meta headers for social media websites and so on. So there are a lot of advantages to thinking about server rendering. And I'm gonna mention 3 in particular. So the first one is, um, this lifecycle of the interaction between the user and the server starts with a URL. For example, you go to a page called /user and you pass it an ID. Therefore, the server already knows what the user is interested in, so the server can perform a lot of optimizations to, for example, prefetch that data and respond it directly. Number 2, the server already knows the capability of the user. So for example, if I go to github.com, there are two different representations for that page, whether you're logged in or logged out. So with server rendering, we have the ability to return a layout that matches that user's capability. In this case, you know, you would render a login form, or you would render the admin panel of your application. Finally, because the server can return an HTML and CSS stream, We can take advantage of the fact that the browser can render progressively. If you're just building a single-page application, now the server has to download all the JavaScript code. Perhaps you've made some network-level optimizations to push data, but still you have to preprocess, interpret, run everything, and then pass some DOM to the browser so that the user sees the data that they're interested in. So because of these three reasons, we think that this type of ideal web application necessitates server rendering. The rest of the principles have to do with, okay, if server rendering is so critical, do we actually need client-side JavaScript at all? And this is a very nuanced theme, I think, because for a lot of applications, arguably, you don't need any client-side JavaScript. For example, pretty much everyone here, for example, uses Hacker News. I think Hacker News probably has some lines of JavaScript for toggling comments, and I would guess that that's pretty much it. And it's at the center of this industry, yet it's never used any client-side JavaScript. So with Next.js, we've made it so that you can also build that sort of application. You don't really need to execute our runtime at all. So we have this flexibility to decide how much you render on the server, how much you render on the client, and so on. We do think that for a— big space of applications, client-side JavaScript is critical. For example, features pertaining to offline access or getting instant feedback after you perform a certain action without having to wait on the network. In reality, this is sort of a function of the quality of our connectivity, right? Because if the server is so close to the user, as it ideally should be, maybe we don't really need that much client-side JavaScript. This 6th principle had to do with thinking about code the same way we think about data. So it's pretty obvious to anyone today that ideally the data that's rendered on the screen updates in real time. If something changes on the backend, or the dataset that the user is rendering changes, it's pretty much well accepted today that we need to show those changes to the user immediately. We think that that should be also the case for code. And there are a lot of similarities between creating a model for an application that is able to update code and update data in real time. And finally, and this is perhaps the most important notion today, is that the key to great performance is anticipation, uh, or prediction. So, um, this goes both for data— like I said, we can anticipate what data the user is going to be interested in based on the URL— but it also might have to do with UI. For example, We may need to prefetch a certain part of the screen based on the trajectory of the input, and so on. So the big question that remained in our minds to complete this vision was, how do we resume the rendering of some content, some DOM that's been rendered on the server? This was a pretty tricky thing to do. And that's where React came in and, for us, solved this problem in a very, very elegant way. By introducing a new model for how to reason about the separation between data and UI. I wrote this subsequent essay, Pure UI, that went into this idea that we're thinking about our UI as a pure function of data. And this is one of the two things that is critical to make this work. We have to have a render function that doesn't know or doesn't fetch the data directly. It's just accessing some state or some props. Perhaps the props, like I mentioned earlier, come from the server, perhaps they come from the client. And secondly, and this is the other critical ingredient to this, is that you need to be able to take control of the lifecycle. In other words, we have to think of rendering from the server and then picking it up on the client as a continuation. This is why it's so critical that in React, for example, componentDidMount only actually fires if the component has been mounted onto the screen. So we can add a lot of code that's client-specific. And an example of that would be that we start with a static snapshot of data, and upon componentDidMount, we subscribe to real-time updates to that data, or perhaps we have to invalidate it altogether. This is why top-level, top-down rendering is so important, because we have to consider that when you server render something and then you pick it up on the client, it's almost like you've gone offline And then there's an uncertainty about the state of the data that the user subscribed to is in by the time he or she reconnects. So the other critical thing that was missing was determining how do we slice that lifecycle? How do we determine that something is ready to be server rendering? And this is an asynchronous process. So we spent a lot of time in this state. Thinking about this problem. And what we came up with was the counterpart to a function that was already exposed, or method that was already exposed in React whenever you were using React.createClass, which was getInitialState. We thought about adding the counterpart of this as a static method to classes, which is getInitialProps. So with this, we can statically analyze classes that are exposed as top-level components, and decide, okay, I need to wait on this function to complete before I proceed to server render. So this has numerous advantages also for the client side, but it's also very easy. It's very easy and very clear how and what's happening here is by the time Next goes and fetches your component, this function resolves to a JavaScript object. That's another critical thing because you can plug in any sort of data adapter here including client-side stateful adapters, which I'll get into in a minute. By analyzing those parameters that come to getInitialProps, you're able to basically get the data from wherever you want. So another question that I posed in that essay was, what is the strict technical difference between a website and a web app? And I think this question is something that In our minds, we refer to a lot. We say, oh, this is a web app type thing, or this is a website type thing, but we thus far haven't technically delineated which is which. So I have a contribution to that question, which I think there are two key things that make something an app as opposed to a site, or at least that I observe in our usage of that. One is global state. An app that is strictly server-rendered, it's impossible to keep some state on the client side in JavaScript and, for example, make a really quick transition to another page based on a cache. So I think that in order to make really great UIs, you have to have the ability to respond optimistically to user input and keep some data cached on the client side. So this is something that makes for a web app type feel as opposed to the traditional Web 1.0 website type feel. And it's also critical for features that you might be interested in like offline support, optimistic feedback based on user input. The other really important notion is ahead-of-time code loading. And that's why I was saying that our idea of fetching data before the user requires it is also true for fetching code before the user needs it. And it's also, of course, very important if you want to create a very good offline experience because it allows you to navigate your app or website while the— for example, while the user is offline or while network problems are occurring. So to give you an example of the extreme of the app side of things, when you download the Facebook iOS app, for example, you're downloading a 200-megabyte code bundle that pretty much has every possible interaction that you would ever perform with the app preloaded. They have some webviews, but in reality they're going on this extreme side of things where the app is bound to perform really well even when the network is down because you've loaded all the code in advance. Someone did a symbol dump of their application and basically you can read all the class names, and I think that person concluded there were like 18,000 classes or so. And for those that are curious, if you sort this, the longest class name is ProfileSetEventsCalendarSubscriptionStatusMutationOptimisticallyPayloadFactoryProtocolProtocol. So this is great, I think, because if you can afford to make that initial investment in that you downloaded everything in advance, then by the time you need to set events in the calendar with subscriptions with status mutation optimistically with payload factory protocol protocol, The user experience is going to be great. So our take on this is that we can converge those two models. This is why we have this Link component built in. So Link is what I show also in the GIF. It allows you to create client-side transitions between routes. And of course, this is optional as well. And what we do is— so the reason we need this, of course, the reason we need client-side transitions is because If we want to honor a global client-side cache, we can't afford to perform full page refreshes every time. Secondly, and the most important thing, and this is what allows us to converge the app and web model, is we prefetch links aggressively. I'm going to show you an example from our website. Every time you click something on our website, everything is immediate. And the reason it's immediate is not because we downloaded a really big app.js bundle. It's because when you first load, we server render according to what the user needs. This one is an interesting page to server render because you can see that CodeMirror, which is the editor that we use for the API example, doesn't— it's not an isomorphic component. So this is something that you could see there in action that we're loading a ton of JavaScript that is code-split for this page. And it only happened on the client, but I was already able to consume the documentation. And while this is happening, a service worker in the background is fetching all the links that the user could be interested in in the future because they are part of this rendering iteration. So by the time I go to the blog about Next.js, it's already likely to be preloaded. So that's how we sort of converge those ideas. It's almost like— By prefetching aggressively, we're doing the— and analyzing, obviously, the things that are interesting to prefetch, not just prefetch everything. We're able to get that best of both worlds experience where the initial download works like the Web 1.0, but then we have an app-style download the entire world approach once the page is loaded. And this is really interesting because it's better than an app because you're only downloading the subset of the world that the user could be interested in by analyzing that tree of components. And code splitting is what prevents that very big initial penalty that a lot of applications incur in. So this one is an example of CodeMirror, but we use D3 in other parts of the website for showing you statistics about deployments. And these are very expensive things. And when it comes down to scalability of your codebase and your teams, this is critical because when someone is working on a slice of the application, they're not introducing global effects that slow down the performance of other parts of the website. And finally, there are two things that are critical for server rendering that we had to handle specially. One was CSS and one was introducing effects into the header. So everything is a component, but in a lot of cases, we have to break out of the component, basically, sandbox. So the most common thing for this type of application is introducing, for example, the meta tag for mobile readiness, or changing the title from page to page. So we bundle this very handy and small component for introducing effects on the head of the page. And also this is important because when we server render, we have to take a slightly different path for obtaining this and rendering than when you were making client-side transitions. And the other one is CSS. So there's been a lot of debate about CSS in JS versus pure CSS. And the reason that we, again, picked a side in this question, so to speak, is because we can make a lot of optimizations for the server rendering pipeline and it offers really great performance for us. Because as you're making transitions between client-side pages, we want to be able to detach styles that are not interested— interesting anymore. And in addition, we found that CSS in JS composes a lot better than plain CSS style sheets. We actually, for Zeit, started with using preprocessed CSS that, in order to isolate We would basically mangle all the class names, and it didn't scale very well for us. In particular, build time was increasing a lot, memory usage was increasing a lot, just to transform and parse all this really huge amounts of CSS. Something that we've observed empirically is that your CSS tends to grow a lot more easily and faster than your JS. So this is why we expose this CSS-in-JS approach, but later on I'll talk about what our long-term vision for CSS is. Those are the 5 things I want to mention about what's next for Next— pun intended. So the first one is, while we think that analyzing the file system provides a really great way to get started, in a lot of cases you do have to go in and, for example, define fancy custom routing schemes, or interrupt and short-circuit a type of request, or introduce global checks for your requests. So that's why we're introducing a way of supplying a handler for the request and response lifecycle. So you can sort of say, for example, if the request comes for the route A, you can render component B, as opposed to letting Next decide based on the shape of the file system. Number 2, you might have noticed that in a lot of cases, we have to import React from React every time we use JSX. Because the compilation results in React.createElement, but in reality, you're not seeing React being used anywhere, so it's not only confusing but not very agnostic and not very general. So we would like to see in the future— and for each of these things that I mentioned here, we have issues where I would love to get input from the community— we would love to see a situation where you don't even have to expose, you don't even have to import React, you can just return your JSX directly. Directly. There are a few things that we can also get from React in the future that are going to make this code even smaller, so as you can see, I crossed out the first line. So once we get fragments, we no longer need to do top-level wrapping, so it's going to be even more expressive in that you just return the— in this case, the head and the paragraph. Then, I don't know, this probably has come up, I would like to write class directly, not name. In the future, that would be— also, we would be shortening this even further. So I think the CSS-in-JS versus pure CSS debate is tricky, and I think there are benefits to both sides. We personally have found that CSS-in-JS fits our workflow a lot better. It gives us a higher level of correctness because we're able to type our CSS, basically. Collocate our CSS and markup better, which gives us an idea of if the components are very well separated or not, or if we're having tons of unneeded CSS. It allows us to not fall into the problem of having style.css and having dramatic amounts of CSS, among other problems. But I do think that we have to be able to reconcile and allow for— your CSS to work well within this model. And the most important thing for CSS to work well within this model is that the CSS that you define within a component only impacts that component. So perhaps by using the Web Components custom elements/shadow DOM APIs, we would be able to get rid of the CSS in JS, at least for the initial presentation of the framework. And we would be able to just include regular CSS. And in this case, obviously, that paragraph style would only apply to that very paragraph. And it would look a lot shorter and nicer as well. So that would be the end result of this evolution. Finally, we are looking into making rendering pluggable. So for example, if you don't want to use React and if you want to try something else, all you would have to do is add a really thin layer on top of this that registers some hooks for rendering. Since the users and API, the contract is very simple, it's just stateless components as functions or classes with a render method, we think that there's an opportunity here for a lot of different renderers to exist. I already said that. And finally, so the approach that we've taken with Babel is We're transpiling as much as V8 supports. So we support async functions because they just landed in V8. We don't support class decorators because they're not in V8 yet. So this kind of takes away a lot of JS fatigue for us because we're sort of targeting a very interesting subset. We use Node 6, which has a very— Node is doing a really great job at keeping track of the latest versions of V8. And we normally develop on Chrome, which would completely eliminate the transpilation step, at least for development. And then you only pay that penalty upon next build to be able to be backwards compatible. But we still think that there are very legitimate cases for plugging in custom stuff. Like you might want to use decorators so you can add it as a Babel config step. So the two URLs to learn more about the project is you can go to our blog/next or you can go to github.com/zeit/nextjs. And finally, I want to make it really clear that when it comes to frameworks, we don't think there are silver bullets. And I tweeted this a few weeks ago because I got excited about the progress that a lot of frameworks are making in this territory like Vue.js and Ember with Fastboot. There are a lot of interesting approaches solving this problem, and with Now we want to support them all, and we think that the user experience of the entire web is going to become better as a result. But also, there's a lot of really interesting feedback to give back to the web platform as well. Like, for example, can we server-render Shadow DOM elements and a few other interesting things that this opens up. So that's it for today, and thank you. Awesome. Thank you very much. I'm changing sides. Where— can we have the questions, please, on Slido? Fantastic. 55 likes. Let's go for that one. So the future of React, of course, is very well defined in the roadmap. The part of the future of React that we are interested in is what is the API surface that can sort of become universal and that can enable these really cool principles. And I think part of the spirit of Next.js is trying to reduce a lot of the boilerplate involved in setting up React, for example. And something I cover in the FAQ as well is what is the difference between create-react-app and this. And the bottom line is that depending on what your target application is and what do you want to use React specifically for, you're going to go lower level to something like create-react-app or you're going to use something like this. So the next question: this looks good for a quick start, but what is your approach to accommodating large-scale projects, tweaking requirements? By tweaking, I don't know specifically what you refer to. We found a lot of edge cases that had to do, for example, with libraries not being isomorphic ready. We actually find a lot of edge cases with our application where build times were too long, so we had to make a lot of optimizations for that. So when you start going into the large-scale application territory, some interesting problems come up. Part of that is why we're not transpiling CSS. We found that it was bringing down our performance a lot. Part of that is why we are looking into app mounting, where you can take a path within your application and refer to a smaller application that lives in a different server so that we can scale and separate them independently. And another approach, for example, when it comes down to tweaking is— so one of them is the first thing I mentioned on our roadmap, which is You want to be able to take over the HTTP server completely. So that's certainly within our interest to support. Another thing is sometimes you need custom-built pipelines, but in general, I don't think the best approach for doing that is to have this gigantic webpack config that takes care of every edge case. What we've done for those situations is we break down the component that we want to tweak into a different repository, and the contract is very simple: as long as it exposes a React component or stateless React function, we can import it within this framework. So in reality, it's worked really well for all our needs. 34 more questions, 2 minutes to go. So let's go through the rest of them. I'll speak really quickly. So I already answered the create-react-app and Express. You can certainly use Express, for example, when you take over the server and if you want to define a lot of custom routing. We didn't think that bundling Express made sense because the only thing we really need is the HTTP server. As I said earlier, one of our goals is to make this as minimalistic as possible. Not everyone needs to do routing, not everyone needs to handle POST requests. An example of that is we use microservice architecture. So we don't even handle any POST methods on our Next server. Next is basically a server that is 100% in charge of rendering. Everything else is deferred to other services within our architecture. So the goal is for Next.js to actually do less and less and less, and Express sort of brings that up a little bit, but it's something that you can incorporate if you want to take over the server and you want to pass an Express function to the http.createServer call. It's certainly up to you. Can you use Next.js with Reason.js? So I think this is an interesting pattern. It would be very interesting— someone asked, can I use Reason on the frontend? I think this is a very interesting pattern where it's interesting to explore alternatives because some of the processes that we run on the backend are actually pretty expensive and pretty slow. So executing React on the backend is not as fast as we would like it to be, for example. So some limitations have to do with JavaScript. Some limitations have to do with the frameworks themselves. For example, we are incorporating streaming of HTML whenever it becomes available, but it's certainly interesting to take this surface area and try to implement it in other languages. And another great thing is Reason supports, I think, as of recently, JSX directly, so it would be really interesting to also not have to deal with that transformation step. Yeah. Let's do the last question. Yeah. So DOM differences, like I mentioned, I gave an example with CodeMirror. So the server is rendering something that didn't have that editor rendered on the page. So we do that very easily because on the getInitialProps, we say editor false or something like this, and that's all it takes. In this case, we did it because of a few things. First of all, Loading the entire CodeMirror codebase on the server side is quite expensive. Secondly, the interaction or the things that we can server render from the editor, we would like to have a static representation of it. So this is the beauty of Next in that you can have a completely different DOM between server and client. When client resumes and componentDidMount fires, you can load arbitrary— you could even do jQuery stuff. If you so desired, and React does give you a warning when the DOM doesn't match, which is very useful in certain cases because you're doing something that you shouldn't be doing, but in a lot of cases, you do want the DOM to not match. So an example where that doesn't make a lot of sense for us is the date, because we configure the date according to a cookie that tells us where you're from or what your timezone offset is. We don't know this ahead of time, so it's hard for us to say if it happened 2 hours ago relative to GMT or if it happened 8 hours ago. This is an example where we do want the DOM in certain cases to not match just because we can't make it match because we don't know what time it is where you're from. That's an example of DOM reconciliation that we run into. We're out of time. Okay. Thank you so much, Guillermo. I appreciate it.
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


