DEV Community

Cover image for How to get CMS in any Next app with one line
Anmol Baranwal
Anmol Baranwal

Posted on

How to get CMS in any Next app with one line

Have you ever thought of building software that could earn a huge revenue?

That app should be very good as per standards and should be able to handle a large set of users without any loss in performance.

I will tell you the most recommended and simplest approach you can use to build such apps using Next.js and Payload.

I will also cover the latest Payload v3 beta release and more.

Let's do it!

payload


What is covered?

In a nutshell, we are covering these topics in detail.

  1. What is Payload and why should you use it?
  2. Payload 3.0 beta release.
  3. Critical concepts of Payload.
  4. A step-by-step guide on how to start using Payload.
  5. Use cases and examples of apps built with Payload.

1. What is Payload and why should you use it?

Payload is a headless CMS and application framework.
Payload is there to give a massive boost to your development process, but importantly, stay out of your way as your apps get more complex.

The best part is that it's open source meaning that you can contribute to make it even better.

It's safe to say that Payload is the best way to build a modern backend with a flexible admin UI.

payload case study snapshot

You can install Payload in any Next.js app using this command:

npx create-payload-app@beta
Enter fullscreen mode Exit fullscreen mode

What is Headless CMS?

For those unfamiliar, a headless CMS simply allows users to manage content in one place and deploy it on any digital channel.

Let me explain.
In short - It's just any backend application, which is 100% built upon APIs. Headless means -> frontend less body. That can be attached to any frontend/Head.

Read the detailed comparison on Payload vs other popular CMS providers such as Sanity, Contentful, Strapi, Directus, and WordPress.

 

Out of the box, Payload gives you a lot of the things that you often need when developing something new:

✅ A database to store your data (Postgres and MongoDB supported). Just to let you know, Payload doesn't care about the Database and uses an adapter to interact with it.

✅ A way to store, retrieve, and manipulate data of any shape via full REST and GraphQL APIs.

✅ Complete Authentication with all the popular functionalities.

✅ A beautiful admin UI that's generated specifically to suit your data.

In the end, you need something fast, cost-effective, fast, secure and flexible. Payload hits all the checkboxes and more.

features

You also get block-based layout building, Local file storage, and even Content localization. Read about all the features you get with Payload.

By the way, the website is one of the best that I've seen of all 5000+ websites :)

power anything

Payload has 19k+ stars on GitHub, is on the v2.14, and is used by 9k+ developers.

Star Payload ⭐️


2. Payload 3.0 beta release.

The idea for this latest release was conceived at the Next.js Conference last year.

James, one of the founders of Payload, discussed potential changes and the background thinking regarding whether they should pursue these concepts or not. Check out this video from the Next.js Conf for more insight!

Payload has released the v3.0 beta app. They have used the Nextjs official team's optimization on webpack and bundlers to improve lots of stuff.

If you directly want to test the v3 app demo, use this command.

npx create-payload-app@beta
Enter fullscreen mode Exit fullscreen mode

You can check the payload 3.0 demo repo on GitHub. ⭐ Star them to show support!

payload 3.0 demo

The main thing you should know is that Payload is now Next.js native. It's like the first CMS for nextjs.

It means integrating Next route handlers, app routers, and other related concepts smoothly. They would work seamlessly together, and voila!

other frameworks

cool things

If Next.js isn't your preference, you can still opt for Astro, Remix, or any framework you like, just like with Payload v2. But, I suggest giving Next a shot at least once.

The most impressive feat is that they managed to shrink the entire modular size to under 2MB. WOW!

Some of the things you should know:

✅ Contents from src/app are moved into a new directory src/app/(app) to keep Payload's root layout and routes isolated from the rest of your app.

✅ Turbopack works out of the box. This is very great!

✅ The Payload admin UI is built with React Server Components and automatically eliminates server-side code from your admin bundle.

✅ It means that there is no two-way process of creating an endpoint to hide the API key whenever we are fetching the data which will ultimately improve the speed of the whole process.

✅ You cannot use useState or other concepts involved in client components unless you define it at the top of the file using use client.

✅ All UI components have been abstracted into a separate @payloadcms/ui package. You can reuse it across different parts of your app, and the imports have also been improved compared to the last version.

✅ You can also run your own Next.js site alongside Payload in the same app. This is what many of us would like to do!

Read about all the highlights of the v3 beta release.

They have also provided a one-click deployment to Vercel. That will make the job a lot easier!

To keep up with the breaking changes before the release of the full stable release, you can check out CHANGELOG.

If you're interested in the journey, then watch this video where James tells about the 2024 Roadmap and their Next.js Decision (And A Lot More). It is from 4 months ago!


3. Critical concepts of Payload.

Payload is based on a small and intuitive set of concepts.

Before starting to work with Payload, it's a good idea to familiarize yourself with the following.

🎯 Config.

The Payload config is where you configure everything that Payload does.

By default, the Payload config lives in the root folder of your code and is named payload.config.js (payload.config.ts if you're using TypeScript), but you can customize its name and where you store it.

You can write full functions and even React components right into your config.

🎯 Collections.

A Collection represents a type of content that Payload will store and can contain many documents.

Collections define the shape of your data as well as all functionalities attached to that data.

They can represent anything you can store in a database - for example - pages, posts, users, people, orders, categories, events, customers, transactions, and anything else your app needs.

A simple collection example.

import { CollectionConfig } from 'payload/types'

export const Orders: CollectionConfig = {
  slug: 'orders',
  fields: [
    {
      name: 'total',
      type: 'number',
      required: true,
    },
    {
      name: 'placedBy',
      type: 'relationship',
      relationTo: 'customers',
      required: true,
    },
  ],
}
Enter fullscreen mode Exit fullscreen mode

It's often best practice to write your Collections in separate files and then import them into the main Payload config.

You can read more about Collections.

🎯 Globals.

A Global is a "one-off" piece of content that is perfect for storing navigational structures, themes, top-level metadata, and more.

🎯 Fields.

Fields are the building blocks of Payload.

Payload comes with many different field types that give you a ton of flexibility while designing your API.

This is the most important because you need to define it under the collections to configure the UI.

Let's see an example with a simple collection with two fields.

import { CollectionConfig } from 'payload/types'

export const Page: CollectionConfig = {
  slug: 'pages',
  fields: [
    {
      name: 'myField',
      type: 'text', 
    },
    {
      name: 'otherField',
      type: 'checkbox', 
    },
  ],
}
Enter fullscreen mode Exit fullscreen mode

Suppose you want to create users, then you can insert an email textbox.

import { CollectionConfig } from 'payload/types'

export const ExampleCollection: CollectionConfig = {
  slug: 'example-collection',
  fields: [
    {
      name: 'contact', // required
      type: 'email', // required
      label: 'Contact Email Address',
      required: true,
    },
  ],
}
Enter fullscreen mode Exit fullscreen mode

email in admin ui

Let's take another example of a rich text editor. I've done it in a users collection.

Payload currently supports two official rich text editors, and you can choose either one depending on your needs. Personally, I am not sure what's the big difference.

  • SlateJS - stable, backward-compatible with 1.0.
  • Lexical - beta, where things will be moving in the future.

Let's see how to implement it (src/collections/Users.ts).

import type { CollectionConfig } from 'payload/types'

export const Users: CollectionConfig = {
  slug: 'users',
  admin: {
    useAsTitle: 'email',
  },
  auth: true,
  fields: [
    // this line only ----------
    { name: 'editor', type: 'richText', label: 'Rich Text' },
  ],
}
Enter fullscreen mode Exit fullscreen mode

The output of the above code will be as follows.

text editor

text editor

 

slash commands

you can also use slash commands

 

It's that easy!

There are a lot of other fields available such as upload, collapsible, blocks (most exciting), Date, and many more.
You can view the complete list.

Fields are the most important concept you should know if you end up using Payload. It makes the work a lot easier!

🎯 Hooks.

Hooks are where you can "tie in" to existing Payload actions to perform your own additional logic or modify how Payload operates altogether.

With Hooks, you can transform Payload from a traditional CMS into a fully-fledged application framework.

Some of the specific use cases are:

a. Integrate user profiles with a third-party CRM such as Salesforce or Hubspot.

b. Integrate with a payment provider like Stripe to automatically process payments when an Order is created.

c. Automatically add lastModifiedBy data to a document to track who changed what over time.

There are so many possibilities for what you can do. Read more about Hooks including use cases, and their three types that are Collection hooks, Field Hooks and Global Hooks.

🎯 Access Control.

Access Control refers to Payload's system of defining who can do what to your API.

Some of the use cases can be:

a. Only allowing public access to Posts where a status field is equal to published.

b. Enabling users belonging to a specific organization to access only that organization's resources.

By default, all Collections and Globals require a user to log in to interact in any way.

You can read more about Access Control.

🎯 Depth.

Depth gives you control over how many levels down related documents should be which is automatically populated when retrieved.

You can specify population depth via query parameter in the REST API and by an option in the local API.

Read more about Depth with a proper example using collections.

It would be better to read about all of these concepts in the official docs.


4. A step-by-step guide on how to start using Payload with v3.

Let's see an overview of how you can use Payload!

You can open up the workspace and use this command to get started.

npx create-payload-app@beta
Enter fullscreen mode Exit fullscreen mode

When they hit stable, there will be many templates like e-commerce, blog, portfolio, and others which are available in the last version. For now, you can proceed with either of them.

options

You will get two options.

 

mongoDB

If you choose MongoDB, you need to configure the connection string.

 

postgres

If you choose Postgres, you again need to configure the connection string.

 

plugin

If you choose a plugin, everything will be set up as usual.

 

I'm going with the MongoDB for now. If you're building a production-level app, I suggest reading on when to choose MongoDB vs Relational DB as per official Payload docs.

You can head over to the MongoDB Atlas website and create a new project for the deployed cluster.

mongodb cluster

There are various ways to establish the connection. I have used all of them, and I prefer VSCode or the Compass.

connection methods

Both are easy, just insert it once you set it up during the initializing process (setting up payload).

vs code mongodb

using VSCode MongoDB extension

mongodb compass

using MongoDB Compass

 

Check the .env file and the PAYLOAD_SECRET will already be created.

DATABASE_URI=mongodb://127.0.0.1/payload-template-blank-3-0
PAYLOAD_SECRET=YOUR_SECRET_HERE
Enter fullscreen mode Exit fullscreen mode

Install the dependencies as usual, I'm doing it using npm i.
Yarn is suggested by the team!
Yes, I know I'm an old-fashioned guy 😆

Anyway, just start the server using npm run dev.

You can access the admin panel at http://localhost:3000/admin. It will take time the first time, then it's easier as we build it further.

admin panel

Create any sample user for now.

This is what it will look like because there is only one collection in the codebase.

users collection

 

users list

List of users registered

 

You can find it in src/app/collections/Users.ts.

import type { CollectionConfig } from 'payload/types'

export const Users: CollectionConfig = {
  slug: 'users',
  admin: {
    useAsTitle: 'email',
  },
  auth: true,
  fields: [
    // Email added by default
    // Add more fields as needed
  ],
}
Enter fullscreen mode Exit fullscreen mode

The first step that we will do is create a new collection, write a sample component with layout.tsx, and configure it to use Tailwind CSS.

Earlier in v2.0 there were some extra steps we needed to take but in version 3.0 it's as simple as installing tailwind in any other next.js project. Refer to docs.

npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
Enter fullscreen mode Exit fullscreen mode

Rename your tailwind.config.js to tailwind.config.cjs

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./src/**/*.{js,ts,jsx,tsx,mdx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
Enter fullscreen mode Exit fullscreen mode

Rename postcss.config.js to postcss.config.cjs.

module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
}
Enter fullscreen mode Exit fullscreen mode

Create globals.css under the app directory.

@tailwind base;
@tailwind components;
@tailwind utilities;
Enter fullscreen mode Exit fullscreen mode

Don't worry, I will attach a repo link that will give you access to all the code.

Let's make some changes to see how the whole process works.

This is the directory structure I'm using.

directory structure

Create SampleComponent.tsx under the src/app/components directory. This is the sample component that we will render on the UI.

export function SampleComponent() {
  return (
    <div className="bg-gray-300 text-black p-20 border border-white">
      <h2>Hi! This is anmol</h2>
      <div>Testing the latest Payload 3.0 beta release</div>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Update Users.ts under src/collections.

import { SampleComponent } from '@/app/components/SampleComponent'
import type { CollectionConfig } from 'payload/types'

export const Users: CollectionConfig = {
  slug: 'users',
  admin: {
    useAsTitle: 'email',
  },
  auth: true,
  fields: [
    // Email added by default
    // Add more fields as needed
    {
      name: 'header',
      type: 'ui',
      admin: {
        components: {
          Field: SampleComponent,
        },
      },
    },
    { name: 'editor', type: 'richText', label: 'Rich Text' }, // for rich text editor
    {
      name: 'enableCoolStuff', // required
      type: 'checkbox', // required
      label: 'Click me to see fanciness',
      defaultValue: false,
    },
  ],
}
Enter fullscreen mode Exit fullscreen mode

What this user's collection does is that it appends a field with a type of UI and it will display the SampleComponent and rich text editor. I was trying some other stuff as well like checkbox.

Create layout.tsx under the src/app directory which will be the root layout.

import type { Metadata } from 'next'
import './globals.css'
import React from 'react'

export const metadata: Metadata = {
  title: 'Payload v3 beta release',
  description: 'Lets build something cool.',
}

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}
Enter fullscreen mode Exit fullscreen mode

You have to create any user by going to http://localhost:3000/admin/ and you can then click on the users collection and visit any particular user page.

The page would be something like this.

user page

It correctly renders the UI with the component that we made.


Now, there are a bunch of concepts that you can use, and as you saw, it's pretty easy.

Let's cover another case of how we can fetch some of the data that we created, for instance, the user data. I'm removing the text editor UI field from the users collection to keep things clean.

I've also replaced SampleComponent.tsx with SampleComponent.jsx because of the huge types we would need to take care of which aren't needed here when trying things.

Replace SampleComponent.jsx with the following code.

import config from '@payload-config'
import { getPayloadHMR } from '@payloadcms/next/utilities'

export async function SampleComponent() {
  const payload = await getPayloadHMR({ config })

  const users = await payload.find({
    collection: 'users'
  })

  return (
    <div className="bg-gray-300 text-black p-20 border border-white">
      <h2>Hi! This is anmol</h2>
      <div>Testing the latest Payload 3.0 beta release</div>

      <h2 className="pt-4 text-underline">Users Data</h2>
      {users.docs.map((user) => {
        return (
          <div className="flex flex-col my-4">
            <div key={user._id} className="flex text-lg space-x-8 w-[600px] bg-gray-800 text-gray-300 px-4 py-4 rounded-md">
              <div>Email: {user.email}</div>
              <div>ID: {user.id}</div>
            </div>
          </div>
        )
      })}
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

It asynchronously fetches data from Payload using the getPayloadHMR function and retrieves a collection of users from the Payload using the payload.find() method.

It iterates over the user's data retrieved from the Payload to display the data as per structure.

This is how we can fetch the data.

The output would be as shown

payload fetched data

Other use cases can be to make your own dashboard, blog, or even manage content for your website.


Let's cover some of the brief concepts using the codebase.

You can use the layout structure used in the Next.js app router and build it with payload.

You will have complete control over the other stuff like slug route, and auth in the collection itself.

export const Users: CollectionConfig = {
  slug: 'users',
  admin: {
    useAsTitle: 'email',
  },
  auth: true,
...
Enter fullscreen mode Exit fullscreen mode

If you want to know more about Auth, read official docs as auth is always used in most of the SAAS products or any software to track progress with data.
They have also discussed CSRF (cross-site request forgery) protection and how Payload removes many XSS vulnerabilities by using an HTTP-only cookie.

You can also watch this!

One of the latest features is the Hot module reloading on the server and the browser. In version 2, Nodemon has to reload whenever the config changes but now it's automatic so it saves a lot of time!

hot reloading

Hot Reloading

 

The changes to your schema and Payload are parallel with your frontend meaning everything is in one single codebase.
It's easy to work with and removes the technical complexities generally involved. Much better DX!

Payload is parallel with your frontend

Payload is in parallel with your frontend

 

There is also a sample route.ts file that shows how you can create your own route handler and return stuff using Payload.
It will be under the src/app/my-route/route.ts

import configPromise from '@payload-config'
import { getPayload } from 'payload'

export const GET = async () => {
  const payload = await getPayload({
    config: configPromise,
  })

  const data = await payload.find({ // type free local API
    collection: 'users',
  })

  return Response.json(data)
}
Enter fullscreen mode Exit fullscreen mode

The Payload team has made it very modular and every package is separate even from Next. The UI components, fonts, translations, graphQL, and others for example. You can easily re-use them however you want.

separate package

separate ui components package

ui components are separated into the UI package

 

The local API in Payload goes straight to the DB even if you're using other frameworks like Remix, Nuxt, or whatever. It doesn't have to go through the HTTP layer and the dependencies are not that big so you can easily use Payload.

You don't have to write webpack aliases anymore to prevent leaks (earlier version), and there is no headache for bundlers because Next.js already does it.

 

I've created a sample code repo on GitHub so you can directly check that out.

I didn't deploy it on Vercel, but you just need to put the env credentials that we used at the start, and it will deploy instantly!

I've explained it as much as I can but I also recommend watching this: Install Payload Into Any Next.js App With One Line — 3.0 Beta Is Here!.

James has discussed the technical aspects of the latest beta release in detail. You should definitely watch this to understand more!

You can read the docs that will be updated soon with the breaking changes, migration guide, and detailed UI components breakdown for the v3 release.

Just wait and be excited :D


5. Use cases and examples of apps built with Payload.

Payload is trusted by a lot of renowned companies, with many considering it one of the best decisions they've made. Some of these companies include Speechify, Microsoft, and Bizee.

who uses payload

 

🎯 Templates

Let's cover some of the open source templates that are available to use with Payload.

Remix & Payload

A mono repo template to use Remix and Payload easily.

This helps you set up Payload for content management together with Remix in such a manner that each application is divided into its package (including the express server app).

 

Astro & Payload

This is a pre-configured setup for Astro and Payloadcms, designed to make it easy for you to start building your website. With Astroad, you'll have a complete development environment that you can run locally using Docker. This setup simplifies the testing and development of your website before deploying it to a production environment.

 

E-commerce template.

They also provide an e-commerce template that will help you to focus more on business strategy and less on technology. Your APIs are your own and your data belongs to you. You are not beholden to a third-party service that may charge you for API overages, on top of a monthly fee, and that may limit your access to your database. Running an online store will never cost you more than your server (plus payment processing fees).

It always feels strange to start doing something we're not favorable with so you can read How To Build An E-commerce Site With Next.js that uses this template.

 

Find all the three official templates from Payload.

Find all the example apps that are built using Payload.

There is one more recommendation on a full tutorial to build an exceptional app.

Watch how to build a Professionally Designed Website with NextJS, TypeScript, and Payload. It's the first part in a four-part series.

I'm including the links of 2nd video, 3rd video, and 4th video so it's easier to access these. I hope this will help you learn something awesome!


🎯 Case Studies

Read the following case studies. They will tell you about the capabilities of Payload and how it lays a solid foundation.

Quikplow

quikplow

Quikplow is an innovative on‑demand service platform, often described as the "Uber for snow plows."

The speed through which Quikplow was able to develop and deploy a fully functional backend to its app wasn’t just unparalleled—it’s almost unheard of. The entire app, spanning authentication, location-based search, e-commerce functionalities, and more, was developed in less than 120 days.

The unprecedented pace was due to Payload's capabilities for authentication, CRUD operations, and admin panel generation, saving Quikplow valuable development time and budget resources.

 

Paper Triangles

paper triangles

Paper Triangles required an online presence that mirrored their renowned immersive experiences—but found themselves constrained by an outdated and slow content management system.

Working with their agency partner, Old Friends, the challenge was to build a website that reflected their cutting-edge work—requiring auto-playing videos, dynamic animations, integrated camera libraries, and more, without sacrificing speed or ease of content updates.

Payload emerged as the perfect fit. Its open-source nature and robust foundation in TypeScript and React made it an ideal choice for developing a highly custom, interactive front-end.

For an agency like Old Friends, Payload was the sweet spot to deliver on its promise to clients like Paper Triangles.

“Payload provides the easy-to-use interface for our clients and the developer freedom we need to execute custom designs,” said Old Friends’ design engineer James Clements.

 

Bizee

bizee

They needed to migrate and overhaul 2,500 pages while re-platforming to a new CMS and enact a comprehensive site redesign under a total rebrand—in just three months.

To deliver on their promise to Bizee, Riotters (agency) relied on Payload for its clean, TypeScript-driven architecture, which proved transformative, streamlining the design integration and ensuring error-free, maintainable code. This accelerated the content migration and preserved SEO and user experience.

It even facilitated the design-to-development process—helping Riotters translate Figma concepts into live implementations.

Crucially, Payload’s natural synergy with Next.js catalyzed cross-functional collaboration among developers, designers, UX professionals, QA teams, and marketers.

 

Read all the case studies from companies like Microsoft, and Mythical Society.

These case studies provide detailed testimonials, with the problems the agencies faced and how they solved them by using Payload.

It's fascinating that Microsoft chose Payload to showcase its AI ambitions. That's a big collaboration!

Anyway, go explore what you can do with it.
If you're interested in becoming a part of the Payload community, you can join their Discord community.

Payload is totally free and open source.
A big kudos to the team and their continued efforts from the whole open source community :)


I hope you loved the breakdown of the Payload beta release and what it has for YOU.

I believe the DX is very good, and it will be better once there are more templates with the necessary docs (when it hits stable).

I've always wanted to build a SAAS app, and Payload 3.0 is like a bomb that I'm definitely going to use since I love next.js.

How about you? Do you see any advantages that can solve your existing problems? Comment and let me know 👇

I'm on a mission to help others grow 1% daily on Twitter so please follow me there for daily insights.

If you like this kind of stuff,
please follow me for more :)
profile of Twitter with username Anmol_Codes profile of GitHub with username Anmol-Baranwal profile of LinkedIn with username Anmol-Baranwal

"Write more, inspire more!"

Ending GIF waving goodbye

Top comments (5)

Collapse
 
anmolbaranwal profile image
Anmol Baranwal

Hi everyone, I hope you enjoyed the breakdown.
I believe that Payload could be crucial if we want to "Build it, Ship it" very quickly.
I really want to know your views on the Payload 3.0 beta release 😄

Collapse
 
michaeltharrington profile image
Michael Tharrington

Woot! Nice one, Anmol.

Good thorough tutorial! Payload sounds pretty darn helpful.

Collapse
 
anmolbaranwal profile image
Anmol Baranwal

Thanks Michael!
Payload is definitely useful, especially for developers using Next.js :)

Collapse
 
ronaldaug profile image
ronaldaug

Get CMS in just one line, however, config for 1k lines. 😅

Collapse
 
anmolbaranwal profile image
Anmol Baranwal

Haha! As I mentioned, they have optimized it so there won't be a problem with size. Anyone can use it in any project, but there is a slight learning curve, which would be solved once they reach v3 stable, bringing more templates with appropriate docs.