All posts
guide7 min read

Deploy a Next.js app for free — without Vercel

Next.js is an open-source framework that runs anywhere Node runs. Vercel is one place to host it — the most polished place, in many ways — but "Next.js" and "Vercel" are not the same product, and the AI tools generating Next.js apps all day (v0, Cursor, Claude Code) don't care where the output runs.

Here's the complete free container deploy, including the config details that actually matter and an honest list of what you give up.

The short version

cd your-nextjs-app
npm i -g @launchmatic/cli
lm login
lm init
lm deploy

Nixpacks detects the next dependency, runs next build, starts with next start, and binds the injected PORT. You get an SSL-secured *.launchmatic.app URL on the free tier — one service, 1 GB Postgres, no card, no expiry. (Free services sleep after 30 idle minutes and wake on request; $9/mo keeps a site always-on.)

That works with zero config. The rest of this post is the 20% that makes it production-grade.

Use standalone output

One line, significantly smaller images and faster cold deploys:

/** @type {import('next').NextConfig} */
module.exports = {
  output: "standalone",
};

Next traces exactly which node_modules your server needs and bundles them into .next/standalone. Without it the whole node_modules ships; with it, deploys are lean. This is the single most useful Next.js container setting and AI tools almost never add it — worth checking any generated repo.

Environment variables: the build-time trap

The classic gotcha moving off any integrated host:

  • NEXT_PUBLIC_* vars are inlined at build time. Set them before lm deploy, not after — changing them requires a rebuild.
  • Server-only vars are read at runtime; change them and restart freely.
lm env set NEXT_PUBLIC_API_URL=https://api.example.com   # before deploy
lm env set STRIPE_SECRET_KEY=sk_live_...                  # anytime

Add Postgres

lm db create app-db --service <serviceId>   # id printed by lm init

DATABASE_URL is injected automatically — Prisma, Drizzle, and raw pg all pick it up unmodified. This is the point where the container model starts paying for itself: the database lives next to the app, not across a marketplace boundary.

What behaves differently off Vercel

Honesty section. On a single long-running server:

  • ISR works — revalidation happens in-process. What you lose is Vercel's globally distributed revalidation; for most apps this is unobservable.
  • Middleware runs as normal Node middleware on your server, not at 300 edge PoPs. Auth guards and redirects: fine. Latency-critical geo-routing: Vercel is genuinely better.
  • next/image works out of the box (sharp at runtime). No image CDN config needed.
  • Edge runtime routes (export const runtime = "edge") should be switched back to nodejs — there are no isolates here.

And the things that get easier: WebSockets work (it's your server — keep the socket open), there are no function duration limits for LLM streaming or slow jobs, and pricing is flat per service instead of metered per invocation. The full trade-off table is in our Vercel comparison.

Auto-deploy and previews

Connect the GitHub integration once and pushes to main deploy production; other branches get preview URLs (Pro tier). If Cursor or Claude Code is making the commits, the loop closes without you: agent commits → push → deployed.

When Vercel is still the right call

Static-heavy marketing site, hard dependency on edge middleware latency, or a team already happy there — stay. The point isn't that Vercel is wrong; it's that Next.js is portable, and the moment your app grows a real backend, the container model fits better. More on that decision in the Next.js framework guide and the complete vibe coding hosting guide.