Easing into the App Router with the Sanity Toolkit for Next.js
Written by Marissa Ghassemian, Knut Melvær
Picture this: you're on the hunt for information or looking to make a purchase online, but the webpage you clicked is taking an eternity to load. Frustrating, right? How often do you just bail when this happens? We all know these experiences drive users away, but let’s face it: it takes a lot of time and skill to develop a performant site, especially for the dynamic, rich experiences that our visitors love. It’s also worth it: websites that meet user expectations and needs instill a sense of trust and reliability in a brand, make it easier for users to achieve their online objectives, and ultimately help you grow your business.
Today we’re happy to share our latest improvements to Sanity’s Next.js toolkit, which combines the might of our client library,@sanity/client, and Next.js, all in one convenient package. Together with Next.js App Router, these improvements reduce the burden on developers to build the complex caching infrastructures needed to power fast, fresh content loads while letting you remove lines of code, perform less maintenance and make fewer API calls.
More delightful = more demanding
Brands that win are constantly launching richer, more dynamic experiences that stand out. The teams that make these experiences a reality are faced with major challenges as they need to maintain performance as sites become more:
- Asset heavy. Videos and images are key to delivering engaging, memorable content— 91% of consumers reported preferring visual content to written content. They’re also a huge contributor to page weight and often the main culprit in slower load times.
- Personalized. Personalization requires dynamic builds with fresh content to deliver tailored experiences. And it’s worth the effort: BusinessWire reported 80% of consumers are more likely to shop with brands that show they know them.
- Updated frequently. Most brands have pockets of content that are refreshed often. Within certain use cases, however, content updates are near-constant. Think about Media companies needing to tenaciously display the latest news.
Overcoming performance drains with Sanity and Vercel
Staying ahead of your competitors requires harnessing the power of innovative tools and platforms. Vercel, a cloud platform for building, deploying, and scaling apps and websites, has been leading the charge in helping development teams meet the ever-increasing demands of their sites. They’re also the creator and maintainer of Next.js, one of the most popular web frameworks on the planet right now for React. Sanity, the Composable Content Cloud, offers the most control and customization of any CMS. Together, the Next.js, Vercel, and Sanity stack is unstoppable.
Sanity has improved how we build with content for our clients. We can give them bespoke content workspaces that make sense for their business, while enjoying the great developer experience that comes with Sanity Content Lake. With the new App Router, we have even more flexibility building successful user experiences, while ensuring great performance. Content creators can push content to production without having to wait for their changes to appear on the site, knowing that the site stays performant for their audience. It seems like this should be table stakes, but it can be really hard to do without the abstractions given to us by Sanity and Next.js.
Grant Sander, VP of Engineering, Formidable
From static to dynamic
To address the need for a more scalable way to update content, Next.js released Incremental Static Regeneration (ISR) in 2021. With ISR, developers can use static-generation on a per-page basis (rather than having to rebuild an entire site for an isolated change). This has been a huge value for the developer community, but comes with challenges:
- Keeping track of what URLs need to be invalidated. In most real-world scenarios where content is reused across pages, you need to keep track of every page URL affected by a content update so you know which pages to send an invalidation request for. This type of caching architecture requires a fair amount of manual work to be done.
- Reloading the entire page. Reloading the entire page after an invalidation request is often a big hit to your performance when you have the type of heavy, rapidly evolving content we all love. This means slower load times, increased bandwidth consumption, and degraded user experiences.
Now: App Router with React Server Components
Fast forward to 2023, Vercel’s latest release of Next.js 13 introduced App Router, giving you a deeper level of control to create sites that perform as fast as static sites, but are completely dynamic. How? By defining your caching strategy—dynamic vs. static—for individual components within a page, you avoid entire page reloads. This is powered by React Server Components, which makes every component on your website responsible for its own data. Using these new data fetching and caching paradigms, revalidation now moves to individual fetching.
The biggest mental model shift in Next.js 13 is to stop thinking which pages should be static or dynamic and start thinking about what data is static or dynamic. Moving the static and dynamic decisions to data fetching gives you more control over when and where to serve static or dynamic content.
Vercel
How exactly do you indicate what components need to be updated without revalidating the entire page? You can use revalidation tags. Revalidation tags mark a specific request correlated to the specified tag to be expired when information changes. This type of technology gives you the customizability to invalidate content with the granularity you see fit, for example, only this author, all authors, and so on. – the power is in your hands.
Sanity for the assist: Built-in compatibility for Next.js
Because Sanity treats content as data (structured and queryable) and offers a high degree of query flexibility with GROQ, it’s a well-suited headless CMS to pair with App Router. And we've fine-tuned our Next.js toolkit, next-sanity, to give developers a more intuitive and efficient experience as they build high-performance, user-delighting sites.
More for developers to love
Next.js is all about giving developers tooling to build as quickly as possible with minimal configurations. With the same intent, we’ve combined the power of our client library, @sanity/client, and Next.js, in one convenient package so developers can enjoy the DX of next-sanity and Next.js in one place. Benefits include:
- Seamless integration: Native integration means that @sanity/client is purpose-built to work with Next.js. This eliminates compatibility issues so developers don’t need to invest time in custom integrations and can reduce risk of bugs and errors.
- Faster development: Developers can save valuable time by leveraging the built-in functionality. They can quickly start building sites without having to write extensive custom code or configurations that accelerate development cycles.
- Consistency and best practices: Native integration follows Next.js best practices and coding conventions. This ensures that developers adhere to established standards, leading to more maintainable code.
- Performance optimization: With core capabilities integrated into @sanity/client, the library is fine-tuned for performance within the Next.js ecosystem. This means that developers can rely on efficient and well-optimized code, resulting in faster-loading websites.
- Reduced learning curve: Developers familiar with Next.js can easily transition to using @sanity/client because it aligns with the framework they already know, so they can be productive from the start.
- Community support: You can find documentation, examples, and community-driven solutions readily available in the Sanity Community, making it easier to troubleshoot issues, seek assistance and get inspiration.
- Future updates and compatibility: As Next.js evolves, Sanity will stay up-to-date with changes so developers can take advantage of the latest and greatest, such as the aforementioned App Router and Revalidation Tags, and maintain compatibility as the framework evolves.
Easing into App Router
React Server Components and the App Router represented a fundamental shift in how you build web applications with Next.js, and it can be daunting to have to re-learn a framework. Fortunately, Next.js lets you adopt the App Router incrementally alongside the Page Router. What’s more, our next-sanity toolkit is compatible with both! This means you get advanced caching and tag-based revalidation features to make your life a lot easier. In other words, using Next.js and Sanity together is a good way to get started with React Server Components, and start reaping its benefits.
Making Fetch happen
Fetch functionality in Next.js refers to the ability to retrieve data from an external source or API in a website. You can fetch data either at build time on the server or during runtime on the client, boosting not only your site's speed but also its SEO and overall user experience. In simple terms, it means quicker page loads, better user experience, better SEO rankings, less work for your client-side code, and even the ability to pre-render pages with ever-changing data. All leading to a smoother, faster, and more efficient website.
Our next-sanity toolkit is now fully compatible with Next.js’ capabilities, bringing together the best of its internal data-fetching methods and our own client library. This combo significantly reduces the number of API calls needed to keep content updated. Instead of constantly polling for changes, you can set up a webhook to trigger the appropriate calls only when a change occurs, eliminating the need for expiration checks. This makes it especially effective for e-commerce and media sites that require real-time updates and robust caching strategies.
While navigating caching options can often be complex and time-consuming, Sanity lets you easily opt for the most fitting caching approach for any page or component. And if your project demands more nuanced control—common in mature, dynamic sites—you can use revalidation tags for fine-grained management, making it easier to keep your content both fresh and efficient.
Example of a component with data fetching + revalidation tag
Internal server error