Skip to main content
ASoc
Comparison

Vercel vs. DigitalOcean: What Owning the Server Actually Costs

Two Route Handlers, zero Dockerfiles, zero nginx configs — what this storefront's own deploy setup says about Vercel vs a DigitalOcean Droplet.

The ASoc Team8 min read

Vercel builds and runs your app for you — push to a branch and it's deployed, scaled, and torn back down between requests. DigitalOcean gives you compute: either a Droplet (a raw Linux VM you administer yourself) or App Platform (a managed layer on top of the same Droplets). The real decision isn't price or brand — it's whether you want to own the server, and this codebase's own deploy setup answers that question by what it doesn't contain.

What "owning the server" actually requires, checked against this repo

A Droplet is a VM with nothing on it. Getting a Next.js app running on one means adding, at minimum: a process manager to keep next start alive across crashes and reboots (pm2 or a systemd unit), a reverse proxy for TLS termination and to put port 443 in front of Node's port (nginx or Caddy), and a deploy script or CI job to pull, install, build and restart on every push. None of that exists in this repository:

$ find . -maxdepth 2 -iname "Dockerfile*" -o -iname "*.nginx*"
# (no output)
$ grep -n "output:" next.config.ts
# (no output — no `output: "standalone"` either)
$ grep -rn "pm2\|systemd" package.json
# (no output)

Zero results across all three checks. That's not an oversight — it's what a codebase looks like when it was built assuming a platform that removes those layers entirely. Deploying this exact repo to a Droplet wouldn't mean flipping a config flag; it would mean writing a Dockerfile, a systemd unit, and an nginx config from scratch, none of which currently exist anywhere in the tree.

What actually deploys on Vercel today

Production has exactly two Route Handlers, both explicit about their runtime:

// src/app/api/webhooks/lemonsqueezy/route.ts
export const runtime = "nodejs";

// src/app/api/download/route.ts
export const runtime = "nodejs";

Neither sets maxDuration — the platform default is enough for both (verify a webhook signature and write to Postgres; check an entitlement and mint a short-lived signed URL). Everything else in the app — all 480 static pages in the current build — is pre-rendered at build time and served from Vercel's CDN with no server process running per request at all. There is no "app" listening on a port here in the sense a Droplet would run one; there's a build output Vercel's platform knows how to serve, plus two short-lived functions.

That build is fast enough to make the "pre-render everything" strategy practical at this scale:

Generating static pages using 3 workers (0/480) ...
Generating static pages using 3 workers (120/480)
Generating static pages using 3 workers (240/480)
Generating static pages using 3 workers (360/480)
✓ Generating static pages using 3 workers (480/480) in 6.8s

480 pages in 6.8 seconds, measured on this exact build. On Vercel that number only matters for how quickly a deploy goes live; on a Droplet, it's the number you'd have to fit into a deploy script you write yourself — clone, install, build, then restart the process manager without dropping in-flight requests — because there's no platform watching the git remote and doing that for you.

Where App Platform actually narrows the gap

DigitalOcean's App Platform is the fairer comparison, not a bare Droplet — it takes a git repo, runs a build, and deploys it without you managing the VM directly, closer to Vercel's model. The real remaining differences are in what's automatic versus configured:

VercelDigitalOcean App PlatformDigitalOcean Droplet
Who patches the OSVercelDigitalOceanYou
TLS certificateAutomatic, zero-configAutomaticYou configure (Let's Encrypt via Certbot, or a proxy)
Static asset CDNBuilt inBuilt in (CDN add-on)You add one, or serve directly
Scale-to-zero on idleYes, per-functionNo — apps run continuouslyNo — the Droplet runs continuously
Preview deployments per branch/PRBuilt inNot built inNot built in
Framework-aware build (Next.js)Native, first-partyBuildpack-based, genericYou script it

The Droplet column is where this codebase's missing Dockerfile/nginx/systemd actually bites — App Platform and Vercel both remove that layer, just with different degrees of Next.js-specific awareness underneath.

The one config that ports cleanly to any of the three

Not everything in this repo is Vercel-specific. Its CSP and security-response headers are defined once, as a plain Next.js config export:

// next.config.ts
async headers() {
  return [{ source: "/(.*)", headers: securityHeaders }];
},

headers() is core Next.js, not a Vercel feature — it runs identically whether next start is executed by Vercel's platform, App Platform's buildpack, or a pm2-managed process on a bare Droplet, because it's the framework's own server emitting the headers, not something injected at the CDN edge. That's the actual boundary worth knowing: build-and-deploy automation (patching, TLS, scale-to-zero, preview URLs) is genuinely platform-specific and is what this whole comparison is about; application-level configuration that Next.js owns travels with the code regardless of where it runs.

Why this matters more than the pricing page

DigitalOcean's per-resource pricing (a fixed monthly Droplet cost, or App Platform's per-container pricing) can be cheaper than Vercel's per-invocation model at steady, predictable traffic — that's a real tradeoff. But it's the wrong axis to decide on first for a codebase like this one: this repo has no infrastructure code to run anywhere except through a platform that builds and serves it automatically. The cost of adopting DigitalOcean's Droplet tier isn't the monthly bill, it's writing the Dockerfile, the reverse-proxy config, and the deploy pipeline this repo has never needed — work that has to happen once, up front, before the pricing comparison even applies.

Troubleshooting: matching the platform to what you're actually running

SymptomCauseFix
"It works locally but nothing deploys" on a DropletNo process manager — next start exits when the SSH session closesAdd pm2 start npm --name app -- start (or a systemd unit) before anything else
Site loads over HTTP but not HTTPS on a DropletNo reverse proxy terminating TLSPut nginx or Caddy in front of the Node process, or use a load balancer that terminates TLS for you
A Route Handler works locally but times out on a serverless platformDoing long-running work in a function meant for short requests (this repo's two routes deliberately never do this)Move long-running work to a background worker or a job queue — not a route handler
App Platform build fails on a Next.js-specific featureIts buildpack is generic Node, not Next.js-aware the way Vercel's build pipeline isCheck App Platform's Next.js buildpack docs for the specific feature, or add a custom build command

Frequently asked questions

Does this app's database live on Vercel? No — neither Vercel nor a Droplet hosts this app's data. Postgres runs on Supabase, reached from process.env.NEXT_PUBLIC_SUPABASE_URL, entirely independent of whichever platform runs the Next.js build. Moving this app's compute from Vercel to DigitalOcean wouldn't touch the database layer at all; DigitalOcean's own Managed Databases product would only become relevant if you were also moving the Postgres instance, which is a separate decision from where the app itself runs.

Is a Droplet cheaper than Vercel? Often, at predictable steady traffic — a fixed monthly VM cost versus Vercel's per-invocation pricing. But the comparison only makes sense once you've built (or bought) the process-manager, reverse-proxy and deploy-pipeline layer a Droplet doesn't include. This repo has none of that today.

Does DigitalOcean have anything like Vercel's per-branch preview deployments? Not built in on either App Platform or a Droplet. You'd wire your own CI to spin up a preview environment per PR, which Vercel does automatically for every push.

Is App Platform basically the same as Vercel? Closer than a Droplet, but its build step is a generic Node buildpack rather than a Next.js-native build pipeline — App Router features that Vercel's build understands out of the box may need a custom build command on App Platform.

Why does this post keep pointing at the same two Route Handlers? Because they're the entire dynamic surface of this codebase — the fact that decides whether a hosting platform's request-scoped compute model fits is how much of your app actually needs it, and here the honest answer is "two small functions, nothing else."

Templates in this post

ASoc Magnet (a lead-generation SaaS landing page), ASoc Mind (an AI creative-services marketing site) and ASoc Momentum (an AI strategy-agency site) all deploy the same way — static build, two Route Handlers, no server to administer.

Browse the full sets: Next.js landing page templates, Tailwind landing page templates. For the same route-census approach against other platforms, see Vercel vs. Render, Vercel vs. AWS Amplify and Vercel vs. Cloudflare Pages.

Keep reading

Comparison8 min read

Vercel vs. GitHub Pages: 344 Static Pages, 8 That Need a Server

GitHub Pages has no compute layer at all — not slower, absent. A fresh build of this storefront counts exactly which routes that categorically rules out, and why it isn't a rendering-mode question.

Read more
Comparison10 min read

Vercel vs. Render: Does Anything You Run Need to Stay Running?

Two Route Handlers, both stateless, neither overriding the default timeout — versus a release script that clones, installs, and boots for minutes. That split is the real decision axis.

Read more