Deploying a Next.js application with Prisma and PostgreSQL to your own VPS means coordinating several moving parts: building the app, generating Prisma Client, running PostgreSQL, applying production migrations, connecting both containers, setting up a reverse proxy, and enabling HTTPS.
This guide shows how to deploy that stack with QuickDeploy. The final setup connects Next.js and PostgreSQL through QuickDeploy's shared Docker network, persists the database on the server, and publishes only the web application through your domain. PostgreSQL is not published as a host port. The same service pattern also works for other full-stack applications that read their database connection from an environment variable.
If you want to understand the underlying container and reverse-proxy steps first, read the Docker VPS deployment guide.
What You Will Deploy
The deployment contains:
- Your Next.js or other full-stack application in a Docker container.
- PostgreSQL in a separate Docker container.
- QuickDeploy's shared Docker network connecting the application and database.
- A persistent directory for PostgreSQL data.
- Caddy as the HTTPS reverse proxy for your domain.
QuickDeploy creates and manages these resources on your VPS. You still own the server, Docker configuration, application, and data.
Prerequisites
Before starting, make sure you have:
- An Ubuntu-based VPS with Docker and Docker Compose installed.
- A domain or subdomain with an A record pointing to the VPS.
- QuickDeploy installed and configured.
- A Next.js or other full-stack application that can read its database connection from an environment variable.
- A production start command for the application.
If your server is not ready yet, follow the Linux VPS setup guide.
Verify The Fit Before Buying
You can check the local tool and your server before purchasing a license:
- Compare your computer, Ubuntu-based VPS, application, database, and domain with the compatibility matrix.
- Install QuickDeploy for your platform and run
quickdeploy --version. This local check does not require a license or connect to your server. - Run the server verification command in the requirements guide to confirm that the SSH user can reach Docker and Docker Compose without an interactive
sudoprompt.
If those checks pass and your application reads DATABASE_URL from the environment, return to the deployment command below. A license is required when you configure QuickDeploy and deploy, not for the local version check.
Choose A Project Name
QuickDeploy uses the project name to keep related containers and data together. This guide uses myapp.
The PostgreSQL container will therefore be reachable inside Docker as:
myapp-postgres
Use the same project name for future deployments so QuickDeploy updates the existing application instead of creating another project.
Configure The Database Connection
Create a .env.production file in your application root. QuickDeploy includes this file when building the app and makes it available to the running container.
DATABASE_URL=postgresql://quickdeploy_app:YOUR_RANDOM_PASSWORD@myapp-postgres:5432/quickdeploy_app
Replace YOUR_RANDOM_PASSWORD with a long, unique hexadecimal password. A 64-character value is a good default; on macOS or Linux, you can generate one with:
openssl rand -hex 32
Use the exact same value in the deployment command below. Hexadecimal output avoids shell-sensitive characters when QuickDeploy forwards the deployment flags over SSH.
The database hostname is myapp-postgres, not localhost. The app and database run in separate containers, so localhost inside the application container refers only to the application container itself.
Do not commit .env.production to Git. Add it to .gitignore if it is not already ignored:
.env.production
Check The Application Port
QuickDeploy needs to know which port the application listens on inside its container. For example, a typical Next.js application listens on port 3000.
Make sure the application listens on 0.0.0.0, not only 127.0.0.1. A custom Nixpacks start command can be configured in nixpacks.toml when framework detection does not choose the correct command:
[phases.build]
cmds = ["npm run build"]
[start]
cmd = "npm run start"
See the runtime configuration documentation for more information.
Deploy The App And PostgreSQL
From the application directory, run:
quickdeploy push \
--domain app.example.com \
--project myapp \
--port 3000 \
--db postgres \
--db-port 5432 \
--db-user quickdeploy_app \
--db-password 'YOUR_RANDOM_PASSWORD' \
--db-name quickdeploy_app
Change:
app.example.comto your domain.3000to the port used by your application.YOUR_RANDOM_PASSWORDto the password from.env.production.
QuickDeploy uploads the project, builds the application image on the VPS, creates PostgreSQL when it does not already exist, starts the containers, checks that the application container remains running, and configures Caddy for the domain.
Verify The Deployment
Open your domain after the command finishes:
https://app.example.com
HTTPS certificate provisioning can take a short moment during the first deployment.
QuickDeploy's container check is process-based; it does not request an HTTP health endpoint. After deployment, verify the public URL and an application route that reads from PostgreSQL.
If the application starts but cannot reach PostgreSQL, check these common causes:
- The project name in the command must match the hostname in
DATABASE_URL. - The database user, password, and database name must match in both places.
- The application must use
myapp-postgres, notlocalhost, as its database host. - The application must listen on the port passed through
--port.
You can inspect the project containers on the server with:
docker compose -f ~/myapp/docker-compose.yml ps
Deploy Next.js With Prisma And PostgreSQL
For a Next.js application using Prisma, the same DATABASE_URL configuration applies: Prisma must connect to myapp-postgres, not localhost, when the application runs inside its container.
Make sure Prisma Client is generated when the application dependencies are installed. If your build does not already do this, add a post-install script to package.json:
{
"scripts": {
"postinstall": "prisma generate"
}
}
Do not access PostgreSQL while building the application image unless the build has an explicitly reachable database. PostgreSQL starts as a deployment service, so database-dependent work should normally happen at runtime rather than during npm run build.
After PostgreSQL is running, apply committed Prisma migrations with the production command:
npx prisma migrate deploy
Use prisma migrate deploy, not prisma migrate dev, on the VPS. You can include the production command in an idempotent release or start process, or run it once inside the active application container after deployment. QuickDeploy creates and connects the services, but it does not run application-specific migrations for you. See Prisma's production migration guidance before choosing the process for your application.
Run Other Database Migrations
Applications using Django, Rails, Laravel, or another migration system also need to apply their production migrations.
The safest approach depends on the framework. You can include the migration in your production start process when it is safe to run repeatedly, or execute it in the active application container after deployment.
Always back up production data before running a destructive migration.
Deploy Updates
Use the same command when shipping a new version. QuickDeploy builds the new application container, checks that it stays running, switches Caddy to it, and then removes the previous application container.
The PostgreSQL service and its data directory remain part of the project instead of being recreated for every application update.
Back Up PostgreSQL
QuickDeploy stores the PostgreSQL data below the project directory on your VPS:
~/myapp/data/postgres
Application deployment does not replace this directory. You should still create regular off-server backups. Also back up the database before removing the project, because removing a deployment can delete its project files and database data.
PostgreSQL On A VPS: Production FAQ
Can I Deploy A Next.js App With Prisma And PostgreSQL?
Yes. The application needs a working production build and start command, must listen on 0.0.0.0, and must use a DATABASE_URL whose hostname is myapp-postgres. Run prisma migrate deploy after PostgreSQL starts; QuickDeploy does not run Prisma migrations for the application.
Can The Application And PostgreSQL Run On The Same VPS?
Yes. A single VPS is a practical starting point for small applications and teams that value a simple deployment and direct infrastructure control. The application and database still run in separate Docker containers, but they share the server's CPU, memory, disk, and failure domain. Monitor those resources as usage grows.
Is PostgreSQL Exposed To The Public Internet?
Not by the generated QuickDeploy configuration. PostgreSQL exposes port 5432 only to containers on the shared Docker network; it does not publish that port on the VPS host. Your application connects to the internal hostname myapp-postgres, while Caddy publishes only the web application through HTTPS.
This network isolation does not replace normal server maintenance. Keep Docker, PostgreSQL, and the operating system updated, and restrict administrative access to the VPS.
Where Does The Database Data Persist?
PostgreSQL writes to ~/myapp/data/postgres on the VPS. Re-deploying the application with the same project name preserves that directory and reuses the existing database service.
What Happens To PostgreSQL During An Application Update?
QuickDeploy starts the new application container and checks that its process remains running before switching traffic. It does not recreate an existing PostgreSQL service during that application update, so the database and its persistent directory stay in place. Verify the public application after each deployment because this process check does not call an HTTP endpoint.
Does QuickDeploy Back Up PostgreSQL Automatically?
No. QuickDeploy persists the database on the VPS, but backup scheduling and recovery testing remain your responsibility. Keep regular backups outside the VPS so a server or disk failure does not remove the application and its only backup together.
When Should I Use A Managed Database Instead?
Use a managed PostgreSQL service or a separate database server when you need features such as managed backups and point-in-time recovery, automated failover, stricter compliance controls, independent scaling, or stronger failure isolation. A database on the application VPS is a better fit when simplicity, cost control, and infrastructure ownership matter more and you are prepared to operate monitoring and backups.
Deploy Without Giving Up Your Server
This setup gives you a conventional Docker and PostgreSQL deployment without requiring a hosted application platform. You can inspect the generated Compose file, connect other services, move the project, or manage the containers yourself.
QuickDeploy packages the repetitive deployment steps into one command while keeping the application and data on infrastructure you control.
Get QuickDeploy and deploy your Next.js and PostgreSQL stack.