DeployBeginner~1 hour for your first deploy

Deploy your app

You built something that works on your laptop, but "works on my machine" helps no one. Deploying puts your app on the internet with a real URL, HTTPS, and env-based secrets so actual people can use it — and so every future change ships safely instead of breaking prod.

the approach

In 2026 you do not hand-configure servers. You pick a managed platform, connect your Git repo, and let a push to `main` build and deploy automatically — git-push-to-deploy is the whole mental model. Vercel for frontend/Next.js, Railway/Render/Fly.io for full-stack apps and containers. Your job is to make the app configurable through environment variables (never hardcoded secrets), keep `main` always-deployable, and rely on preview deployments to test PRs before they hit production. Treat the platform as the source of truth for prod config; treat your repo as the source of truth for code.

Step by step

  1. 1

    Pick a platform that matches your stack

    Next.js or a static/SPA frontend: Vercel or Cloudflare Pages. Full-stack app with a backend, background jobs, or a database: Railway or Render (both give you a URL from a Git repo in minutes). Need containers or edge regions: Fly.io. Don't overthink it — you can move later.

  2. 2

    Get your code on GitHub first

    Every one of these platforms deploys from a Git repo, not from your hard drive. Push to GitHub, confirm your `.gitignore` excludes `.env`, `node_modules`, and build output, then double-check the repo has no secrets committed in its history.

  3. 3

    Connect the repo and confirm the build command

    Import the repo in the platform's dashboard. The critical settings are the build command (usually `npm run build`), the output directory, and the start command — these must match your `package.json` scripts exactly, or the build fails or serves nothing.

  4. 4

    Move every secret into environment variables

    Database URLs, API keys, and auth secrets go in the platform's Environment Variables / Secrets panel, not in code. Read them via `process.env.X`. Set them for both production and preview environments so preview deploys actually work.

  5. 5

    Turn on preview deployments

    Vercel, Railway, and Render automatically build a throwaway deploy for every pull request with its own URL. This is your single best safety habit: test the PR's live URL before merging, and keep `main` as production.

  6. 6

    Add your custom domain and HTTPS

    Point your domain at the platform (usually a CNAME or the platform's nameservers). HTTPS certificates are issued and renewed automatically — you never touch a cert. Verify the app loads on the real domain, not just the platform's `*.vercel.app` URL.

  7. 7

    Handle database migrations and health checks

    Run migrations as a release/deploy step (e.g. `drizzle-kit migrate` or `prisma migrate deploy`), never a manual step you'll forget. Add a `/health` endpoint so the platform knows when a deploy is actually ready, and never point a seed script at production.

  8. 8

    Know your rollback before you need it

    Every platform keeps previous deployments and lets you re-promote one with a click. Find that button now. A bad deploy should be a 30-second rollback, not a 2am debugging session.

Starter snippet

dockerfile
# Production Dockerfile for a Next.js app (works on Railway, Render, Fly.io).
# Requires `output: 'standalone'` in next.config.js.
# syntax=docker/dockerfile:1
FROM node:22-alpine AS base

FROM base AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci

FROM base AS build
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -g 1001 nodejs && adduser -S -u 1001 -G nodejs nextjs
COPY --from=build /app/public ./public
COPY --from=build --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=build --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
ENV PORT=3000
CMD ["node", "server.js"]

✕ Watch out for

  • Committing a `.env` file or an API key to Git. Even if you delete it later, it lives in your history forever — rotate the key and scrub it. Add `.env` to `.gitignore` before your first commit.
  • Hardcoding `http://localhost:3000` or a dev database URL. In prod those point nowhere. Every environment-specific value must come from `process.env`, and every var must be set in the platform's dashboard.
  • The build passes locally but fails in CI. Usually a Node version mismatch or a case-sensitive-filesystem bug (`import './Button'` when the file is `button.tsx`) — Linux CI cares, your Mac doesn't. Pin your Node version and match filename casing exactly.
  • Running migrations or seed scripts by hand — or worse, running a seed against prod. Migrations belong in a release step; a destructive seed pointed at the wrong `DATABASE_URL` will ruin your day.
  • Shipping straight to `main` with no preview and no rollback plan. When (not if) a deploy breaks, you want a preview URL that caught it and a one-click re-promote of the last good build.

✓ Pro tips

  • Tell your AI agent the exact platform and stack ('deploy this Next.js app to Railway with a Postgres DB'), then make it do two things: grep the whole codebase for `process.env.` and hand you the complete list of env vars the app reads, and confirm the build/start commands in its config match your `package.json` scripts. Missing env vars are the #1 cause of a deploy that builds fine but crashes on boot.
  • Deploy on day one, before the app does anything real. A 'hello world' that's live is worth more than a finished app that's never been deployed — it proves the whole pipeline works while there's nothing to debug.
  • Treat `main` as production and never push directly to it. Open a PR, look at the preview deployment's live URL, then merge. This one habit catches most 'it worked locally' failures.
  • Ask the agent to add a `/health` endpoint and a rollback note to your README so future-you (and the platform) know how to tell a good deploy from a bad one.