SPARKZ Network
Guides

deploying a node.js app to plesk with git

A working walkthrough of getting Next.js, Express or any Node app running on Plesk with Passenger — the startup file, the deploy order, and the node_modules mistake that costs people an afternoon.

Hosting9 min read

Plesk runs Node applications through Phusion Passenger, which keeps your app alive as a real long-lived process behind nginx. Once it is set up correctly it is genuinely low-maintenance. Getting there trips people up in three specific places, and none of them are documented where you would look.

This walkthrough assumes shared hosting with the Node.js extension available, and a repository on GitHub, GitLab or Bitbucket.

The startup file is not your framework's CLI

This is the first thing that catches people. Plesk asks for an “Application Startup File” and runs it with Node. It does not run `next start` or `npm start` — it executes one file.

So a framework that normally boots via its own CLI needs a small wrapper. For Next.js that means a file which starts the server programmatically and listens on the port Passenger provides:

const http = require("http");
const next = require("next");

const dev = process.env.NODE_ENV !== "production";
const port = parseInt(process.env.PORT, 10) || 3000;

const app = next({ dev, dir: __dirname });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  http.createServer((req, res) => handle(req, res)).listen(port);
});

An Express app usually needs no wrapper at all — it already listens on a port. Just point the startup file at your existing server entry point and make sure it reads process.env.PORT.

Deploy order matters more than anything else

This is the mistake that costs an afternoon, and the error message points nowhere near the cause.

  1. 01DISABLE the application in Plesk first.
  2. 02Run NPM install.
  3. 03Run your build script.
  4. 04Enable the application again.

Installing while the app is running means npm is replacing files that the running Node process still holds open. It cannot, so it leaves the tree half-written and reports it as a cleanup warning rather than an error.

Setting up Git deployment

  1. 01In Plesk, add a Git repository and paste the remote URL.
  2. 02Choose the branch to track — usually main.
  3. 03Set the deployment path to your application root.
  4. 04Choose automatic deployment so Plesk pulls when you push.

From then on, pushing to that branch updates the files on the server. Note what it does NOT do: it does not run npm install and it does not run your build. When dependencies or built output change, you still run those two steps yourself and restart.

The build has to run before the app starts

Frameworks that compile ahead of time — Next.js, Nuxt, SvelteKit, Astro in server mode — produce a build directory that the server reads at boot. If that directory is missing the app either crashes or silently serves nothing.

It is worth making that failure loud rather than mysterious. A few lines at the top of the startup file will do it:

const fs = require("fs");
const path = require("path");

if (!dev && !fs.existsSync(path.join(__dirname, ".next"))) {
  console.error("Missing .next build output. Run the build before starting.");
  process.exit(1);
}

Now a missing build says so in the log instead of presenting as an inexplicable 503.

Things worth knowing before you start

  • Document root: Plesk warns if it matches the application root. Pointing it at your public folder resolves the warning and lets nginx serve static files directly.
  • Restart after every deploy. Passenger does not always notice changed files on its own.
  • Node version is set per application, so two apps on one account can run different runtimes.
  • Build-time network access matters: anything fetched during the build — Google Fonts, a remote schema — fails on a host with restricted egress. Self-host those assets if the build is not reliable.
  • SSH is available for anything the panel makes awkward, but most routine work does not need it.

When shared hosting is the wrong answer

Being honest about this saves everyone time. Shared hosting Node is a real Node process, not a shim — but you do not get root, you cannot install system packages, and long-running background workers or heavy WebSocket use want a machine of their own.

For a rendered site, an API, or a small headless CMS, shared hosting handles it comfortably and somebody else patches the operating system. Past that, a cloud server is the right call and you can still put Plesk on top so the workflow above barely changes.

Domain search

need a domain to go with it?

Check availability across every extension we sell. Renewal prices shown next to registration prices.