Shipzo / Guides / JavaScript · Node.js · Express

How to deploy a Node.js Express app for free

JavaScript · Node.js · Express8 min readUpdated 25 October 2026

Your Express server runs on localhost:3000. To put it online you need three small changes: the port, the start script, and where secrets live. This guide covers all three, plus MongoDB.

Quick answer
  1. Listen on process.env.PORT.
  2. Add "start": "node server.js" to package.json, and commit package-lock.json.
  3. Move database URLs and keys into environment variables.
  4. Push to GitHub and deploy on Shipzo. Tests run first if you have them.

Step 1: Listen on the right port

server.js

const express = require('express');
const app = express();

app.use(express.json());

app.get('/', (req, res) => res.send('API is running'));
app.get('/health', (req, res) => res.json({ status: 'ok' }));

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log(`Listening on ${PORT}`));

Hosting platforms assign the port through the PORT variable. Hard-coding app.listen(5000) is the number one reason Express deploys fail their health check.

Step 2: Fix package.json

package.json

{
  "name": "my-api",
  "version": "1.0.0",
  "main": "server.js",
  "scripts": {
    "start": "node server.js",
    "dev": "nodemon server.js",
    "test": "node --test"
  },
  "engines": { "node": ">=20" },
  "dependencies": {
    "express": "^4.21.0",
    "mongoose": "^8.7.0"
  },
  "devDependencies": {
    "nodemon": "^3.1.0"
  }
}
  • start uses node, not nodemon. Nodemon is for development, where it restarts on file changes.
  • Commit package-lock.json so the server installs exactly the versions you tested.
  • Every require() must be listed in dependencies. A package installed globally on your laptop doesn't exist on the server.
  • Add node_modules/ and .env to .gitignore.

Step 3: Connect MongoDB the right way

mongodb://localhost:27017 only works on your laptop. Create a free cluster on MongoDB Atlas and read the URL from an environment variable:

const mongoose = require('mongoose');

mongoose.connect(process.env.MONGODB_URI)
  .then(() => console.log('MongoDB connected'))
  .catch((err) => { console.error(err); process.exit(1); });
  • In Atlas, under Network Access, allow your host's IP address (or 0.0.0.0/0 for testing). Otherwise the connection times out.
  • In Shipzo, add MONGODB_URI=mongodb+srv://... under your project's Settings → Environment variables. Values are masked in every log.

Step 4 (optional): Add a test

Node has a built-in test runner. With a test script in place, Shipzo runs it before every deploy and blocks the release if it fails:

test/app.test.js

const test = require('node:test');
const assert = require('node:assert');

test('adds numbers', () => {
  assert.strictEqual(1 + 1, 2);
});

Step 5: Push and deploy

git add .
git commit -m "Production ready"
git push
  1. Create a free Shipzo account → New deployment.
  2. Paste the repo link, add your environment variables in step 5 of the form, and press Deploy.

Shipzo detects Express from package.json, installs with npm ci, runs npm test, builds a Node 20 container, starts it with npm start, waits for GET / to answer, then switches traffic. Your API is live at https://your-api.shipzo.tech.

Common errors and fixes

ErrorFix
Health check timed outUse process.env.PORT, or set App port in Settings to the port your app uses.
Error: Cannot find module 'x'Add it to dependencies (npm install x) and commit package.json and the lock file.
MongooseServerSelectionErrorAtlas is blocking the server's IP. Update Network Access.
MONGODB_URI is undefinedAdd the variable in Settings and redeploy.
Works locally, crashes on the serverCheck the runtime logs tab. It's usually a missing environment variable or a file path with different capital letters.

Deploy it in one click

Paste your GitHub repo into Shipzo. Tests, Docker build, HTTPS and monitoring are handled for you. Free during the beta, no card needed.

Create a free account

Frequently asked questions

Does my API sleep when idle?

No. It keeps running, so the first request after a quiet period is fast.

Can I use Socket.io or WebSockets?

Yes. WebSocket connections are passed through to your app.

Is there a free tier?

Yes. Shipzo is free during the beta, with up to 3 projects per account.

Can I deploy NestJS or Fastify?

Yes. Any Node server with a start script or a server.js/index.js entry file works.