← Blog
Deployment

Build Commands vs Start Commands: Why the Distinction Matters in Production

Running your dev command in production is one of the most common mistakes that makes apps work but run badly. Here is the difference between building and starting, and why it matters.

ThomasThomas·2026-06-01

When you run your app locally, you probably type npm run dev or something similar. It starts a server, you open a browser, and things work. When you deploy, many developers run the same command on the server.

This is understandable. It works. But it is one of the most common ways to ship a slower, more fragile app than you need to.

What the dev command actually does

A development server does several things that are useful when you are actively building but wasteful when an app is serving real traffic:

It watches your files for changes and rebuilds when something is modified. On a production server, nobody is modifying files. This watcher consumes resources doing nothing.

It compiles TypeScript to JavaScript on every request or file load, using an in-memory compiler that is fast for iteration but not optimized for throughput.

It generates source maps and includes debug information so that error messages show you original TypeScript line numbers rather than compiled JavaScript. This is helpful for debugging but adds size and overhead to every response.

It disables or weakens caching so that you always see the latest version of your code without needing to clear anything. In production, caching is how you serve things fast.

It may run in an error-tolerant mode that continues running even when there are type errors or syntax problems. In production you want a crash to be loud, not silent.

None of this makes your app wrong. It makes it slower and less efficient than it could be.

What the build step does

Running npm run build transforms your source code into optimized output meant for a production server. Depending on your framework, this means:

TypeScript is compiled to JavaScript once, ahead of time. The compiled output is what runs. No more per-request compilation.

JavaScript is minified and tree-shaken, meaning dead code is removed and file sizes are reduced. Smaller files load faster.

Assets are hashed and optimized. CSS is minified. Images may be processed. Everything is prepared for efficient serving.

The output is a directory of static files and a server entry point that can be started directly with Node.js, without any additional tooling.

What the start command does

The start command runs the compiled output. For most frameworks this is something like node dist/server.js or node build/index.js. It is a plain Node.js process running pre-compiled code, with no watchers, no on-the-fly compilation, and no development tooling.

This is what npm start should do. If your package.json does not have a start script, or if the start script runs the dev server, you need to add or fix it.

{
  "scripts": {
    "dev": "ts-node-dev src/index.ts",
    "build": "tsc",
    "start": "node dist/index.js"
  }
}

The deployment platform runs npm run build to compile your code, and then npm start to run it. If start runs the dev server, the platform is running development tooling in production.

Framework-specific patterns

Next.js: next build produces the .next directory. next start serves it. Do not use next dev in production.

Vite + Express (or similar): vite build produces the dist directory. The server entry point is typically compiled separately with tsc. The start command runs the compiled server file.

AdonisJS: node ace build compiles the app into the build directory. node build/bin/server.js starts it.

NestJS: nest build or tsc produces the dist directory. node dist/main.js starts it.

Remix: remix build produces the build directory. The start command depends on your deployment adapter.

How to tell if you are doing it wrong

Look at your deployment platform's start command configuration. If it says npm run dev, ts-node src/index.ts, or nodemon anything, you are running a development server in production.

Look at your startup logs. If the app logs something about watching for file changes, restarting on modification, or running in development mode, you are running a development server.

Check your NODE_ENV. It should be production. Many frameworks and libraries check this value and change their behavior accordingly. Running without it, or with NODE_ENV=development, means you are in a mode designed for a developer at a keyboard, not a server under production load.

The performance difference

The difference between a dev server and a production server is not marginal. A compiled Next.js app typically handles two to three times more requests per second than the same app running under next dev. The startup time is shorter. Memory usage is lower. Response times are faster.

For a small side project with low traffic, this may not matter. For anything with real users, it is worth getting right from the start.

Jetpacked detects the correct build and start commands for your framework and sets them automatically. If your package.json is missing a start script or has a dev server wired to start, it resolves this before deployment rather than letting a slower configuration go live.

Deploy your app in minutes

Jetpacked handles Docker, HTTPS, databases, and deployments so you can focus on building.

Launch your app free