Deployment guide

Deploying a Payload CMS application on a VPS

Deploy on a VPS Cloud →

Development9 min read

Deploying a Payload CMS application on a VPS

Payload CMS is a TypeScript-first headless CMS that integrates natively into Next.js. Self-hosting it on a VPS gives you a unified code-first stack, where the CMS and the front end share the same runtime. Here is how to deploy it in production, with its database and a comparison against Strapi.

Why self-host Payload CMS on a VPS

Payload CMS takes a radically code-first approach: your content schema is defined in TypeScript in configuration files, versioned with Git, and since its version 3 Payload installs directly into a Next.js application via the App Router. This means a VPS lets you host the CMS and the front-end site in a single Node process, sharing the build and the runtime. You get end-to-end typing, schema migrations managed in code, and no dependency on a graphical interface to model your content. Self-hosting is the natural option here: Payload is designed to be deployed like any Next.js app, and a VPS gives you control of the database (MongoDB or PostgreSQL), the uploads and the environment variables, without an intermediary platform.

Concrete benefits

  • Content schema defined in TypeScript and versioned with Git: full code review and history
  • CMS and Next.js front end in a single runtime: one build, one process to deploy
  • End-to-end typing between the Payload config, the API and the front end, without manual generation
  • Choice of database: MongoDB or PostgreSQL via the official adapters
  • Schema migrations driven by code (payload migrate), reproducible across environments
  • Local API: direct data access without an HTTP call from Next.js server code

Hardware and software prerequisites

Since Payload relies on Next.js, the build is demanding: plan for a VPS with 2 vCPU and 4 GB of RAM to build and run the application comfortably, especially if the Next.js front end is substantial. Install Node.js 20 LTS, Docker and Docker Compose. On the database side, provision MongoDB 7 or PostgreSQL 16 depending on the chosen adapter (@payloadcms/db-mongodb or @payloadcms/db-postgres). Point your domain at the VPS IP. Count 15 GB of disk for the node_modules, the .next build, the uploads and the database backups.

Step-by-step deployment

01

Choose and configure the database adapter

In payload.config.ts, declare the adapter: mongooseAdapter for MongoDB or postgresAdapter for PostgreSQL, reading the connection URL from DATABASE_URI. This choice is structural: PostgreSQL requires migrations, MongoDB is more flexible on the schema.

02

Set the secret and build the Next.js app

Set PAYLOAD_SECRET (the token encryption key) in the environment. Run npm run build: since Payload 3 lives inside Next.js, this command compiles both the Payload admin and your front end. Watch the RAM during the build.

03

Containerize with Docker Compose

Create a node:20-alpine Dockerfile that builds the app and runs npm start, then a docker-compose.yml linking the app service to a mongo or postgres service. Mount a volume for the uploads and pass DATABASE_URI and PAYLOAD_SECRET as variables. Run docker compose up -d.

04

Run the migrations (PostgreSQL)

If you use the PostgreSQL adapter, apply the schema with npm run payload migrate after the containers start. With MongoDB, the schema is applied automatically, no manual migration is needed.

05

Configure Nginx as a reverse proxy

Point a vhost to http://127.0.0.1:3000 (Next.js default port). Increase client_max_body_size for media uploads and add the X-Forwarded-Proto headers so that Payload generates correct HTTPS URLs.

06

Secure with SSL and set the server URL

Run certbot --nginx -d mydomain.com, then set serverURL: 'https://mydomain.com' in payload.config.ts. This URL conditions the media links, the reset emails and the correct operation of the admin panel behind the proxy.

Payload CMS vs Strapi: which headless CMS to self-host?

CriterionPayload CMSStrapi
Configuration approachCode-first in TypeScript, versioned with GitGUI-first via the Content-Type Builder
Front-end integrationNative in Next.js (a single runtime)Decoupled, front end and CMS separate
Supported databasesMongoDB and PostgreSQLPostgreSQL, MySQL, SQLite
TypingNative end-to-end TypeScriptGenerated types, looser integration
Server data accessLocal API without an HTTP callREST/GraphQL API via HTTP
Content modelingIn the code, by developersIn the interface, accessible to non-developers
RAM needed for the buildHigh (Next.js build)High (React admin build)
Ideal forDev teams, typed Next.js projectsMixed teams, visual modeling

Leverage Payload's Local API in your Next.js server components: instead of calling your own API via fetch, import getPayload and query the database directly (payload.find({ collection: 'posts' })). You remove an HTTP round-trip and gain in latency as well as in security. For media, plug in the @payloadcms/storage-s3 plugin to store uploads off the VPS, and automate a daily dump of your database via a cron to guarantee off-server backups.

Deploy Payload CMS on a unified stack

The ServOrbit Cloud VPS offers the power needed for Payload's Next.js build and a Docker environment ready for MongoDB or PostgreSQL, to host your code-first CMS and your front end on the same machine.

Need help?

Browse our help center and FAQ, or write to our team — support in French, English and Arabic.