adrianmaj.com

Payload, Ā Next.js, Ā React

PayloadCMS from Scratch #1 - Create and configure project

Author

Adrian Maj

Date published

PayloadCMS is a modern, dynamically developing headless CMS dedicated to Next.js. Thanks to Payload, you can significantly speed up project creation by eliminating the need to repeatedly write the same boilerplate code. Its flexibility and simplicity make it perfect for both small websites and large applications requiring extensive admin panels.

In this post, I'll show you how to create your first "Hello World" in Payload and describe the individual elements of project configuration. After reading it, you'll have a solid foundation for further learning and working with this great tool.

Installation

For setting up Payload, we'll use the official npx script, which simplifies the installation process.

  1. Creating a Project Directory
    Create the directory in any location and open it in your preferred terminal.
    šŸ’” Tip: Payload recommends pnpm, which I also recommend - you can find installation instructions here
  2. Running the Installation Script
    While in the directory, run the command npx create-payload-app@latest - adding @latest will always create the newest version. If you already have a folder created and don't want the wizard to create a new one inside, it's worth adding . at the end of the command, then the project will be created in the current folder.
    npx create-payload-app@latest .
  3. Choosing Settings
    We choose the settings we're interested in, in my case it's the blank template and MongoDB database. As for the connection string, it can be changed later at any time in the .env file.
    Payload project settings
  4. Running the Application
    According to the instructions displayed after confirmation, we launch our application. In our case, we're already in the folder where the project is located, so we can skip the cd command. We start the development server with the command pnpm dev.

After a moment, Payload should be running locally and accessible at http://localhost:3000.

payload-new-project.png

If at this stage you encounter problems with running the server, make sure that:

  • Your database is working correctly.
  • The .env file contains the correct connection string.

Project Structure

It's time to familiarize ourselves with what the wizard created for us. For quick access to Visual Studio Code, I recommend the command code . in the terminal. After opening IDE, we see the following structure:

1šŸ“ payload-template
2ā”œā”€ šŸ“ .next
3ā”œā”€ šŸ“ .vscode
4ā”œā”€ šŸ“ node_modules
5ā”œā”€ šŸ“ src
6ā”‚ ā”œā”€ šŸ“ app
7ā”‚ ā”‚ ā”œā”€ šŸ“ (frontend)
8ā”‚ ā”‚ ā”œā”€ šŸ“ (payload)
9ā”‚ ā”‚ ā””ā”€ šŸ“ my-route
10ā”‚ ā”œā”€ šŸ“ collections
11ā”‚ ā”‚ ā”œā”€ šŸ“„ Media.ts
12ā”‚ ā”‚ ā”œā”€ šŸ“„ Users.ts
13ā”‚ ā”‚ ā””ā”€ šŸ“„ payload-types.ts
14ā”‚ ā””ā”€ šŸ“„ payload.config.ts
15ā”œā”€ šŸ“„ .env
16ā”œā”€ šŸ“„ .env.example
17ā”œā”€ šŸ“„ .gitignore
18ā”œā”€ šŸ“„ .npmrc
19ā”œā”€ šŸ“„ .prettierrc.json
20ā”œā”€ šŸ“„ .yarnrc
21ā”œā”€ šŸ“„ docker-compose.yml
22ā”œā”€ šŸ“„ Dockerfile
23ā”œā”€ šŸ“„ eslint.config.mjs
24ā”œā”€ šŸ“„ next-env.d.ts
25ā”œā”€ šŸ“„ next.config.mjs
26ā”œā”€ šŸ“„ package.json
27ā”œā”€ šŸ“„ pnpm-lock.yaml
28ā”œā”€ šŸ“„ README.md
29ā””ā”€ šŸ“„ tsconfig.json

Let's discuss the key elements that distinguish PayloadCMS from a standard Next.js project:

  • src/app/(frontend) - folder where the Next.js application running under PayloadCMS is located.
  • src/app/(payload) - contains the Payload admin panel and all related files. This folder is created automatically and should not be modified.
  • src/collections - place for collections, which are the data structures that Payload is based on. Collections are defined in code, which eliminates the need for manual clicking ("click ops"), as is the case in competitive Strapi.
  • payload-types.ts - contains all generated types needed to work with collections. The file is updated automatically and should not be edited manually.
  • payload-config.ts - the main CMS configuration file. It defines, among others, database configuration, added collections, global settings, plugins, and many other options. Due to its extensiveness, it will probably get a separate article.

The remaining files are consistent with a standard Next.js project, so I won't discuss them here. If you haven't worked with Next.js before, it's worth familiarizing yourself with its documentation first.

Basic Configuration

Opening the payload-config.ts file, we'll find the basic CMS configuration. It's worth analyzing each element carefully to later navigate this file freely and adapt it to your needs.

1// payload-config.ts
2
3// storage-adapter-import-placeholder
4import { mongooseAdapter } from '@payloadcms/db-mongodb'
5import { payloadCloudPlugin } from '@payloadcms/payload-cloud'
6import { lexicalEditor } from '@payloadcms/richtext-lexical'
7import path from 'path'
8import { buildConfig } from 'payload'
9import { fileURLToPath } from 'url'
10import sharp from 'sharp'
11
12import { Users } from './collections/Users'
13import { Media } from './collections/Media'
14
15const filename = fileURLToPath(import.meta.url)
16const dirname = path.dirname(filename)
17
18export default buildConfig({
19 admin: {
20 user: Users.slug,
21 importMap: {
22 baseDir: path.resolve(dirname),
23 },
24 },
25 collections: [Users, Media],
26 editor: lexicalEditor(),
27 secret: process.env.PAYLOAD_SECRET || '',
28 typescript: {
29 outputFile: path.resolve(dirname, 'payload-types.ts'),
30 },
31 db: mongooseAdapter({
32 url: process.env.DATABASE_URI || '',
33 }),
34 sharp,
35 plugins: [
36 payloadCloudPlugin(),
37 // storage-adapter-placeholder
38 ],
39})

Storage Adapter

The first thing that catches the eye is a comment, or rather a placeholder for the storage adapter. It's worth configuring it right at the beginning because otherwise, all photos uploaded to the CMS will be saved locally in the project folder. This isn't the best solution, especially with a larger number of files.

Payload offers several adapters for file storage ā€“ you can find more about this in the documentation. AWS S3 is definitely the most popular for self-hosted, and you can also find its configuration in the documentation.

šŸ’” Tip: The latest version of AWS S3 SDK introduced changes regarding checksums. To avoid errors, in the S3 configuration, set requestChecksumCalculation and responseChecksumValidation to "WHEN_REQUIRED".

Admin Panel

We now move to the configuration object, which in the default config starts with the admin key. It contains admin panel options, by default we have two positions configured:

  • user - specifies the collection of users who have access to the admin panel. This allows us to separate application users from administrators by creating separate collections for them. You can provide a reference to the slug field from the collection object or directly enter its slug as a string, e.g., "users".
  • importMap - Here, we have configured the base directory (baseDir) for custom components that can be used to personalize the admin panel. By default, it's the src folder, the same one where the configuration file is located. At the beginning, it's worth sticking with this option.

Collections

Configuring collections in the configuration file is very simple. Just add a reference to the collection in the collections array, and it will be automatically added to the admin panel.

After this operation, appropriate types for this collection should also be generated. However, if this doesn't happen, you can use the command pnpm generate:types. This will manually force the generation of types from collections, fields, and global settings, which you'll learn more about in subsequent articles.

Other Options

The remaining options will be described briefly, as they are neither significant nor extensive enough to require a separate section.

  • editor - here we set the default text editor for richText fields. By default, it's lexicalEditor, which we can customize and adapt to our needs. If we modify the editor, just provide a reference to our custom solution. Additionally, we can set different editors for individual fields, which gives us full flexibility. You can read more about the richText editor in the docs.
  • secret - string used by Payload for encryption, password hashing, and other security-related operations. We usually leave this option default, as changing it can lead to problems with data access if our database isn't empty.
  • typescript - TypeScript settings for Payload. In most cases, we leave this field default, but if needed, we can customize the configuration, you can read more about it here.
  • db - Database adapter, set by default when creating the project, depending on the selected option. It's worth noting that this is an external package, so if we want to change the database type, we need to install the appropriate adapter. You can read more about databases in Payload in the docs.
  • sharp - If you work with Next.js, you probably know the sharp package, which is used for image optimization. Importing it into the Payload configuration allows for photo cropping, focal point selection, and automatic resizing in the admin panel. This makes images better adapted to different sizes and quickly loaded on the page.
  • plugins - As the name suggests, we add all plugins we want to use in our application to the plugins array. Payload offers several official plugins, as well as countless community plugins that significantly extend its functionalities. The right choice of plugins will save time by eliminating the need to write your own implementations. You can find community plugins on GitHub by browsing the payload-plugin topic.

Summary

In this article, you learned how to easily install PayloadCMS, configure basic settings, and familiarize yourself with key elements of the project structure. You learned how to set up a storage adapter, customize the admin panel to your basic needs, and how to add collections. We also discussed important options in the payload-config.ts configuration file that allow for application personalization.

In the next article, we'll discuss next steps such as creating collections, user management, and configuring global settings. We'll also look at access control and permissions for different user groups.

If you want to continue learning and explore the topic of PayloadCMS, I encourage you to follow my blog,where I'll publish more articles on this topic. Additionally, on my social media profiles, I'll inform about new posts and updates related to PayloadCMS.