Frontend Development

Next.js Hosting in 2026 — Vercel, Cloudflare Pages, or Your Own VPS?

By Domain India Team · DomainIndia SupportPublished 18 min read
Knowledge base article
Contents (20 sections)

Verdict at the top: for a typical small-to-medium Next.js project, the honest first answer is that a managed platform such as Vercel or Cloudflare handles most Next.js workloads with very little operational work. Self-host on a VPS when (a) you've outgrown the free tiers, (b) you want to keep the frontend, a Node backend and a database on the same machine for cost, or (c) you already run other services on the box and want to consolidate. For pure-static Next.js sites, shared cPanel or DirectAdmin hosting works well: output: 'export', upload out/ to public_html/, done. This guide covers each path honestly.

Key takeaways

Next.js has three rendering modes (Static, SSR, ISR) and five practical hosting options: Vercel, Cloudflare, a Domain India VPS, the Domain India App Platform, and Domain India shared hosting with a static export. Vercel and Cloudflare suit most marketing sites and content-heavy apps; a VPS gives you control and room for other services; shared hosting is best kept for pure-static sites without API routes or middleware.

1. The five paths: when each is right

PathWhen to pick itMonthly cost (typical small site)
Vercel (Hobby = free / Pro $20/mo per user)Default for new Next.js projects; pure Next.js focus; team has no ops bandwidth₹0-1,700
Cloudflare Workers or Pages (free / Workers Paid $5/mo)Cost-conscious; want one bill for CDN + DNS + hosting; comfortable with Cloudflare's runtime limits₹0-450
Domain India VPSSelf-host preferred; need to colocate with backend/DB; running multiple servicesFrom ₹553 + GST
Domain India App PlatformManaged Node.js hosting without running a server yourselfFrom ₹100 + GST
Domain India shared (cPanel/DirectAdmin)Pure-static export (no API routes, no SSR, no middleware)See the cPanel and DirectAdmin plan pages

The decision lands on the question: does your app need long-running Node-server features (SSR, API routes, middleware, ISR)?

  • No — static export is great; pick whichever host you already use.
  • Yes — pick Vercel, Cloudflare, the App Platform or a VPS. Shared hosting is built for small request/response apps, not a production Next.js server (see section 5).

2. Latency: the part most "X vs Y" articles fudge

For an Indian audience, the distance between the visitor and whatever answers the request matters most. Rough, illustrative numbers for Indian broadband:

PathIndia round trip to first byte
Cached response from a CDN edge in India (Vercel or Cloudflare)5-30 ms
Server-rendered response from a function region in India15-40 ms
Server-rendered response from a function region in the US200-300 ms
Origin server in India, no CDN20-50 ms
Origin server in Europe, no CDN130-180 ms
Any origin with Cloudflare in front5-15 ms (cached) / origin round trip (miss)

Takeaway for Indian-audience sites: cached pages and assets are fast on any CDN with Indian edges. What differs is where your server-rendered pages and API routes run. On Vercel, check which function region your plan lets you choose and pick Mumbai if it is available; on your own server, put Cloudflare in front and cache what you can. If you don't know where your hosting server is, a ping or traceroute from India gives you a good idea.

3. Path 1: Vercel (the default)

Best when: you want zero ops overhead, your project is Next.js-centric, and you can stomach the pricing model.

The good: deploys from git, first-class Next.js support (Vercel maintains the framework), built-in image optimisation, free SSL, automatic preview deploys per pull request.

The catches:

  • Hobby (free) tier excludes commercial use. If you're shipping a product, you're technically required to be on Pro ($20/mo per user, ~₹1,700). Vercel's enforcement is light-touch but the licence is clear.
  • Function region matters. Static and cached content is served from Vercel's global CDN, which includes India, but server-rendered pages and API routes run in the function region you choose (the default is in the US). Check your plan's region options.
  • Usage pricing is the gotcha. Pro includes a data transfer allowance and then charges per GB, at rates that vary by region. A medium-traffic site that goes viral can produce a large bill; set spend limits.
  • Vendor lock-in is real. Vercel-specific features (ISR On-demand, Edge Config, Vercel KV) tie your app to their platform. Migrating later is painful.

Setup:

bash
npm install -g vercel
cd my-next-app
vercel                 # interactive setup
vercel --prod          # deploy production

That's it. Push to git → auto-deploy. Custom domain via Vercel's dashboard.

When to graduate off Vercel: when usage bills keep growing, when you want to colocate with your own backend services, or when you have the ops capacity to self-host.

4. Path 2: Cloudflare Workers and Pages

Best when: you want low-cost hosting with Indian edge locations and your Next.js app fits within Cloudflare's runtime.

The good: Cloudflare has edge locations in several Indian cities (including Mumbai, Chennai, Delhi, Bengaluru, Hyderabad and Kolkata); static assets are served without bandwidth charges; custom domains and SSL are free; it integrates with Workers, D1, R2 and KV.

The catches:

  • Use the OpenNext adapter. Cloudflare's current recommendation for full Next.js apps is the OpenNext adapter (@opennextjs/cloudflare), which deploys to Workers. The older @cloudflare/next-on-pages adapter only supported the edge runtime and is deprecated. Pure static exports can still go straight to Pages.
  • Not a full Node.js server. Workers support many Node.js APIs through compatibility flags, but not all. Native modules (for example sharp) and anything using child_process won't run; use Cloudflare Images or a custom image loader.
  • Free-tier limits. Workers requests, CPU time and build minutes have free allowances; check Cloudflare's pricing page for current numbers.

Setup: follow Cloudflare's Next.js guide for the OpenNext adapter, connect your GitHub repository, and deploy. Pushes to the repository can trigger new builds.

For Next.js apps that mostly use static generation with a few API routes, Cloudflare is excellent and very cheap. For apps that lean heavily on Node-only packages or advanced Next.js features, Vercel or your own server is the safer bet.

5. Path 3: a Domain India VPS (self-host)

Best when: you want infrastructure control, have multiple services to colocate, or want a fixed monthly cost regardless of traffic. A Domain India VPS is self-managed: you get full root access and you install, secure and back up everything yourself.

Build for production

Configure next.config.js for standalone output:

javascript
/** @type {import('next').NextConfig} */
const nextConfig = {
  output: 'standalone',
  // If using next/image with non-localhost domains:
  images: {
    remotePatterns: [
      { protocol: 'https', hostname: 'cdn.yourdomain.com' },
    ],
  },
};

module.exports = nextConfig;

Build locally or in CI:

bash
npm install --legacy-peer-deps     # only if you have peer-dep conflicts
npm run build

Standalone output structure:

code
.next/standalone/server.js        ← the entry point
.next/standalone/.next/...
.next/standalone/package.json
.next/static/                     ← copy alongside
public/                           ← copy alongside

Deploy package — what to ship

bash
# On dev machine, build then copy these to VPS
rsync -avz --delete .next/standalone/ user@vps:/opt/myapp/
rsync -avz --delete .next/static/ user@vps:/opt/myapp/.next/static/
rsync -avz --delete public/ user@vps:/opt/myapp/public/

Run via systemd

/etc/systemd/system/myapp.service:

ini
[Unit]
Description=My Next.js App
After=network.target

[Service]
Type=simple
WorkingDirectory=/opt/myapp
Environment=NODE_ENV=production
Environment=PORT=3000
Environment=HOSTNAME=127.0.0.1
ExecStart=/usr/bin/node server.js
Restart=on-failure
User=myapp
Group=myapp

[Install]
WantedBy=multi-user.target
bash
sudo systemctl enable --now myapp
sudo systemctl status myapp
sudo journalctl -u myapp -f       # tail logs

systemd is the right answer in 2026 — PM2 was popular but adds complexity for no real benefit on a single-host setup.

Reverse proxy with nginx

/etc/nginx/sites-available/myapp:

nginx
server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl;
    http2 on;
    server_name yourdomain.com www.yourdomain.com;

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_bypass $http_upgrade;
    }

    location /_next/static/ {
        alias /opt/myapp/.next/static/;
        expires 365d;
        access_log off;
        add_header Cache-Control "public, immutable";
    }
}
bash
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Or skip nginx and use Caddy, which auto-handles SSL via Let's Encrypt:

caddy
yourdomain.com {
    reverse_proxy 127.0.0.1:3000
    handle_path /_next/static/* {
        root * /opt/myapp/.next/static
        file_server
    }
}

For most VPS deployments, Caddy is genuinely simpler than nginx + certbot.

Build memory — the most common deploy gotcha

Next.js builds are memory-hungry. On a small VPS with 2 GB of RAM, a medium-sized Next.js app can run out of memory during npm run build. Symptoms:

code
<--- Last few GCs --->
[12345:0x...] FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

Three fixes:

  1. Build elsewhere, deploy artefacts. Run npm run build in CI (GitHub Actions) or on your laptop, then rsync the standalone output. Most-recommended pattern.
  2. Add swap on the VPS if you must build on the box:
    bash
    sudo fallocate -l 4G /swapfile
    sudo chmod 600 /swapfile
    sudo mkswap /swapfile
    sudo swapon /swapfile
    echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab
  3. Bump Node's heap limit (less reliable):
    bash
    NODE_OPTIONS='--max-old-space-size=2048' npm run build

If the build still fails, build in CI or move to a larger VPS plan; the VPS page lists the RAM of each plan.

6. Path 4: the Domain India App Platform

The App Platform is managed hosting for apps: you deploy from GitHub with Deploy Now, or from CI with a deploy token, and the platform builds and runs the app. Node.js is detected automatically, so a Next.js app with standard build and start scripts is a natural candidate; any other stack needs your own Dockerfile. Every plan includes PostgreSQL and free SSL.

Things to know before you choose it:

  • There is no automatic deploy on every push. Click Deploy Now, or call the deploy token from your CI pipeline.
  • There is no SSH access, no Redis add-on and no WebSocket support. If your app needs any of these, use a VPS.
  • Test your app there before you move production traffic. The getting started guide walks through the first deploy.
App Starter
₹100/mo + GST
  • 512 MB RAM per app
  • 1 vCPU
  • 5 GB NVMe SSD
  • PostgreSQL Database
See plan details

7. Path 5: static export to Domain India shared hosting

Best when: your Next.js app is genuinely static (no API routes, no SSR, no middleware), and you already have shared hosting at Domain India.

javascript
// next.config.js
const nextConfig = {
  output: 'export',
  images: {
    unoptimized: true,    // built-in optimiser disabled for static export
  },
  trailingSlash: true,    // generates /about/index.html
};
module.exports = nextConfig;
bash
npm run build
# Creates out/ directory with static HTML/CSS/JS

Upload the contents of out/ to public_html/ with the File Manager, FTP, or GitHub Actions to cPanel.

Domain India shared hosting runs the Apache web server and .htaccess rules work. For clean URLs, drop a .htaccess in public_html/:

code
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)/$ /$1/index.html [L]

What you lose on static export:

  • API routes (pages/api/*, app/api/*) — they don't exist; you'll need a separate backend or external service.
  • SSR (getServerSideProps) — pages are fully pre-rendered at build time.
  • ISR (revalidate in getStaticProps) — same; no runtime regeneration.
  • Image optimisation via next/image — served as-is unless you use a third-party loader (Cloudinary, imgix).
  • Middleware — edge functions don't run.
  • Dynamic routes that can't be enumerated at build time — /users/[id] with arbitrary IDs needs SSR.

If your app is a marketing site, blog, documentation, or portfolio with no user-specific server-side rendering, static export is excellent — fast, cheap, no operational overhead.

What about the Node.js tool on shared hosting?

cPanel and DirectAdmin both have a Node.js app tool (Setup Node.js App), which runs small Node apps behind Apache through Phusion Passenger. It suits small Express or Fastify APIs. A full Next.js server is a poor fit: a Next.js build can need more memory than a shared account allows (so build locally and upload the output), the app shares the account's CPU and memory limits, and nothing long-running outside the web server is allowed. If you want to try it, follow Deploy a Node.js app on shared hosting and test carefully; for production SSR, the App Platform or a VPS is the safer choice.

8. ISR: the feature that bites people

Incremental Static Regeneration is genuinely useful: pre-render at build time, regenerate on a schedule (or on-demand). But it has hosting-dependent gotchas:

On Vercel: ISR works out of the box. Revalidate triggers on the next request after the TTL expires.

On Cloudflare: ISR works through the OpenNext adapter, but it needs a cache store configured (for example R2 or KV). Read the adapter's caching docs before you rely on on-demand revalidation.

On a VPS: ISR works, but be aware:

  • Revalidation writes to disk under .next/cache/. Make sure your filesystem allows writes (it does on standard VPS, but read-only-rootfs deployments break this).
  • Multiple Next.js instances behind a load balancer don't share cache by default — each instance regenerates independently. Use shared cache (Redis adapter for Next.js cache) for multi-instance setups.
  • The revalidate: 60 you set in code means "regenerate at most once per 60 seconds, lazily on next request". A site with no traffic doesn't regenerate.

On shared hosting with a static export: there is no ISR, because there is no Next.js server. Rebuild in CI when content changes and upload the new out/ folder.

9. A VPS with Cloudflare in front (the budget play)

For Indian-audience Next.js sites that don't justify a paid platform plan, this is often a good cost/performance combination:

  1. Deploy Next.js to a Domain India VPS with the systemd and Caddy setup above.
  2. Put Cloudflare (free plan) in front of it.
  3. Cloudflare's Indian edge locations serve cached pages and assets to Indian users in a few milliseconds.
  4. Cache misses pay the round trip to your VPS, which the user perceives as "first load slower, then fast".

For most landing pages, marketing sites and brochureware, this stack has a fixed monthly cost with no usage-based bandwidth surprises. For highly dynamic apps (real-time dashboards, checkout flows), the cache-miss penalty matters more, so measure it from India before you commit. Our Cloudflare setup guide covers the DNS, SSL and caching settings.

10. Common errors and what they actually mean

Image with src "..." has either width or height modified, but not the other. — Next/Image needs both dimensions to prevent layout shift. Either provide both width and height, or use fill mode with a sized parent.

A required parameter (id) was not provided as a string in generateStaticParams — an App Router generateStaticParams returned the wrong shape. It must return an array of plain objects such as [{ id: '1' }, { id: '2' }], with string values. The { params: { id } } wrapper belongs to the Pages Router's getStaticPaths, not the App Router.

Module not found: Can't resolve 'fs' (or 'child_process', 'path') — you're trying to import Node-only modules in code that runs on the edge / browser. Move the import inside a server component, API route, or getServerSideProps.

Error: API Resolved without sending a response — your API route handler ran but didn't call res.end(), res.json(), or res.send(). Add a return.

Error: ENOSPC: System limit for number of file watchers reached — dev mode hit Linux's inotify limit. Increase: echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf && sudo sysctl -p.

<--- JS stack trace ---> FATAL ERROR: ... JavaScript heap out of memory — build OOM. See "Build memory" section above.

Error: getaddrinfo EAI_AGAIN api.example.com — DNS resolution failed at runtime. Common on isolated build environments. Make sure your VPS has working DNS (/etc/resolv.conf).

Error occurred prerendering page "..." followed by network error — you're calling an API at build time that's not reachable from your build environment. Move data fetching to runtime (getServerSideProps) or pre-fetch from CI.

Error: Page "..." is missing param "..." in "generateStaticParams" — App Router dynamic route had a request for a slug not in the static-params list. Either add the slug, or set dynamicParams: true (default) and ensure the page handles SSR fallback.

TypeError: Cannot read properties of undefined (reading 'pathname') at NextRouter — old next/router used in App Router context. Migrate to next/navigation (useRouter, usePathname).

Hydration mismatch (Text content does not match server-rendered HTML) — server and client rendered different HTML. Common causes: Date.now()/Math.random() outside useEffect, browser-only globals (window, document) accessed during SSR, conditional rendering based on typeof window. Fix: gate with useEffect or useState initialisation.

11. Performance baselines: what good looks like

For a typical Next.js marketing site with ~10 pages, ~50 KB JS bundle:

MetricStatic export (CDN)SSR on VPS + CloudflareSSR on VPS direct
TTFB (Indian user)5-30 ms5-20 ms (cache hit) / origin round trip (miss)Origin round trip (100+ ms from a distant server)
LCP (Largest Contentful Paint)0.8-1.5 s1.0-1.8 s2.0-3.5 s
CLS (Layout shift)000
INP (Interaction to Next Paint)50-100 ms50-100 ms50-100 ms

These are illustrative figures for a well-built site, not measurements. The biggest single win is the CDN: without one, every request pays the full round trip to your server.

Where Domain India fits

  • Static Next.js sites: shared cPanel or DirectAdmin hosting with output: 'export'. See the cPanel and DirectAdmin plan pages.
  • Managed Node.js hosting: the App Platform, from ₹100 a month; Node.js is auto-detected and PostgreSQL and SSL are included.
  • Full control: a self-managed VPS, from ₹553 a month, with root access for systemd, Caddy or nginx, and Cloudflare in front. You manage the server and its backups; VPS plans include no snapshots or backups.

Prices are Domain India list prices, per month, excluding 18% GST. For questions about your account or plan, use 24/7 live chat or a support ticket; tickets get a first response within 15 minutes, and there is no phone support. Support can't debug your application code on a self-managed VPS.

Bottom line

For a new Next.js project starting today, try a managed platform first. If you need self-hosted infrastructure (a cost ceiling, colocation with your backend), a VPS with Cloudflare in front is a strong combination with a fixed monthly cost. For pure-static Next.js (marketing site, blog, documentation), shared hosting works well with output: 'export'.

Frequently asked questions

Why not just use Vercel for everything?

Vercel is a very good Next.js host when you want zero ops. The reasons people choose otherwise: usage costs grow with traffic, the free Hobby tier excludes commercial use, server-rendered code runs in the function region you pick rather than everywhere, and Vercel-specific features create some lock-in.

Is Cloudflare really free for production Next.js sites?

Static assets, custom domains and SSL are free, and commercial use is allowed. Server-rendered pages run as Workers, which have a free daily request allowance and a paid plan from $5 a month. Most small sites stay within the free allowance; check Cloudflare's pricing page for current limits.

Can I run Next.js on shared cPanel hosting?

A static export (output: 'export') works well on cPanel and DirectAdmin. Server-side features (API routes, SSR, middleware, ISR) need a running Next.js server; shared hosting's Node.js tool can run small Node apps, but a full Next.js server is a poor fit for the account's resource limits. For those features, use the App Platform or a VPS. See our Docker on shared hosting article for the same constraint.

What about cPanel's "Setup Node.js App"?

Setup Node.js App exists on cPanel and DirectAdmin and runs Node apps behind Apache through Phusion Passenger. It suits small Express or Fastify apps. For a full Next.js server, build locally, test carefully and expect the account's CPU and memory limits to apply; for production, the App Platform or a VPS is the safer choice.

How do I handle environment variables on a VPS?

Two patterns: (a) .env.production file at your app root (gitignored, deployed separately); (b) systemd EnvironmentFile=/etc/myapp.env directive. Don't put secrets in next.config.js — they get baked into the build output.

What's the right way to do image optimisation on a VPS?

Two options: (a) use next/image with the built-in optimiser (requires sharp to be installed: npm install sharp); (b) use a third-party image service (Cloudflare Images, Imgix, Cloudinary) and a custom loader. The first is simpler if your VPS has CPU headroom; the second is better at scale.

How do I deploy on every git push?

Use GitHub Actions or GitLab CI: build the standalone output, copy it to your VPS, and restart the systemd service. See our guide to GitHub Actions deploys to a VPS. On the App Platform, call your deploy token from CI instead.

Does Next.js work with Cloudflare's full edge stack (Workers + D1 + R2)?

Yes. The OpenNext adapter (@opennextjs/cloudflare) deploys Next.js to Cloudflare Workers, and D1 (SQLite) and R2 (object storage) are available through Workers bindings. The older @cloudflare/next-on-pages adapter is deprecated.

My Indian audience is loading the site slowly. What's the first thing to check?

Cache-hit ratio. If your Next.js app is on a VPS with Cloudflare in front, run curl -sI yoursite.com | grep cf-cache-status — if every request is MISS, your caching rules aren't right. Static assets should be HIT immediately. HTML may be DYNAMIC if it needs SSR; that's fine.

Ready to deploy? Compare VPS plans, read the App Platform guide, or open a support ticket with questions about a plan.

Self-hosting Next.js?

A self-managed Domain India VPS gives you root access to run Next.js under systemd behind Caddy or nginx, with Cloudflare in front.

See VPS plans

Was this article helpful?

Your answer helps us decide what to improve next.

Still need help? Open a support ticket and our team will reply.

Prefer an app? Add this site to your home screen.Get the app