Right now your project only exists while you are looking at it. You type npm run dev, a starts, and the site appears at http://localhost:3000. Close the laptop and it is gone. Nobody else could have reached it anyway.

Deploying is the work of changing that. The word covers two separate steps that beginners tend to run together, which is why the first attempt usually fails in a confusing way.

The idea

Deploying puts a copy of your project on a computer that is always on and has a public address, then starts it there. First a build turns your source files into the compressed, rearranged output a browser can actually load. Then a run step starts that output on a and keeps it running after you disconnect.

code
  YOUR LAPTOP                            A SERVER SOMEWHERE
  ------------                           --------------------

  src/  package.json
     |
     |  git push                         a clean checkout of
     +------------------------------->   your repository
                                              |
                                              |  step 1: build
                                              |  npm run build
                                              v
                                          .next/   dist/
                                              |
                                              |  step 2: run
                                              |  npm start
                                              v
                                         listening on port 3000
                                              |
                                         https://yourapp.com

How it works

  • The build is a translation. Your TypeScript becomes JavaScript, twelve CSS files become one, images get resized, and anything unused gets dropped. The output folder (.next for Next.js, dist for Vite) is what the server runs. Only part of it, the static files, is ever sent to a visitor's browser. Your source goes to the server too, since the server is usually where the build runs, but nobody visiting the site downloads it.
  • This assumes your project is on GitHub. A managed platform deploys by watching a repository, so a project that only exists in a folder on your laptop has a step before this one. Version control, plainly is that step.
  • The run step is a process that has to survive. On a plain server, closing your SSH connection kills whatever you started, so something has to restart the process when it crashes or when the machine reboots. On Linux that job usually belongs to systemd. Managed platforms do it for you and never mention it.
  • Some sites skip the run step entirely. If every page can be generated at build time, the output is just files, and a can be served by anything. Sites with logins, databases or payments need a running process. In Next.js that choice is the output: "export" setting, and it changes the start command: next start refuses to run in that mode and tells you to serve the out folder instead.
  • The dev server is a different program from the production one. It is slower, it shows you friendly error pages, and it tolerates mistakes that the real build rejects.

What to do

  1. Run npm run build on your own machine before you deploy anything. Most first deploys fail at the build, not at the server. A type error or an import with the wrong capitalisation will pass in dev and fail in the build, because macOS treats Button.tsx and button.tsx as the same file and Linux does not.
  2. Pin the Node version instead of remembering it. Run node --version, then put the major version in package.json as "engines": { "node": "24.x" }. That is the file Vercel, Render and Railway all read, and Vercel accepts major versions only. An .nvmrc file is worth adding as well for your own machine and for Render, but Vercel does not read it, so .nvmrc alone leaves you on whatever default the dashboard has. Version drift between your machine and the server is the most common cause of a build that works in one place and fails in the other.
  3. Ask your AI assistant for the two commands separately. "What is the build command and what is the start command for this project?" Knowing those two strings is most of what deploying is.

Where it breaks

"It works on my machine" is almost always something your machine has that the server does not: a file that never got committed, a package you installed globally a month ago, a database running on localhost, or an environment variable sitting in a .env file that git ignores. The server starts from a clean checkout of your repository and nothing else, which is exactly what makes it a useful test and exactly what makes the first attempt painful.

The other trap is treating deployment as the last task. A project that has never been deployed has an unknown amount of work hiding in it. Deploy an empty page in week one, while the only thing that can be wrong is the deployment itself. One thing has to happen before that first push, though: secrets and environment variables explains which files must never reach GitHub, and it is cheaper to read now than to rotate a key later.