If you think that static rendering is limited to generic and public content that is the same for every user of your website, this talk is for you. Segmented Rendering is a new pattern for the Jamstack that lets you personalize content, statically, without any sort of client-side rendering or per-request Server-Side Rendering. Get the best possible performances for use cases such as theming, internationalization, A/B testing, multi-tenancy, and start treating your users right!
Treat your users right with Segmented Rendering
AI Generated Video Summary
The Talk discusses the concept of segmented rendering for personalization in web development. It explores different rendering techniques, including server-side rendering, static seed generation, and dynamic rendering. The issue of rich guests and poor customers is addressed through segmented rendering. The implementation of segmented rendering with Next.js involves a lightweight proxy server and URL rewriting. The Talk also highlights the benefits of invisible server-side rendering and suggests a future unified API for server rendering.
Hello everybody and welcome to my talk, Treat your users right with segmented rendering. My name is Eric Burel. I'm the founder of LBKE, a small company in Montpellier, France. I'm a web developer but I'm also a consultant in public funding for research to business. I'm the maintainer of VulcanJS, a framework you might know if you come from the Meteor.js ecosystem and that is now running on Next.js and GraphQL.
Hello everybody and welcome to my talk, Treat your users right with segmented rendering.
First, let me introduce myself. My name is Eric Burel. I'm the founder of LBKE, a small company in Montpellier, France. I'm a web developer but I'm also a consultant in public funding for research to business. I'm the maintainer of VulcanJS, a framework you might know if you come from the Meteor.js ecosystem and that is now running on Next.js and GraphQL. I'm a member of the DevoGraphics Collective created by Sacha Gref who runs the State of GS, CSS and GraphQL surveys. I'm in particular in charge of the survey form where you actually fill the survey and I am teaching Next.js at Human Coders, a teaching company in France. You can meet me on Twitter or on Medium where I publish a few articles on various subjects, namely Next.js and GraphQL.
2. Personalization and Rendering
I'm going to talk about personalization and explain what is the segment in segmented rendering. Web personalization includes examples like theming, internationalization, paid versus free content, and A-B testing. Next.js is a framework that offers three ways of rendering applications, including client-side rendering.
Okay and depending on the value of course I pick a different theme in the application. But it's not the sole use case. There are many use cases of web personalization. We have this same in use case but also internationalization. It's a case of personalization that we we sometimes forget but when we change the language of an application to adapt the language of the user we are doing what we call personalization. We are optimizing the website and the user experience depending on their characteristics. The language we think they talk or the language they selected in a menu. This is personalization. Having paid versus free content is also personalization especially for instance if you have only the beginning of an article before hitting a pay wall. This is personalization in a sense that unpaid users have a different experience from paid users. Paid users have their content and unpaid users are invited to get a subscription. They have a different experience, a personalized experience, and they belong to different segment guest users and paid users. A-B testing is also a very important use case, maybe more advanced, but if you make a lot of money out of a website you probably have set up already A-B testing because it helps you test new versions of your website incrementally without affecting your whole user database. So most often we have two segments that are actually named buckets in A-B testing environment, A and B, and you have two different of the website A and B depending on the on this segment.
3. Rendering Techniques
Server-side rendering is the polar opposite of client-side rendering. Static seed generation is a middle ground that allows for generating multiple versions of a page based on parameters. Dynamic rendering, such as client-side rendering, allows for real-time updates but requires more computations. Static generation, while not adaptable to individual requests, is faster and can be tempting for personalization.
Server-side rendering is the polar opposite. You are doing everything on the server for each request. This is closer, for instance, to how PHP works. When you do a request it will hit a page that is a template. The server will fetch some data from the database at this point and will fill the template with the right values, and you end up with your rendered page that is then sent as-is to the browser as pure HTML.
And you have static seed generation, which sits in between, which is basically just server-side rendering, but not paired request, but computed at build time. It's similar in a way to just writing HTML. You could just write the page. But of course, it would be quite dumb to write the content directly. So static seed generation lets you do this at scale. You have the same page, and the static seed generator is able to generate multiple versions depending on some parameters you input, like the language, the theme, and so on.
They divide into two categories. The first one would be the dynamic ways to render a content. Client-side rendering and paired-request server-side rendering are dynamic because server-side rendering happens for each request. So the data can be updated every time the user refreshes the browser, at least. Client-side rendering is even more dynamic because it can be interactive, since it operates on the user's browsers. It can do computation any time. It doesn't even have to talk with the server. So most often you have this pattern, this jam-stacked pattern of calling APIs to get new data and rendering everything client-side. This is very jam-stackish way of doing things.
Static seed generation is well static. Because things are computed at build time, they cannot evolve for each request because you don't have the request yet. No one requested your server, you are just building it and deploying your server at this point. But it's faster because things are already computed and stored in a cache, so there is no new computation. The server just has to serve the computed HTML. And what will you use for personalization? You might be tempted to say dynamic patterns because they can adapt to the request because they can happen in the user's browser, so literally on their machine. It's easier to adapt and to personalize for a precise user, of course. However, they are slower. They need more computations. So you also have the choice to use static generation, but how? It's faster, so it's tempting.
4. Segmented Rendering for Rich Customers
Using dynamic and slower rendering for personalized content creates a rich guest, poor customer issue. Unpaid visitors and guest users receive faster static renders, while authenticated customers with personalized content experience slower rendering. Segmented rendering addresses this issue by enabling static renders for personalized content.
But how? Again, since it doesn't move, how do you do that? And using systemically the dynamic and slower solution leads to an issue that I call the rich guest, poor customer issue. You will use the faster static renders only for public content, for content that is available to anyone surfing the web. So unpaid visitors, guest users, as well as connected users. And you will use the slower dynamic renders for personalized content. You will do use CPU time from the users, if you do client-side rendering. You will have slower computation on the backend if you do pair requests server-side rendering. So basically your customers that are authenticated, that receive personalized content based on their own personal data, have the poorest pattern, the slowest pattern. They are poor customers, while the guests that provide most often less value on the website because they are not connected, you don't know them, you can target them, they are not customers, they have the best experience. They are rich guests. This is the rich guest, poor customers issue. And segmented rendering is a way to reduce this issue by enabling static renders for personalized content to have rich customers.
5. Personalized Staticness and Proxy Server
Let's talk about personalized staticness using segmented rendering patterns. The easiest implementation is to have one URL per segment, one URL per theme choice for users. But it leads to some issues. Users shouldn't be able to tell in which bucket they are. The URL can become long and ugly. To solve this issue, let's introduce a simple, lightweight proxy server.
So let's talk about personalized staticness using segmented rendering patterns. Let's do a first try, let's try to use the URL to personalize the content statically. It's very easy because most static seed generators rely on the URL, be it next.js, or Gatsby, or Astro, and so on. You give them URLs to render, and depending on the parameter, they will fetch the correct data and render the page accordingly. That's how they work.
So it's the easiest implementation, is to have one URL per segment, one URL per theme choice for users. So users that picked the fire theme will have one version, water theme one version, and grass theme one version. But it leads to some issues. First, the user can change the URL. It's okay for a theme, it's okay for a language. It's even a feature in a way, for a language. You can change the language of the page by just changing the URL. But it's a problem if you start doing personalization with paid content. You don't want users to change the URL to suddenly become paid users. You'd rather want them to pay for something. Then the user can see the parameter. Again, not a problem for a language, it's even a good thing for a language because it allows sharing the URL to other people speaking the same language with the language in the URL so they get the right content. But for an A-B test, that's a huge issue. Users shouldn't be able to tell in which bucket they are. Otherwise, you are drastically biasing the A-B test. It leads to a lot of issues and the data are just not valid anymore. So they shouldn't see the parameter in this case. And finally, the URL can become long and ugly. If you have a lot of parameters, you will end up with the language, the dark or light theme, the tenant, the company, the organization the users belong to. If you are doing business to business, it's very common to have multi-tenancy. To have multiple companies using your application with a lot of users per company. You will have the A-B test bucket, which is not good, paid content and so on. You have very long and ugly URLs.
So, to solve this issue, this limitation, let's introduce a new piece in our architecture. Let's introduce a simple, lightweight proxy server.
6. Proxy Server and URL Rewrite
The proxy server rewrites the URL based on the segment, making it invisible to the user and protecting it from being changed. The length and appearance of the URL are no longer an issue, and there are advanced patterns to compress parameters if needed.
The role of this proxy server will be to take the HTTP request that hits the server and to re-write the URL, depending on the segment. I insist on the word re-write the URL, and not redirect the URL. A URL re-write is not visible to the end-user, and that's the key difference, because it solves all our issues with the URL at once.
The user cannot see the parameter anymore. The user cannot change the parameter anymore, because it's protected by the server, it's computed server-side. So the user cannot hack it by just changing browser values. And finally, the fact that the URL is long and ugly is not a problem anymore, because the users do not see it anymore. You can reach the limitation of 255 characters for URL, but in practice this will never actually happen. And even then we have more, even more advanced patterns to fix that. It's linked in the resource it's called the Megaparam patterns. Basically, you can encode the parameters to compress them. So there is solution even for this slight limitation.
7. Segmented Rendering and URL Rewriting
To solve our issue, we convert the cookie into a URL parameter compatible with existing frameworks. This is called segmented rendering, where each variation has a unique URL. For example, for internationalization, the accept language header can be used to rewrite the URL to the correct language, eliminating the need for an explicit language parameter. Users can change the language using an invisible cookie instead of a visible URL parameter.
So to solve our issue, we have an HTTP request with the cookie fire and we turn that into a URL parameter fire, which is compatible with how existing frameworks work because Gatsby, NEFGS will be able to statically render content as long as the URL for each variation is unique. This is what we call segmented rendering. This is a recipe with two ingredients having one URL per segment. This is just how static rendering works. If it generates multiple variations of your website statically, you already do this but the trick is to use a tiny URL rewriting server to redirect to the right URL depending on other parameters of the request like the cookies or the headers. If I take another example with internationalization you could use the accept language header and rewrite the URL to the right language. This would remove the need from having an explicit language parameter. You still need a way for users to change the language but you could do that using a cookie that is invisible instead of using a URL parameter which is visible and in some scenarios might be ugly.
8. Implementation with Next.js
Let's take a look at an implementation with Next.js. Our application uses segmented rendering to allow users to pick a theme. The theme is stored in a cookie, providing personalization without altering the URL. The page is statically rendered with the chosen theme, and the server response confirms the correct theme. The implementation involves static seed generation and incremental static regeneration for flexibility. The middleware, a lightweight proxy server, reads the theme cookie and writes the URL. This achieves segmented rendering without the need for a root parameter.
Okay so this might sound a bit abstract. So now let's take a look at an implementation with Next.js which is very interesting because it allows Next.js embeds the concept of edge middlewares that are exactly that. The proxy server that we need to implement segmented rendering. They provide that out of the box.
So here is our application using segmented rendering. It's a Next.js application that lets me pick a theme fire, water or grass. Okay so let's pick the fire theme. You will see that it changes the color as expected. The interesting part is that it doesn't alter the url. First, so if I go to application and check the cookies for this application I will see that I'm relaying on the theme cookie name fire instead of using a root parameter I'm using a cookie which is the right way to do personalization in many scenarios. Second interesting fact is that if I reload the page I will get the themed version already. Of course this is all statically rendered so for instance if I go to the network and I check the response of the server for the html request I will see my content with the right theme. So here I've not configured the the CSS for server-side rendering but I can see the fire theme in the html already so I'm indeed using static rendering. This is computed in advanced server-side there is no client-side computation happening.
Regarding the implementation the first piece is just a page with static seed generation as you would find in any Next.js application using get static path, get static props as usual. I generate different version of the page depending on the theme parameter. Notice that I'm using incremental static regeneration which is just a pattern in Next to understand the Next to handle the case where I have a lot of themes. For instance, here I'm not pre-rendering the green starter because maybe this is less requested by people and I don't want to have a very long build time so it will be computed only on the first request. So we have a lot of flexibility with this approach. And then of course I render my page based on this parameter. This is very usual if you use Next.js or any other static rendering framework, you will be used to this approach. But the most important part is the middleware. This is my proxy server. And when I mean tiny and lightweight, I'm not joking. It's 25 lines with a lot of commands. What it does, reads the cookies. If it's a valid theme, it will write the URL. Okay. As simple as that. This is how I get segmented rendering, so static rendering with personalization without using a root parameter.
9. Invisible Server-Side Rendering and the Future
This part discusses the security and benefits of invisible server-side rendering for personalized themes. It also mentions the implementation example and the use of segmented rendering at the edge. The conclusion highlights the importance of caching in server-side rendering and suggests a future unified API for server rendering.
This is invisible to the user and this is secure because it's happening server-side. I can't let the user pick a theme that does not exist, for instance. They can only select fire, water, grass, or none. Otherwise, I throw an error. This is secure. It's great for paid content, A-B test, for instance.
Finally, just a detail, but that's optional, I've added some logic to switch the theme based on a cookie using an API root. So, I'm using the set cookie HTTP header, but you could do the same client-side, of course.
Let's get back to my slides. So, now you have an example of the implementation, and in Vercel, you might have a different wording. They won't call that segmented rendering. They will call that edge personalization. And it's actually the Vercel translation of this pattern. This is the same thing, except that Vercel is allowing you to have segmented rendering at the edge using its edge network. But it's basically the same idea.
Short conclusion. What's the future of server-side rendering? I think the future of server-side rendering is understanding that it's all about caching. Static is server-side rendering cached at build time. Per request, server-side rendering is just a cache miss in the same pattern. The cache key is not just the URL, but the full request. This is the idea behind segmented rendering, to use the request and not just the URL. And the value is of course the rendered HTML, or the data. It depends on the pattern. Gatsby deferred static rendering, for instance, is untying both and Next.js is always considering them as a whole. They are very tightly related in Next, but either way, that's the cache value. So my take is that in the future, we will have a unified API for server rendering that encompasses static PairRequest and everything in between. And until that, we have segmented rendering.