If you’re new to the idea of a “headless CMS”, then you’ve been living under a rock it is a way of building applications that uses APIs to retrieve the data it needs to render your content.
As you might already know, websites would traditionally server-render their content on-the-fly and couple the rendering layer (the markup) with the data itself. And unless you wired in something like Cloudflare to cache your API requests, this meant that not only was your server working overtime, but you were also locked into something like PHP to build interfaces.
OK, now back to 2023. For the past handful of years, decoupling the API layer meant that we could build in any framework on any platform by sharing APIs. This means that we can ship entirely separate applications in isolation from one another, from static Next.js sites to React Native apps.
To no one’s surprise, Payload has gone all-in with the idea of headless CMS. We love the idea of giving front-end developers the tools they need to build apps using their framework of choice, and do it quickly. But not every headless setup is the same.
Some of them are wildly different.
Ultimately, the requirements of your project should determine which setup you choose, but it can be confusing to know where to start.
This post will guide you through these concepts at a high-level, provide you some fully working examples to learn from, and most importantly, give you some production-ready templates to jumpstart your next project.
Payload supports every kind of headless setup and includes authentication, for free, with one line of code. These are concepts that apply to any front-end framework, not just Next.js.
At a high level there are three main ways of using Payload in a headless capacity:
This has long been the standard for myself and many other developers: deploy Payload on one server, deploy Next.js on another, then connect the two through network requests.
This is probably the easiest way of understanding the relationship of your front-end and its headless CMS. You could even host these applications entirely separately from one another.
For example, when Vercel began offering front-end hosting solutions, this meant that our static web pages could be served through their global network and cached on their CDN. Our Payload instance would be completely isolated, running entirely on its own infrastructure, with relatively low CPU usage.
Now fast forward a few years and a few dozen sites, and we’re admittedly exhausted with this setup.
Don’t get me wrong, this is a great situation if you’re maintaining a small number of projects. But deployments are tedious at scale this way because they need to be done in sync. Changes to the CMS need to be deployed before the front-end is. Made a change to your GraphQL schema? Forget about it. Whole things breaks. Good thing we’ve deployed statically and that Vercel has instant rollbacks.
I’m exaggerating here, but only slightly. This can be a serious pain. Plus when deploying this way, there are additional security hoops to jump through because your site is accessing your API across domains and ports. It’s not the end of the world, especially if this is your only site, but it does require a bit of brain power up front.
That being said, most of our examples showcase this setup (listed toward the end of this post) and I’ll continue recommending it.
So while deploying separately might be a great choice for many projects, using a combined setup has become increasingly more popular over time, and for good reason. Here’s why:
When you use Payload, you plug it into your Express server. That's a fundamental difference between Payload and other application frameworks. It means that when you use Payload, you're technically adding Payload to your app, and not building a "Payload app".
Let that sink in for a moment.
This means you can integrate your Payload instance directly with your front-end on the same server. This means:
That last point is huge. This setup makes it possible for you to use Payload Local API directly on your front-end. Unlike
fetch requests, you don't need to deal with server latency or network speed whatsoever and can interact directly with your database.
It's very popular right now to deploy serverlessly, or better yet, on the edge. While Payload is not fully on the edge (yet), we did go serverless in Next.js.
This was a big win for so many developers.
You get all the benefits of a combined setup, plus some. However, it's not for everyone, and below I've outlined why (but first, let’s back up to explain what “serverless” means): Instead of spinning up a long-running Payload app that is always open, and always listening for incoming requests to its API, we spin up Payload fresh every single time we need it.
What this ultimately means is that when you visit
/admin, for instance, Payload may or may not be running, and may require a moment to boot. This means that lightly used sites may experience the infamous “cold start", a known caveat of this pattern. But if your app receives regular, heavy traffic, this might still be a great option for you. Or if your site is statically generated, your users may never even notice.
This pattern will allow you to deploy your entire stack to Vercel, including Payload.
Now let’s talk about the front-end stack. React has pretty much swept the floor in terms of popularity in recent years. While there have always been some great alternatives out there, this has always been the single most important deciding factor in our adoption of it.
And long before Payload, way back when React was class-based and before Vercel had been coined, we were server-rendering React and hydrating the client ourselves.
This is why we value Next.js so highly. We no longer had to jump through these hoops because Next.js had our backs. To us,
getServerSideProps was like magic.
Then just like that they shipped support for static site generation which immediately became a game-changer for us. Over night,
getStaticProps became our best friend. This meant that our sites could now generate HTML at build time, passing huge savings in server bandwidth onto us. We implemented incremental static revalidation, on-demand ISR, preview mode, the works (examples below). And for smaller sites, this also meant that we no longer had a strong need to implement API-level caching.
Plus, our websites felt like they loaded at light speed ... and we’d casually take all the credit. 😉
Now the tides are turning once again and we’re all for it. We’re really coming around to the idea of React Server Components and we’re leaning into it big time. For some in the Next.js world, the move from the Pages Router to the App Router has proven to be a learning curve, and admittedly it has for us too.
This change was especially difficult to embrace because it was a complete paradigm shift (and the page router was that good). But looking back, this is sort of how I felt when React Hooks was first introduced. Once I got the hang of it, it made total sense. I was really only upset because I had to learn something new and that it took away from real paying work. Real concerns, but this has since payed dividends in site speed and DX.
If I haven’t made this clear enough, there are many different ways of integrating your front-end with Payload. But we don’t want to lock you into a box or force you to stay up all night pulling your hair out trying to get all the latest and greatest features in place, especially when it comes to Next.js.
This is exactly why we built the Examples Directory.
If you’re working with Next.js and Payload in any capacity, we probably have an example for that:
Or if you’re interested in Vercel Visual Editing Integration, we’ve got that, too.
The Examples Directory is constantly changing, and we’re always looking to showcase features from all different frameworks. If you’re looking to become a Payload contributor, this is a great place to start.
If you’re working on a feature or framework that is not yet demonstrated, please consider contributing your work for others to see.
OK, phew, that was a lot.
If you’ve tuned out until now, good news, there’s an option for that 😊. We have fully-featured, end-to-end templates which put together all the best practices to the best of our ability. Each is built in the same way we’d build an application for ourselves, making all the right decisions so you don’t have to. But just like with examples, this is an ongoing effort.
We’re constantly adding new features, making improvements to our templates, as well as making new ones.
It’s possible to build all kinds of other applications with Payload too, from CRM to LMS and everything in between.
If you read this post and are still lost then I have failed you, but I’d love to know about it. Please reach out with any questions you might have. Or better yet, publicly shame me on X.