An average user easily goes through over a hundred web pages per day. And about half these users visit sites on their mobile device. This means your website needs to get to interactive within seconds, if not milliseconds — always. If you’re building with both high performance and great conversion, you’re probably aware of the delicate balance that you need to strike to delight your users with a memorable experience. You’ll need third-party services to help you measure and analyze your site’s performance, but this might contribute to a slower website. Fortunately, Next.js comes loaded with features that you can use to get that balance right. In this blog post, we’ll explore strategies to optimally connect your third-party services to your Next.js site and make your site faster.
There are more than 25 million ecommerce sites on the internet. For your website to stand out and reach your target audience, you need to rely on more than just your code. You need external services to help you with localization, personalization, analytics, A/B testing, and more. These services are all built in mind in helping you understand your users and provide exactly what they’re looking for. But if you don’t connect these sites to your site thoughtfully, you could end up paying a steep performance cost.
The Next.js script component lets you load scripts in a variety of ways. One of them is the worker strategy, which is still in the experiment stage and is accomplished in collaboration with Builder.io’s Partytown.
The worker strategy lets you offload third-party scripts from the main thread to run concurrently on a completely separate thread. This entirely eliminates the performance impact from third-party services that only need to run in the background, like analytics, which are working behind the scenes and do not need to block your main thread. Partytown uses a lightweight technique that makes the worker thread emulate the main thread, so that all your third-party scripts can work as they would on the main thread.
Partytown is still in beta, so not all third-party scripts work perfectly, but we encourage you to try working with Partytown to improve performance. You could also ask your vendors to make modifications that allow your services to run performantly in the worker environment.
The idea behind these strategies is to prioritize render-critical content — content that your user needs to see as fast as possible. Anything that is not render-critical is deprioritized and loaded after the user can start interacting with the site.
Next.js does this using static site generation, server-side rendering or edge servers at build time or incrementally at runtime. These let you offload as much data as possible to the server so that we can deliver to the end user instantly from a cache and do as little remaining work as possible in the browser’s main thread. This is really useful to run services like CMS, ecommerce platforms, search functionalities, etc., that are supplying content for your users to see on a Next.js site.
This is where the getStaticProps and getServerSideProps functions come in. When we export the getStaticProps function, we can collect all the data in advance and can serve it from the edge pre-rendered and not have to fetch anything browser side. With getServerSideProps, we can deliver more dynamic server-rendered data. React server components let you fetch data within our components using suspense. These two strategies help you achieve the fastest possible load times for your site.
Next.js’s Edge middleware comes to the rescue. You could add a file right in your Next.js project, and upon deployment, this file actually gets delivered and runs at the edge at the CDN, as opposed to your origin location. Yet it’s right there in your project, deployed, managed, and version controlled together.
With just a tiny bit of code, you can do rewrites at the edge. With Edge middleware, we can deliver different variations of content, pre-generated or generated on demand, to different visitors on the same URL — equally fast as a static page, but as dynamic as you need. This is a great strategy for services supporting A/B testing, like Builder.io, LaunchDarkly, or Google Optimize, and allows you to extensively customize.
Cookies are a great way to share small snippets of data about your users between the browser and the edge. When you draw cookies with key value pairs and a prefix (for example, personalization.returnvisitor=true) from a customer data platform (CDP), you can automatically append the key value pairs to the URL path. This means we’re dynamically rewriting /page into /page with attributes (In this case, we’re rewriting /page to a /page/returnvisitor).
This way, you can serve a unique page to your visitors who have specific attributes. With incremental static regeneration (ISR), we can fall back on every set of pairs we haven’t seen before and render them server-side. If we’ve seen the key value pairs before, we can parse them out with getStaticProps and send the additional attributes to different servers to get a more tailored response. Now we can respond with our personalized page — and what’s more, this page remains in the cache for that specific set of attributes so future visitors with those attributes will get the same page immediately. We can revalidate this page from time to time in the background or with on-demand ISR anytime content updates in your CMS or other services. This means you can keep these personalized pages up-to-the-second fresh.
Here’s another end-to-end example, this time featuring Builder.io. In the case of Builder, instead of just asking for generic data, we can pass through the attributes about the given visitor. Then in Builder’s visual development platform, your teams can make variations of any content based on the attributes we’ve set, no matter their coding skills. When you’re rendering you can render basic structured data where you define structure and add fields where you like (which is what you’re used to with your headless CMS).
You can also dynamically render composition trees. Builder can provide a drag-and-drop editor to allow even your non-development teams to compose your React components and set their props. When you deliver that tree, your Builder component dynamically renders that tree. So from the components you’ve registered, the tree describes that you put your hero here, your products there, and what props you need — and dynamically populate all that. Builder helps you address use cases like personalization or landing pages, reduces dependency on developers and therefore, developer backlogs, and also helps you maintain everything in your design system, matching your developer needs.
This workflow can work with literally any other backend. And here’s the best part: You can use this strategy not only to build different pages, but also for sections of pages or your typical CMS structured data.
Third-party scripts can significantly slow your website down. Fortunately, Next.js comes with a host of features that help you create highly performant websites even when you use third-party services. The versatile
<script/> component helps you handle services like analytics, and you can move background apps to a worker thread using Builder.io’s Partytown. SSR and SSG are great strategies for anything that supplies content to your website, like CMSs and ecommerce platforms. Finally, Edge middleware is a great solution when you need to create high-performance personalization and unique pages and sections of pages for each visitor.
If you enjoyed this summary, you might enjoy watching the video of the conference below.