Vercel made deploying Next.js trivially easy. Push to main, get a preview URL, merge, and your production site updates. That workflow is genuinely great. The problem starts when your app gets traction and the invoices arrive.
Vercel Pro costs $20/month per team member. That gets you 6,000 build minutes, 1TB bandwidth, 1M serverless function invocations, and 5,000 image optimizations. Go past any of those limits and the overages add up fast: $0.01 per additional build minute, $0.15 per GB of bandwidth past the included 1TB, $0.60 per 1,000 additional image optimizations. For a Next.js app with ISR pages, moderate traffic, and a few hundred optimized images, crossing those ceilings is not a matter of if but when.
The alternative is not to give up the git-push-deploy workflow. It is to run it on infrastructure you control. Dokploy gives you the same experience -- connect a GitHub repo, push code, get automatic builds and deployments -- on your own server. This guide walks through the complete process of deploying a production Next.js application with Dokploy on a MassiveGRID VPS.
What You Need
The infrastructure requirements depend on what stage your project is in. Next.js builds are CPU-intensive operations. Server-side rendering, Incremental Static Regeneration, and the built-in image optimization API all consume CPU cycles at build time and runtime. This makes the ability to scale CPU independently from other resources particularly useful.
- Getting started or staging: A Cloud VPS with 2 vCPUs and 4GB RAM handles most Next.js apps comfortably. Shared vCPU resources are fine when you are not running builds continuously.
- Production with traffic: A Dedicated VPS gives you dedicated CPU cores. Next.js SSR under load is CPU-bound -- dedicated cores eliminate the noisy-neighbor problem and give you consistent response times during traffic spikes.
- Production SaaS: Managed Cloud Dedicated Servers add high availability and managed operations on top of dedicated resources.
You will also need a domain name pointed at your server and a GitHub (or GitLab/Bitbucket) account with your Next.js repository. If you have not yet installed Dokploy, follow the installation guide first -- it takes under 15 minutes.
Connecting Your GitHub Repository
Once Dokploy is running, log into the dashboard at your server's IP on port 3000 (or your configured domain). The deployment process starts by creating a new project.
- Click Create Project from the dashboard. Give it a name that matches your app (e.g., "my-nextjs-app").
- Inside the project, click Create Service and select Application.
- Choose GitHub as the provider. If this is your first time, you will need to install the Dokploy GitHub App on your account or organization. This grants Dokploy read access to your repositories.
- Select the repository and branch you want to deploy. For most setups, this is
mainorproduction. - Enable Auto Deploy if you want pushes to that branch to trigger automatic builds -- this is the equivalent of Vercel's git integration.
At this point, Dokploy knows where your code lives and will listen for pushes. But it does not yet know how to build your Next.js app.
Configuring Build Settings
Dokploy supports two build strategies: Nixpacks (auto-detection) and Dockerfile (manual control). For most Next.js apps, Nixpacks works out of the box -- it detects the package.json, installs dependencies, and runs npm run build. But for production deployments, a custom Dockerfile gives you more control over caching, multi-stage builds, and the final image size.
Using Nixpacks (Quick Start)
Select Nixpacks as the build type. Dokploy will auto-detect your Next.js project. Set the following:
- Build Command:
npm run build(orpnpm buildif using pnpm) - Start Command:
npm run start - Port:
3000(Next.js default)
Environment Variables
Navigate to the Environment tab in your service settings. Add all the environment variables your app needs. Common ones for Next.js:
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
NEXT_PUBLIC_SITE_URL=https://yourdomain.com
NEXTAUTH_SECRET=your-secret-here
NEXTAUTH_URL=https://yourdomain.com
NODE_ENV=production
Variables prefixed with NEXT_PUBLIC_ are embedded at build time, so changing them requires a rebuild. Server-only variables (like DATABASE_URL) are available at runtime only.
Setting Up Your Domain and SSL
Dokploy uses Traefik as its reverse proxy, which handles SSL certificate provisioning automatically through Let's Encrypt.
- In your service settings, go to the Domains tab.
- Click Add Domain and enter your domain (e.g.,
app.yourdomain.com). - Enable HTTPS -- Traefik will request and auto-renew a Let's Encrypt certificate.
- On your DNS provider, create an A record pointing your domain to your server's IP address.
DNS propagation typically takes a few minutes. Once complete, your Next.js app will be accessible over HTTPS at your custom domain. Traefik handles the HTTP-to-HTTPS redirect automatically.
Adding a PostgreSQL Database
Most production Next.js apps need a database. Dokploy can provision PostgreSQL directly alongside your app, eliminating the need for an external database service.
- In your project, click Create Service and select Database.
- Choose PostgreSQL, give it a name, and set a strong password.
- Dokploy will create the database container and expose an internal connection URL.
- Copy the internal URL and add it as the
DATABASE_URLenvironment variable in your Next.js service.
Prisma or Drizzle Setup
If you are using Prisma, add a build step to run migrations automatically. In your Nixpacks config or Dockerfile, ensure npx prisma migrate deploy runs before the app starts. You can set this in the Build Command field:
npx prisma migrate deploy && npm run build
For Drizzle, the equivalent is npx drizzle-kit migrate before the build step. Both ORMs will use the DATABASE_URL environment variable to connect.
Performance Optimization
A default Next.js deployment works, but production apps benefit from a few specific optimizations that reduce build times, image sizes, and memory usage.
Standalone Output Mode
Add the output: 'standalone' option to your next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
}
module.exports = nextConfig
This tells Next.js to produce a self-contained build that includes only the dependencies your app actually uses. The resulting .next/standalone directory contains a minimal Node.js server. Without this, your Docker image includes the entire node_modules directory -- often hundreds of megabytes of unused packages.
Docker Multi-Stage Build
For maximum control, use a Dockerfile with multi-stage builds. Select Dockerfile as your build type in Dokploy and create a Dockerfile in your repo root:
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --only=production
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
ENV NEXT_TELEMETRY_DISABLED=1
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]
This produces a final Docker image that is typically 150-200MB instead of 1GB+. Smaller images mean faster deployments and less disk usage on your server.
Node.js Memory Limits
Next.js builds can consume significant memory, especially with large page counts or heavy static generation. Set the memory limit explicitly in your environment variables:
NODE_OPTIONS=--max-old-space-size=2048
On a 4GB VPS, setting this to 2048MB (2GB) leaves enough room for the OS, Dokploy, and your database. Adjust proportionally based on your server's RAM -- this is where independent resource scaling becomes valuable, as you can increase RAM without paying for CPU cores you do not need.
Cost Comparison
Here is where the economics become concrete. Consider a Next.js app with moderate traffic: 50,000 monthly visitors, ISR for product pages, image optimization enabled, and a PostgreSQL database.
| Resource | Vercel Pro | MassiveGRID VPS |
|---|---|---|
| Base cost | $20/month per seat | From $1.99/month |
| Build minutes | 6,000 included ($0.01/min overage) | Unlimited (your CPU) |
| Bandwidth | 1TB included ($0.15/GB overage) | 1-10TB included (plan dependent) |
| Image optimization | 5,000 included ($0.60/1K overage) | Unlimited (runs on your server) |
| Database | Vercel Postgres: $20/month add-on | Included (self-hosted PostgreSQL) |
| Serverless invocations | 1M included (overages apply) | N/A (persistent Node.js server) |
| Typical monthly cost | $40-80+ (with database and overages) | $4.99-14.99 (VPS with resources to spare) |
The cost difference compounds as you scale. Adding a second developer on Vercel Pro means another $20/month per seat. On your own server, it means adding another SSH key. If your app grows to need more SSR capacity, you scale CPU independently. If your database grows, you scale RAM and storage independently. You only pay for the resources that actually need to increase.
This is the fundamental advantage of infrastructure with independently scalable resources: your costs grow linearly with your actual resource consumption, not in tier jumps dictated by a pricing page.
MassiveGRID for Dokploy
- Cloud VPS from $1.99/mo -- Ideal for staging environments and low-traffic apps
- Dedicated VPS from $4.99/mo -- Dedicated CPU cores for consistent SSR performance under load
- Independent scaling -- Increase CPU for builds, RAM for database, or storage for assets separately
- 4 global locations -- Deploy close to your users in NYC, London, Frankfurt, or Singapore
- Managed Cloud Dedicated -- For production SaaS with HA and fully managed operations
Next Steps
With your Next.js app deployed on Dokploy, you have the same git-push-deploy workflow that Vercel provides, running on infrastructure you control at a fraction of the cost. From here, consider:
- Setting up Dokploy from scratch if you have not yet installed it
- Reading the VPS sizing guide for Dokploy to right-size your server for your workload
- Understanding shared vs. dedicated resources to choose the right infrastructure tier as your app scales
The migration path from Vercel to self-hosted is not a downgrade. It is a trade: you take on the responsibility of running a server (which Dokploy makes minimal) in exchange for predictable costs, no usage ceilings, and full control over your deployment pipeline.