Right now your project only exists while you are looking at it. You type npm run dev, a
development serverA program on your own machine that serves your site to your browser while you work, and rebuilds it every time you save a file.
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 A computer that stays on and answers requests from the internet. Same hardware ideas as your laptop, different job. and keeps it running after you disconnect.
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.comHow 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 (
.nextfor Next.js,distfor 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
A site made only of pre-built files. There is no program running on the server, so there is nothing to crash.
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 startrefuses to run in that mode and tells you to serve theoutfolder 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
- Run
npm run buildon 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 treatsButton.tsxandbutton.tsxas the same file and Linux does not. - Pin the Node version instead of remembering it. Run
node --version, then put the major version inpackage.jsonas"engines": { "node": "24.x" }. That is the file Vercel, Render and Railway all read, and Vercel accepts major versions only. An.nvmrcfile is worth adding as well for your own machine and for Render, but Vercel does not read it, so.nvmrcalone 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. - 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.