The Code-First Advantage of Payload CMS
What I really like about Payload CMS is that everything is done through code. You don't have to go around clicking in the admin UI to set up things like you would in WordPress, Strapi, or even Directus. You just configure everything directly in code and use the admin UI to add data to your app.
Being a developer, this is really appealing to me. It has a great developer experience, but the end users don't need to know anything about coding to add new data to the CMS easily. Let me show you how it works.
Setting Up Your MongoDB Database
First of all, you need to set up MongoDB to be able to use Payload. This is very easy and there are a few options. For this demo, I'm going to be using a Docker instance of MongoDB. If you want to set up MongoDB that way, you could follow along with this tutorial.
Another way is to visit MongoDB docs and follow instructions there to install it on the system of your choice. And the third and probably the easiest way is to sign up for MongoDB Atlas and use their free tier to set up your DB, and then use that during the Payload setup. All the links for MongoDB setup will be in the description below.
Creating a New Payload Project
Once you install MongoDB, go to your terminal and run npx create-payload-app. Just be sure that you have Node.js version 10 or above running on your system. Now give it a name. I will call mine payload-movies since we are going to create a standard demo that I always use for these types of videos, a kind of a movie database.
For project template, I'm going to choose a Blog so that we have some collections and fields right away. And then later, we are of course going to add our own collections of fields to create a movie database type of site.
Now, you need to enter your MongoDB connection. For me, it's going to be root:root@localhost:27017 since I'm using the Docker setup. For you, it may be something a bit different. Wait a bit for project dependencies to be installed, and then just cd into the payload-movies directory and run npm run dev or yarn dev if you're using Yarn.
You should get a URL to the Payload admin, which will usually be localhost:3000/admin. Go to that address in your browser. You will be greeted by a welcome screen and be prompted to add the first user. Add your data here and click the Create button.
A Tour of the Admin Interface
The admin interface for Payload is very simple. You have access to collections which were created during Payload installation. These collections work the same way like in Directus; they are just collections of a specific data items. Since we opted for a blog site during payload installation, we get some standard ones like Posts, Categories, and Tags. Of course, you also have Users for user management and Media for media management.
When you click on any collection, you can create an item in that collection and then fill in the data in the fields assigned to that collection—also all very, very similar to Directus. Once you create a new item, you can check out the API response for it by clicking on the API URL link.
Now, this all looks very minimal, but don't confuse minimal with the lack of options or features. Remember, in Payload, you set up everything through code, so you can make it as complex or feature-full as you like. Because the admin interface is not for you, the developer, it's made for editors and non-technical users. And they need the UI to be as simple as possible for adding content to the site without much friction.
And if you need some custom features in the admin UI, you can easily achieve that by adding in your own custom React components, using provided React Hooks, and by customizing the CSS. So, even the admin interface is very extensible. Maybe I'll show you how to do that in some other video. For this video, let's try to cover the basics of creating collections and fields. And I'm also going to show you how to create data relations and how to add some custom functionality to your fields.
Defining Your First Collection in Code
Now open your code editor and let's get to work. Go to the src directory and then to collections and create a file called actors.ts. Payload uses TypeScript, which is great because you are going to get a lot of code hints and autocomplete options in your editor so that you can work much faster.
First, we are going to import CollectionConfig from payload/types so that we have typings for our collection. Then we define our Actors collection with CollectionConfig type. And then we are going to define a slug for our collection, useAsTitle which is going to be the title of the item in the collection that is going to be displayed in lists and on the item page. For now, I'm going to set it to be firstName, because we are going to create a field called firstName for actors.
After that, we are going to set access to read so this can be read by anyone. In Payload, you can have very granular control over who can read what, but we will not cover that in this video.
I will now add two fields: firstName and lastName. Defining fields in Payload is very intuitive. You just define name, type, and label for the field. For some fields, it can get a bit more complex, but not by much. I will show you that a bit later. Lastly, I will just add the timestamps property to be false.
Now just export your collection and we are done with the actors.ts file for now. One last thing we need to do is to register Actors in the payload.config.ts file. First, we just import Actors, then you just add Actors to the collections array, and that's it.
Enhancing Collections with Field Hooks
Go to the admin in your browser and refresh the page. You should see the Actors collection show up in the UI. Click on it and try adding an actor, Robert De Niro for example, and click save. Okay, so this works, but what I don't like is that the title of the actor is just 'Robert' without the last name. So let's try to fix that.
Go to the actors.ts file and import the FieldHook type. Then we are going to create a function that is going to return the value of the firstName and lastName fields. I'm going to call this function populateFullTitle. Now we add a new field called fullName and hide it in the admin UI, and then we use a beforeValidate hook to populate this field automatically with the populateFullTitle function we just created.
We must not forget to set the property useAsTitle to be fullName instead of firstName.
Building Relationships Between Collections
Go to the browser, refresh, and save Robert De Niro again. Also, let's try adding one more actor, Brad Pitt this time. The name won't be filling up as you type, but it will populate first and last name once you hit save. So this is great.
Now, let's add a Movies collection. In the collections directory add a file called movies.ts, and we follow the same pattern like we did for the Actors collection. We are going to use the title field for our useAsTitle property. I'm going to add two fields here: title and date for now. Take note that the date field has the type of date. This is going to give us a nice date widget in the admin UI.
Now we want to add two more fields: actors for choosing the actors in the movie, and also poster for the movie poster. Since we want to add the actors from our Actors collection, the actors field is going to be of type relationship. For this type of field to work, we also need to define what collection this field relates to. This is super easy, just add a property called relationTo and put actors as the value.
Since a movie can have many actors, we are going to set a hasMany property to be true. We also want to create new actors from this field in the admin UI, so we are going to set an admin.allowCreate property to true. We need to set up one more field for the movie poster. This field is going to be of type upload. And for upload fields, you also need to set a relation just like for a relationship field type. I'm going to set relationTo property to be media so that we can upload new media, but also use already existing media.
Save this and we are done with the Movies collection.
Creating Content and Testing the API
Only thing left to do is to register it in payload.config.ts file. Now let's test it out in the browser. Refresh the admin UI and you should get a Movies collection. Create a new movie. Movie title is going to be 'Goodfellas'. I'm going to set the release date to be January 1st, 1990. And now we can select actors. I'm going to choose Robert De Niro. And since we enabled creating actors from this page, I'm also going to add Joe Pesci by clicking on the plus button. Add Joe Pesci and click save.
And for the movie poster, I'm going to upload new media and the poster for Goodfellas. Then click save, and then save again to save the movie. And that is it. We can check out the API response by clicking on the API URL.
Final Thoughts and Next Steps
I must say, Payload is pretty nice. It has a nice developer experience and is very easy to use for the editors. And since you can do everything in code, you can easily share your code through Git with your team or other developers you're working with.
This has been only a taste of what Payload can do, and I will for sure make a few more videos about it since I find it very enjoyable to work with. And as always, don't forget to read the docs if you want to get your hands dirty with it.
Anyway, this has been it for this video. Everything we did here will be available for you on GitHub. The link will be in the description below. Thank you guys for watching and I will see you in the next one.