Deploy a Node / Express API
A JSON API on Express, live on an HTTPS URL.
An Express API is the simplest thing to run on Dockhold: it's already a long-running server. You just need it to listen on the assigned port. This recipe is the whole path.
In a hurry? Start from the ready-made express-api-starter template — click Use this template on GitHub, then deploy it. Or follow the steps below to set up a project you already have.
1. Listen on the assigned port
Read the port from the environment and bind all interfaces:
const express = require("express");
const app = express();
app.get("/health", (_req, res) => res.send("ok"));
const port = process.env.PORT || 3000;
app.listen(port, "0.0.0.0", () => {
console.log(`listening on ${port}`);
}); And give it a start script in package.json:
{
"scripts": {
"start": "node server.js"
}
}
Your app must listen on 0.0.0.0 and read its port from the
PORT environment variable — never localhost, never a
hardcoded port. Dockhold assigns PORT at runtime; an app that
ignores it can't receive traffic.
2. Read config and secrets from the environment
Set plain config (feature flags, public URLs) in the dashboard. Put secrets
— API keys, tokens, passwords — in the Vault; they're encrypted and injected
at runtime, so they never live in your repo. Read everything from
process.env; don't hardcode values.
3. Add a database (optional)
Enable the managed Postgres add-on and Dockhold injects
DATABASE_URL. Read it directly:
const { Pool } = require("pg");
const pool = new Pool({ connectionString: process.env.DATABASE_URL }); Apps are stateless — the container filesystem is wiped on every restart and deploy. Persist anything you need to keep in the database, not on local disk.
4. Connect the repo and deploy
- Push the project to a GitHub repository.
- Open the dashboard, connect GitHub, and pick the repo.
-
Dockhold detects the Node project, runs
npm install, and starts it withnpm run start. No Dockerfile needed.
Your API goes live at https://<your-app>.dockhold.app
with HTTPS handled for you. Every later push to your main branch redeploys.
Troubleshooting
- URL times out: you must pass
"0.0.0.0"toapp.listenand useprocess.env.PORT— bindinglocalhostor a fixed port means no traffic reaches you. - CORS errors from a browser frontend: set the allowed
origin to your deployed frontend URL via an env var; don't hardcode
http://localhost. - Database connection refused: read
process.env.DATABASE_URL— don't point atlocalhost.
Next
- Add a Vite + React frontend
- Agent rules — make your AI tool generate Dockhold-ready apps.
- All recipes