Vercel made deploying Next.js effortless — push to Git, get a URL, done. But that convenience comes with a price tag that scales faster than your traffic. Vercel Pro costs $20 per team member per month, bandwidth overages kick in at 1TB, and serverless function execution is metered separately. For a three-person team running a medium-traffic application, you can easily cross $100/month before you've thought about it. The community has started calling this the "Vercel Tax" — a recurring cost that grows alongside your success.
Coolify gives you a Vercel-like deployment experience on your own VPS. Git push triggers, automatic SSL, preview deployments, and a clean dashboard — all running on infrastructure you control at a fixed monthly cost. A Cloud VPS starting at $1.99/month or a Dedicated VPS starting at $4.99/month gives you predictable pricing regardless of how many deployments you run or how much bandwidth your application consumes.
This guide walks through deploying a Next.js application on Coolify from start to finish — from connecting your Git repository to configuring preview deployments and tuning production performance. If you're considering leaving Vercel or want a deeper cost analysis, see our Vercel vs. self-hosted Coolify cost comparison.
Why Self-Host Next.js
The economics of self-hosting become compelling once you move past a hobby project. Here's what the numbers look like for a typical SaaS application serving 50,000 monthly visitors:
| Cost Component | Vercel Pro | Coolify on VPS |
|---|---|---|
| Base platform cost (3 seats) | $60/mo | $0 (open source) |
| Server / hosting | Included (with limits) | $4.99–$14.99/mo (VDS) |
| Bandwidth (2TB/mo) | $40/mo overage | Included |
| Serverless execution | Metered after 1000 GB-hrs | N/A (persistent server) |
| Estimated monthly total | $100–$150+ | $4.99–$14.99 |
Beyond cost, self-hosting gives you control over your build environment, deployment pipeline, server location, and runtime configuration. You're not constrained by Vercel's function size limits, execution timeouts, or middleware restrictions. Your Next.js app runs as a standard Node.js server with full access to the filesystem, long-running connections, and WebSocket support.
Prerequisites
Before starting, you need three things:
- A working Coolify installation. If you haven't set this up yet, follow our step-by-step guide to installing Coolify on a VPS. The guide covers server provisioning, firewall configuration, and initial Coolify setup. Minimum recommended specs: 2 vCPU, 4GB RAM, 50GB SSD.
- A Next.js project in a Git repository. Any Next.js 13+ application works — App Router or Pages Router. The project should have a valid
package.jsonwith the standard Next.js scripts (dev,build,start). - A domain name. You need a domain (or subdomain) with access to DNS management. You'll point an A record to your server's IP address.
Connecting Your Git Source
Coolify connects to your Git repositories through a GitHub App integration. This is more secure than deploy keys or personal access tokens because it provides granular, per-repository permissions that you can revoke at any time.
Setting up the GitHub App
- In the Coolify dashboard, navigate to Sources in the sidebar.
- Click Add New Source and select GitHub App.
- Coolify will redirect you to GitHub to create and install the app. Select your GitHub account or organization, then choose which repositories to grant access to. You can select specific repositories rather than granting access to all repos.
- After authorization, you'll be redirected back to Coolify with the GitHub App connected.
Creating a new resource
- Click New Resource from the Coolify dashboard.
- Select Public Repository or Private Repository (with GitHub App) depending on your repo visibility.
- Choose your connected server (the server where Coolify is installed, or a remote server if you've added one).
- Select the repository and the branch you want to deploy (typically
mainorproduction). - Coolify will automatically detect that the project is a Next.js application and configure the build settings accordingly.
Nixpacks Auto-Detection and Build Configuration
Coolify uses Nixpacks as its default build system. Nixpacks analyzes your repository, detects the framework (Next.js in this case), and automatically generates a Docker image without requiring you to write a Dockerfile. It reads your package.json, identifies the Node.js version, installs dependencies, runs the build command, and packages the output into an optimized container.
The detection is automatic: Nixpacks sees the next dependency in your package.json and configures the build pipeline accordingly. However, there's one critical optimization you should make before your first deploy.
Enabling standalone output mode
By default, Next.js builds include the entire node_modules directory in the production output. This creates Docker images that are 1GB or larger — wasteful for storage and slow to deploy. Next.js provides a standalone output mode that traces your application's actual imports and copies only the files needed at runtime.
Add the output setting to your next.config.js (or next.config.mjs):
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
}
module.exports = nextConfig
This single change reduces your Docker image from 1GB+ down to 100–200MB. The standalone output includes a minimal Node.js server that replaces next start, so your application starts faster and uses less memory at runtime.
Verify your package.json scripts
Nixpacks expects standard Next.js scripts in your package.json. Ensure these are present:
{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
}
}
Nixpacks will run npm run build (or yarn build / pnpm build depending on your lockfile) during the image build, then use npm start as the container's entrypoint. If you're using a monorepo or custom build scripts, you can override the build and start commands in Coolify's resource settings under the Build tab.
Build resource requirements
Next.js builds are CPU-intensive operations. The build process compiles React components, generates static pages, optimizes images, and bundles JavaScript — all of which demand significant CPU time. On a shared VPS, this means your build competes with other tenants for CPU cycles, leading to unpredictable build times that can range from 2 minutes to 10+ minutes for the same project.
This is where MassiveGRID's Dedicated VPS makes a measurable difference. Dedicated CPU cores mean your Next.js build gets consistent, uncontested processing power. A build that takes 8 minutes on shared infrastructure typically completes in 2–3 minutes on dedicated cores. When you're deploying multiple times per day, that difference compounds.
Environment Variables
Next.js has a specific convention for environment variables that Coolify respects. Understanding the distinction between build-time and runtime variables is critical for a correct deployment.
Adding variables in Coolify
Navigate to your resource's Environment Variables tab in the Coolify dashboard. You can add variables one at a time or paste a block of KEY=value pairs. Each variable can be toggled between:
- Build-time — Available during
next build. Use for variables that need to be embedded in the JavaScript bundle. - Runtime — Available when the container is running. Use for secrets and values that should not be in the client-side bundle.
- Both — Available during build and at runtime.
The NEXT_PUBLIC_ prefix
Next.js inlines any environment variable prefixed with NEXT_PUBLIC_ into the client-side JavaScript bundle at build time. This means:
NEXT_PUBLIC_API_URL— Embedded in the browser bundle. Visible to users. Must be set as a build-time variable in Coolify.DATABASE_URL— Only available server-side. Never sent to the browser. Should be set as a runtime variable.NEXT_PUBLIC_STRIPE_KEY— Your publishable Stripe key. Needs to be in the bundle, so set as build-time.STRIPE_SECRET_KEY— Your secret key. Must never reach the client. Set as runtime only.
Important: If you change a
NEXT_PUBLIC_variable, you must trigger a rebuild for the change to take effect. Runtime-only variables take effect on the next container restart without a rebuild.
Example environment configuration
# Build-time variables (NEXT_PUBLIC_ prefix)
NEXT_PUBLIC_APP_URL=https://myapp.example.com
NEXT_PUBLIC_API_URL=https://api.example.com
NEXT_PUBLIC_GA_ID=G-XXXXXXXXXX
# Runtime-only variables (secrets)
DATABASE_URL=postgresql://user:pass@db:5432/myapp
NEXTAUTH_SECRET=your-random-secret-here
NEXTAUTH_URL=https://myapp.example.com
REDIS_URL=redis://redis:6379
SMTP_HOST=smtp.example.com
SMTP_PASSWORD=your-smtp-password
Post-Deployment Optimization
Once your Next.js application is live on Coolify, the initial deployment is only the beginning. A production application demands attention to performance tuning, caching strategy, and resource allocation. The following optimizations apply whether you're running a content site with static generation or a dynamic application with server-side rendering.
Enable standalone output mode
By default, Next.js copies the entire node_modules directory into the production build. For containerized deployments on Coolify, you should enable standalone output mode in your next.config.js:
/** @type {import('next').NextConfig} */
const nextConfig = {
output: 'standalone',
images: {
formats: ['image/avif', 'image/webp'],
},
experimental: {
serverMinification: true,
},
}
module.exports = nextConfig
Standalone mode produces a self-contained build that includes only the dependencies your application actually uses. This reduces the Docker image size by 60–80%, which directly translates to faster deployments and lower memory consumption at runtime. Coolify's Nixpacks builder detects this configuration automatically and adjusts the Dockerfile accordingly.
Configure caching headers
Next.js serves static assets from the /_next/static/ path with immutable cache headers by default, but your API routes and server-rendered pages need explicit cache configuration. Add a headers() function to your next.config.js to set appropriate Cache-Control directives for different route patterns. For pages that change infrequently, consider using ISR (Incremental Static Regeneration) with a revalidation interval rather than full SSR on every request.
Resource allocation
In Coolify's resource settings for your Next.js deployment, set explicit memory and CPU limits. A typical Next.js application with moderate traffic runs well with 512 MB–1 GB of RAM and 1 vCPU. If you're using Next.js Image Optimization, increase the memory limit to at least 1 GB since the sharp library buffers images in memory during transformation. Monitor your container's actual resource usage through Coolify's metrics dashboard for the first week and adjust limits based on real data rather than guessing.
Monitoring and Observability
Coolify provides built-in container metrics — CPU usage, memory consumption, network I/O, and disk usage — accessible from the resource dashboard. For Next.js-specific monitoring, you need application-level instrumentation.
Health checks
Configure a health check endpoint in Coolify's settings. Next.js API routes work well for this purpose. Create a /api/health route that returns a 200 status and optionally checks downstream dependencies like your database connection:
// app/api/health/route.js
import { NextResponse } from 'next/server'
export async function GET() {
return NextResponse.json({
status: 'healthy',
timestamp: new Date().toISOString(),
uptime: process.uptime(),
})
}
Set the health check path to /api/health in Coolify's resource configuration. Coolify will poll this endpoint and automatically restart the container if it becomes unresponsive, providing basic self-healing without any external monitoring infrastructure.
Log management
Coolify captures stdout and stderr from your container and displays logs in the dashboard. Next.js outputs useful information by default — build warnings, route compilation times, and runtime errors. For structured logging in production, consider writing JSON-formatted log lines that include request IDs, response times, and error stack traces. Coolify's log viewer supports searching and filtering, which becomes essential as your application scales.
For applications that require deeper observability, Coolify supports integration with external logging and monitoring services. You can configure your Next.js application to export OpenTelemetry traces, forward logs to a centralized service, or expose a Prometheus metrics endpoint — all manageable through environment variables without changing your deployment configuration.
Why MassiveGRID for Your Next.js Deployment
The infrastructure running beneath Coolify determines the ceiling of your application's performance. MassiveGRID's platform is engineered for workloads exactly like containerized Next.js deployments — where CPU burst performance during builds, consistent memory bandwidth during SSR, and low-latency networking for API routes all contribute to the end-user experience.
Every MassiveGRID server runs on enterprise-grade hardware with NVMe storage, ensuring that Coolify's Docker operations (image pulls, layer caching, volume mounts) execute at full speed. Our global network spans four data center regions — New York, London, Frankfurt, and Singapore — so you can deploy your Next.js application close to your users. All plans include DDoS protection, automated backups, and a 99.99% uptime SLA backed by redundant infrastructure at every layer.
Deploy Next.js with Coolify on MassiveGRID
- Cloud VPS — From $1.99/mo. Independently scalable resources for development and staging environments.
- Dedicated VPS — From $4.99/mo. Dedicated CPU cores for consistent Next.js build performance.
- Managed Cloud Dedicated — Automatic failover and Ceph 3x-replicated storage for production workloads.