In this chapter, our goal is to integrate Payload into our Next.js application. Before we go forward, I would like to confirm that you are on your main or master branch. You can do that by running git status and just confirming that everything is up to date. You can also double check by going inside of your graph and just confirm that you have everything on your main branch here, meaning you've merged the pull request, right? I just don't want you to continue developing in a branch from a previous chapter or if you're not following these git instructions no need to do anything at all so now that we have confirmed that let's go ahead and decide which database we are going to use.
So, Payload offers us these three amazing options. MongoDB, Postgres, and SQLite. In my case, I'm going to go with MongoDB. Mostly for this reason right here. MongoDB is non-relational, meaning by nature it's flexible, having a schema-less structure.
This is great for nested and relational data and specifically good for our content management system where we are gonna have collections which are going to drastically change and they are honestly gonna be different for every single use case, right? So it's just easier to work with a database which can handle so many changes quickly rather than working with a database which is going to require constant migrations. That isn't to say that you cannot use Postgres or SQLite. You absolutely can, but I'm just giving you a tip. My developer experience was absolutely the best with Mongo.
So, one more point for Mongo here goes for their free cloud hosting via Atlas. And that's what we're going to do now. Of course, if you want to, locally, you can use Docker if you're handy with it and just obtain a simple Mongo URL, but I'm going to show you how to do it using Atlas. So head to MongoDB website and go ahead and open the dashboard. Depending on if this is your new account, you might see a different screen, but basically you have to get to this screen where you're going to deploy your cluster.
Go ahead and select the free option, and you can uncheck the preload sample dataset. We are not going to need it. The provider, region, none of this matters. I think it's going to choose the one recommended for you, right? And click create deployment.
No need to add anything else. While that is creating, you can close any models that show up and go inside of your database access here. As you can see, I already have a user. You might not have a user. So just go ahead and click add a new database user, choose the password authentication method.
And I suggest you just add a very simple username and password combination for development of course and go ahead and add an atlas admin role which will simply allow this user to do anything and click add user So just confirm that you have at least one user here which we are going to use to connect to the database. Another important thing is the network access. So at the moment, only my IP address will be able to connect to this database. But for those of you who are working from different places or you have dynamic IP addresses, you might benefit from adding another IP address and clicking allow access from anywhere. Or if there is no button, just enter 0.0.0 slash zero and click Confirm.
I would not recommend using this in production, but it is definitely handy in development. That's why I'm gonna be adding it so we never get those error messages saying that we can't connect to our URL string. So by the time we did this, I think our cluster should be ready now. We can see it's still doing some final changes here and it looks like it is done. I can click Browse Collections.
In my case, it's going to be completely empty. If you added a sample data set, you might have some data here. It really does not matter. Mongo is very flexible, So we can add more data here. So leave it like this for now.
And what we have to do next is we have to integrate payload. So what is payload? So from their documentation, Payload is the Next.js full stack framework. And honestly, I couldn't agree more about this statement. It is absolutely amazing.
And with literally running a single command, this is everything that we're going to get. A full admin panel with server and client components, which is going to match our data. And we're going to be able to extend this admin panel with our own React components if we want to do that. We're also going to get automatic database schema, including direct database access and ownership, migrations, transactions, indexing, and more. And in order to access that data, Payload offers us a REST API, a GraphQL, and a straight to database Node.js APIs.
For example, we can use those in server components. We also get out of the box authentication with payload and we can use it and we will use it for our entire app. Also a very important point, it allows a deeply customizable access control pattern, which will come in handy because we are going to build a multi-tenant app, which means that we are gonna have to restrict from some users from seeing information they should not be seeing on our admin panel and a ton of other things we are going to discover as we go along. And in case you were wondering, yes, Payload is open source and we can deploy it anywhere And that's exactly what we are going to do. So we're gonna use the open source payload version and we are going to self-host it on Vercel.
That's exactly what we can do. And it is as simple as just deploying your entire app on Vercel. There's literally nothing more you have to do. It's honestly such an amazing value that you get from this. So let's go ahead and learn how to install this.
First of all, software requirements. So any JavaScript package manager, as you can see, several are mentioned here, but bun is not. That's because bun is still in their experimental testing phase, but I'm going to be using BUN. I found no issues whatsoever. This important point, Node.js version 20.9.0.
That is important because Next.js requires a lower version of 18.18. So if you had 19 and you thought, oh, okay, I don't have to update. Well, now you do. So this is the minimum version you need to have. As you can see, I barely make it.
So I'm gonna have to update this soon as well. And we already have the compatible database, so that part is solved. Make sure you have all of these requirements. So now we're going to run the Create Payload app. And before you do that, I just wanna show you the current version that I'm gonna be using which is 3.33.0.
I don't think that you have to use this exact version. I think the major version might be more important, right? Because payload 2 to payload 3 was a huge jump and a very big breaking change. But I think that these minor versions will not cause that much of a difference. But if you want to be sure, you can use the same version that I am.
One more very important thing, you need to add this to your CLI, right? Because otherwise it will fall back to PNPM. So this is what we're going to do now. And you might notice that there's no bun, but if I searched throughout their Create Payload app and I found use bun to be you know alongside all of these other options but you can see they've marked it as experimental so that's probably why they haven't added it into the readme but In case you forgot to add this, it will fall back to PNPM if you have PNPM installed. It might even give you an error if your PNPM is not up to date.
So I just want to give you that little tip. It will also create a PNPM lock file here if you don't specify your package manager. So make sure that you specify it. So what we're gonna do now is we're going to run the command, right? So I'm gonna do bunx create payload app.
And this is not enough, right? So I also have to do dash dash use bun same goes for you if you're using npx just add use npm here or if you're using yarn just add use yarn here or if you're using pnpm and pnpx you I'm pretty sure you don't have to do anything but still you add use pnpm make sure you are inside of your project here make sure the project is shut down for the moment and you can just press enter. So it detected a Next.js project and it's asking if we would like to install Payload. I'm going to select yes and looks like we have to do something first. So Payload does not support a top-level layout file in the app directory.
So what we have to do is we have to create a new route group and move all of our files into that. So they recommend using app here. So I would suggest that you read what they recommend and go inside of the app folder and create a new folder app inside of parentheses, of course, and then you are going to select everything else and move it inside. If you get prompted to update any imports, you can just say yes, right? It really doesn't matter.
So you should see about 24 changes now. Well, I mean, if you've been following, you should see exactly 24 changes, except if you didn't add these routes, right? Maybe you didn't do that. But you should see something like this. And before you do anything else, I suggest that you do bun run dev, just to confirm that your app is exactly as it should be.
Right? So nothing should change. You should still have your nav bar and your footer, which is what we did in the previous chapter. And then we merged that into main or master branch, correct? So after you have confirmed that everything is working fine, you can go ahead and run this command again.
Just make sure you add your package manager here, otherwise it will fall back to using pnpn. So let's go ahead and install payload. And now we have to select a database. So I will select MongoDB. And as you can see right here it offers you a local string but since we already created our cluster I'm going to go ahead and click connect.
There are many options you can use but I'm going to click this MongoDB for VS Code and I will just copy this. I will remove this, and then I'm going to paste it here. I am now gonna go ahead and replace my password and my username. So I've created some Simple accounts, Antonio with a password of Antonio. So it's for this convenience, right?
And you can also, I think you actually should go to the end of this slash and add the name of your database. So e-commerce like this. As you can see, it's using BUN and it says BUN support is untested. So this is kind of a confirmation that it is using BUN. And there we go.
Payload project successfully initialized. And let's go ahead and see what actually happened here. So you can see that instead of my app folder, I now have a front-end folder, a payload folder, and my route folder. Outside of the app folder, I now have collections. I also have payload types and payload config.
And what I wanted to confirm is that it used my bun lock, right? So if you would not have specified use bun, it will fall back to pnpm. And if you have pnpm installed, it would have added a pnpm lock file here, which just doesn't make sense, you know, because we want to use our current package manager, no point in using two of them in a single repository, right? So now that we have that, what happens if you try running your app? Well, I will tell you immediately, while this works, you will get an error if you refresh your homepage.
The reason you're getting an error is because Payload added this frontend and it added a page and a layout. So now you have two layouts, right? And two pages. So here's what I want you to do. I want you to double check that inside of your app folder, inside of your layout here, you have the dmsans import.
Just because this will confirm to you that this is your old layout, which we worked on. And inside of your home, confirm that you have the page.tsx with the IMA button text and the checkbox and the text area and the progress. I just want you to confirm that all of that is inside of your app, inside of the app. And now you can safely remove the frontend. The reason I'm asking you to check this is because, you know, sometimes people go ahead and do their own thing here.
And here, when I told you to move your things to an app directory, maybe there's a chance someone actually renamed it to frontend, and then Payload would technically override that folder. So that's why I wanted to confirm with you that everything is working. So now, if you go ahead and do bun run dev again, I would suggest you shut down your app and restart it. Let's refresh again, and there we go. Everything is working.
So what's new? Well, If you go to localhost 3000 slash admin, which I'm going to show you here. So this is the route localhost 3000 slash admin, go here. You will notice, Yeah, you might get an error here. It is possible.
So keep your eye on the terminal. If everything is loading fine, this basically means that your MongoDB is successfully connected. So you can check inside of your .environment here, you can see added by payload, this is our MongoDB connection, Antonio at Antonio with e-commerce here, right? So if you got an error here, it could say that it failed to connect to MongoDB. That would mean that you have provided it with an incorrect database URL.
Easy fix. Just go ahead here and double check. Click connect, obtain this string, go inside of your database access, create a new user if needed, confirm they have the roles necessary, and confirm that you have the 0.0.0 inside of your network access. And after you do that, paste the new string here and rerun your app. And now you will be greeted to this page where you have to create your first user.
So I'm going to use admindemo.com with a password of demo and confirm password of demo. And I will click create. And as you can see here, we have a fully fledged CMS here. I can go ahead and look into my users. I can go ahead and create a new user if I want to.
Same goes with media. I can upload a new file. So how do we work with Payload? Let's go ahead and explore some things that were added here. So I'm going to shut this down now.
If you're curious about this Payload app here, You can feel free to open it and click on a file inside. And the first thing you'll probably notice is a big comment here, which says, this file was generated automatically by the Payload. Do not modify it because it could be rewritten at any time. So yes, you are not going to touch this ever. You can look at it, but it makes no sense changing anything inside.
Besides that, you have a MyRoute, which is just a handy example of how to fetch something from Payload, specifically the users collection. And now you also have the collections folder. In here, we have two familiar resources, users and media. So that's exactly what you're seeing here. You can see that this one is very simple and a very important field here, ALF is set to true.
You're gonna see what that means in a second and you can probably guess what it means, right? We also have the media field here. So the best way to learn about these collections is to try and create one of your own. So if you go ahead inside of here and create categories, for example, and you can just leave it like this for now. Don't do anything yet.
Let's go ahead and try this MyRoute. So even if you don't have or accidentally deleted this MyRoute, it doesn't matter. We're just gonna try something. So I'm gonna go ahead and go to localhost 3000 slash my-route. So this is how it looks like, my-route.
And if I click here, it's just going to return a JSON with all of my users, right? Admin at demo.com, right? So What I want to try now is the following. I want to go back inside of my collections, categories, and I'm just going to import this. And then I'm going to export categories, collection config, and give it a slug of categories and then give it fields, which is an array of objects.
A name of this field will be name and the type can be all of these things, but we're going to keep it simple with text. And let's also add a required rule. So what happens now? We just added the categories collection, right? But if you visit your admin dashboard, you are going to notice that it's not here.
So how do you connect it? And besides noticing that it's not here, if you try and go inside of my route or you can just watch me try it, if I try and load the categories collection, you can see that I'm getting an error here. Categories does not exist here. So what we have to do is we have to go inside of the payload.config.ts and you can also quickly visit payload types here. Search for categories.
They are nowhere to be found. But the moment we go ahead and import categories from collections categories and then add them to the collections array here and save, what's going to happen now is that it's going to be generating a new import map. It's going to be generating new types automatically. And you can see that my route is all of a sudden no longer a problem. Right now, you can see that you actually have categories.
And if you go inside of your payload types and search for categories, you will see that they are now generated, right? But in case this did not happen for you, if you still can see it in your types, it is possible for that to happen. Don't worry, I got you. I just want to first show you that now categories should appear in your admin and you should be able to create a new category and you should be able to see them right here. So in case your payload types have not generated, this can happen if you have a lot of things running on your machine or you might have a bit of an older machine, a bit of a slower machine, that's completely fine.
What you can do here is you can manually run generating types here using payload generate types. So the way I'm going to do this is by going inside of my package json and adding a script generate types and just add this. There we go. Because if you want to use it standalone, right, If you just try doing this, it's not gonna work. So you have to prefix it with bunx.
Or you can just add generate types and then you can do bun run generate types like this. And this will force Payload to generate the new types file. So by now you should definitely have categories. So this is our introduction to payload, right? You can already see how powerful it is just from this few lines of code that we did.
So what I want to do now is I want to copy these two things and just try and load some things inside of my UI. So I'm going inside of source app folder, home, page.tsx. If you don't have use client at the top this means that this is a server component. So let's mark this as an asynchronous file. Let's remove all of these imports and let's replace them with config promise from payload config and payload.
Make sure to not forget an at sign here. And let's go ahead and remove everything here besides a little div here. And now what we're going to do is the same thing that's happening in this route. We are first going to establish the payload using get payload and passing in a config promise. And then we're going to go ahead and load data.
So this is a perfect way to load data in server components. This is the direct to database Node.js API that we've mentioned in the beginning. And now what you can do here is just do JSON stringify data null 2. Basically, these two things will make it look prettier in a JSON. And now if you go to localhost 3000, If you want to, you can open two apps, localhost 3000.
And let me just combine this two like this. So let me wait a second for this to load. And there we go. And you can see that if I go ahead and add a new category, for example, it will add a new category, it will load a new category here, something new, and let's click save. Let's wait for this to submit.
And the next time the user visits, there we go, we now have something new. And we have the test category, You can see the pagination is built in into this API. So it's going to make it super easy for us to build infinite load and all the other things like that. So yeah, I'm absolutely amazed by this. And one cool thing that you can also do and try it out, which we are later going to do a bit more heavily, inside of your collections, try and add an axis object here.
For example, create can be completely set to false, so it can update, like this. And now, if you go inside of categories, you can see that there's no longer the create button. You can no longer see them. You can see that all of these have the plus button, but categories doesn't. It's because we've set it to false.
Later on, we will be able to destructure the request from here, and then we would check if request.user, and then we would probably add some other field like isAdmin, right? Something like that. So only admins will be able to create that. So that's just a pseudocode example, but that's how we're gonna work with access control here. So I think that this is a pretty good introduction to Next.js, to Payload, and I think it's a perfect time to end the chapter so you can digest this information and play around a bit for yourself.
So let's just confirm here we have integrated payload. Well, Oh yeah, we didn't verify the data in the database. So yeah, if you want to, you can just go inside of your clusters here, browse collections, and you should see your dot environment here. We have added slash e-commerce at the end. So you should be able to find your data inside of the e-commerce here.
And there we go. You can see we have the categories with test and something new and users. And users also have salt and hash, meaning this is fully prepared for Auth. Great. So we definitely confirmed that as well.
Now we have to push this to GitHub. So let's go ahead and do it. 04 payload integration. So what I'm gonna do is git checkout-b 04 payload integration like this. So I'm now in a new branch.
I'm gonna add everything. I'm going to commit 04 payload integration. You can of course be more descriptive here and then git push u origin 04 payload integration, like this. There we go. So this is how my graph looks like now.
You can see that I'm on a new branch. You can see that I'm on a new branch here. So let's go ahead inside of our e-commerce here. There we go. You will probably get a prompt here, but as always, if there is no prompt, you can click new pull request and click on 0 for payload integration here and create a pull request.
So I'm going to create that pull request. And as always, we're going to have a peek at what CodeRabbit has to say. In the previous chapter, it caught a very important bug. So I think it's going to be interesting to see what is going to detect from all of these files right here. And here we go, we have a summary by CodeRabbit.
So we have some new features and we have some chores. And as you can see, it gave us an extremely thorough walkthrough of all the changes we did. So the changes integrate enhanced payload CMS functionality throughout the project. It also detected that we added the REST API and GraphQL handlers, which is something that Payload added for us. It went over each file individually and gave a summary of what happened there.
And it also created the sequence diagrams for us to understand exactly how we are fetching our data. So if you remember in our home component here, right, let's go to page, you can see that we fetch the categories and display them. So it detected that and it actually created a sequence diagram for us to understand how that is happening. So I find that absolutely amazing. And it also wrote some refactor suggestions.
So we know that we just did this as mock files, as initial data, but you can see that it suggests a refactor to enhance this with access, to add some groups here, some more fields. So I think that's very impressive. And it also found some other suggested changes throughout our code. Since we were using these files as just you know, testing data, we don't need to resolve any of them. I've checked, none of them are bugs as it was in previous pull requests, but still, I just find this so impressive.
I think it's a really nice summary for us to understand what we just did here. Great! So now what I'm going to do is merge the pull request and I am not going to delete the branch. So now If I go here, there we go. This is the master now.
So what you should do now is get checkout master or main, depending on what you use, and then get pull origin master or main again. Let's just wait a second. There we go. So all of those changes here. Let's run get status, confirm that we are on origin master.
As you can see, I still have all the files here and you can see exactly what happened. We branched out to do a payload integration and we merged it back to master if you want a sanity check you can go ahead to localhost 3000 here and you can go to slash admin just to confirm that you still have payload, but this should already tell you that payload is here. But there we go, just go to slash admin and it will start compiling the admin. Perfect. So Let me go ahead and mark this as complete as well.
Great, that's it for payload integration. Amazing, amazing job and see you in the next chapter.