Skip to content
Want deep learning about Payload? Payload Essentials is for you!Enroll Now

Deploy Payload with No Cold Starts and No Surprise Bills

PayloadPayload CMS8:33 video • ~7 min readFree

Deploy Payload CMS to an always-on Node server, with a Postgres database and your media uploads on the same machine.

This post contains affiliate links. If you click on a link and make a purchase, I may receive a commission at no extra cost to you.

What's up everyone? I have thoughts about serverless infrastructure generally and Vercel specifically, but that's not what this post is about. This post is about deploying a Payload application using a service called Cloudways by Digital Ocean. First, I wanted to thank Cloudways for sponsoring this post and making it possible to show yet another server-ful method of deploying applications in a world of too much serverless infrastructure.

One of the most common questions I get asked is: "Where should I deploy my project?" It seems that a new "best" provider shows up every other day, so it can be hard to choose between options. I'm hopeful that in this walkthrough, I can equip you with the tools and knowledge about another deployment option that checks a lot of boxes for me. I will say that one thing I really like about Cloudways is that I can manage multiple client accounts within one place.

In today's post, I'll be using Cloudways' Velocity to deploy my Payload Essentials Starter repo. If you don't know what Cloudways is, it's a managed hosting platform that allows you to deploy Node.js apps very quickly. It comes with everything you'd expect from hosting software, like enterprise-grade security, but with predictable pricing.

You pay a monthly price for a server, so you don't have to be a mathematician to figure out what you're going to spend like you would for a serverless platform or completely metered option.

It has all the benefits of an always running Node server, which means no cold starts or massive bills. You can try it out for free, or get started by using my referral link.

Plans start at $20 a month, which gets you 2GB of RAM and 2 vCPUs, but you can upgrade to higher plans if you need more resources. Your database runs on the same server at no additional cost.

You can also add team members with full access to whatever servers and applications you'd like without an additional per-seat cost. So, you can host several client sites all within the same server and share only what they need to see with them or your team if you have one.

Now that all my talking points are out of the way, let's get rolling with a fresh deployment.

Getting Started

First, get signed up for a Cloudways account.

Once you're logged in, select Velocity. You can either start a free trial or get full access right away. I'll click "Start Free Trial." I should be fine on the Starter plan, so I'll leave that selected and scroll down to check my disk space. I'll leave this at 25GB. Then click Continue.

Select the region that makes the most sense for you and name your server. I'll name mine Payload Essentials. My provider is GitHub, but you may choose GitLab or Bitbucket as well. I'll click "Connect" below "Connect GitHub." In another window, I'll confirm the authorization into my account.

Once connected, I can see all of my repositories.

About the repo

The repo I'm using is in the description. If you want to follow along with this next part with that repo, be sure to clone the repo to your computer and push it to your git provider before moving forward.

For those who have gone through my Payload Essentials course, this project is going to look familiar. It's the starter project that you build in the course using Next.js and Payload. It uses Mongo DB and Cloudflare's R2 storage. The course is also on an older version, so if you're working with that repo, you'll need to update to version 3.90 or higher to address some critical vulnerabilities. We'll be using 3.90.1.

All that to say, I've updated the project to version 3.90 and changed Mongo DB to Postgres using UUIDs to keep the IDs as strings. Cloudways does not currently have managed Mongo DB as a service, but it does have Postgres, which we can use with Payload with no problems. The biggest paradigm shift in this switch is that the project now uses migrations, which we'll handle in the deployment script.

What's provided

While this project specifically is Next.js, Cloudways supports much more out of the box. You can deploy Remix, plain React, TanStack, Astro, Nuxt, Angular, and much more.

If it builds to SSR or a static bundle and starts with Node, Velocity can run it.

We also set up 25 GB of persistent volume, that means we can use local storage instead of using S3 storage. Depending on what kind of application you're running, storage can add up, however. So you might want to consider still using an external storage provider, especially if you want to use a CDN other than Cloudflare.

Cloudways provides a CDN up to 250GB of bandwidth on the Starter plan. They provide this through Cloudflare Enterprise. This is one of the few features in Cloudways that is metered, so after you hit your 250GB in bandwidth, you'll be charged 2 cents per GB after the plan's CDN bandwidth allowance.

To use their CDN with a custom domain, follow the instructions in the Cloudflare section of the platform to get started. This requires simply pointing your domain at their servers, just as you would for setting up any custom domain for any hosting provider.

If don't want to use their CDN or want to continue using S3, feel free. But as I mentioned, I've taken all of that out of this repo, so you'll need to set up the configuration, infrastructure, and input its environment variables on your own. We'll carry on the rest of this post using local storage.

Configuring Cloudways

I'll select my repo here called payload-essentials-postgres. Once you select your repo, you need to include environment variables just as you would any other hosting platform. We'll simply need our PAYLOAD_SECRET and database connection string, which we'll pick up in a little bit. For now, I'll create a Payload secret and move on. This will flash on my screen, but I'll be tearing this down after recording, so this isn't something I'm trying to protect. But you should remember to treat your Payload secret as private.

Since we're using Postgres, we need to make sure that we have a migration step in the build command. Let's change our build command from pnpm run build to include payload migrate first. Then click save changes. I'll leave the rest of the settings as they are and click "Deploy Now."

I know this application is going to fail because there is no database connection string, so there's nothing for the application to build against. We'll need to wait for the server to finish being created before we can fix that.

Setting up a database

Now that the application is done and we have a failing build for our project, we need to set up our database.

We get to that by going to the "Access Details" section of the application. You can choose between using Postgres natively or using your existing Supabase account. I'll select native Postgres and then "Proceed". Once I click this, it will automatically insert the variables into my project, but I'm only using one database environment variable, and that's DATABASE_URL. I'm going to construct that URL using the pieces provided to me in the database section under access details.

Now that the environment variable is in, I'll head back over in overview. I'll click "all deployments" next to our failed deployment. From here, we can hit "Redeploy." Now we wait for this to deploy.

Now we see we have a successful deployment, we can open it up by clicking on the "open in new tab" icon by our application name. Of course, this goes to a 404 because we need to go to our admin screen. So I'll add /admin to the end of the URL. Then I'll create a new account. Then I'll create a Home page with a picsum photo. I'll add a hero block that just says "Home" with a hero image that we'll get from picsum.photos as well. When I save the home page, I should be able to go back to the root route and see a home page with the image we uploaded.

Final Thoughts

And that's all it takes to deploy on Cloudways by Digital Ocean. In one server, we now have a dedicated Postgres database for our Payload Essentials application. With it, we have an always on Node.js server with no cold starts so our Next.js application is always fast. As part of our plan, we also have 25GB of persistent storage, so we can store all of our objects on the server as well. Optionally, you have access to an enterprise-grade CDN through Cloudflare when you set up a custom domain within the platform.

Thank you, again, to Cloudways by Digital Ocean for sponsoring this post. You can sign up for your own Cloudways account.

Keep going