Deploy an Express application
Kuppit detects an Express application from the express dependency together with a start script, and starts it with that script. Express does nothing with PORT on its own, so the server has to.
What Kuppit detects
| Setting | Value | From |
|---|---|---|
| Framework | Express | The express dependency and a start script. Without a start script, nothing is detected. |
| Node version | 24, or what engines.node in package.json admits | Only engines.node is read. 24 and 22 are supported. |
| Package manager | pnpm, npm or Yarn | The lockfile, or the packageManager field. |
| Build command | Your build script, if there is one | A TypeScript compile, say. Absent for plain JavaScript. |
| Start command | npm start, pnpm start or yarn start | Your start script. |
| Port | 3000 | A default; PORT overrides it at runtime. |
Before you deploy
Kuppit starts the container with PORT set and sends every request, and the health check, to that port. Listen on it, on all interfaces:
import express from 'express'
const app = express()
app.get('/', (request, response) => {
response.send('ok')
})
const port = Number(process.env.PORT ?? 3000)
app.listen(port, '0.0.0.0', () => {
console.log(`listening on ${port}`)
})
A server that listens on a fixed port, or on localhost, starts fine and then fails the health check with The application did not become healthy. A start script that runs ts-node or tsx is fine as long as it is in dependencies rather than devDependencies; the build installs what production needs.
Deploy
Follow the Quickstart: install the GitHub App, choose the repository and branch, confirm the proposal, and choose Deploy analyzed commit. When the deployment reaches Live, the service's hostname answers.
Configuration
Everything your server reads from process.env comes from the service's Variables tab and what the environment provides. Add a value, mark it secret if it is one, and Redeploy now: a variable changes the next deployment, never the running one.
Add a database
On the environment's Overview, Add resource, PostgreSQL. Keep the name database. Add DATABASE_URL on the Variables tab as a Reference to database → DATABASE_URL, then redeploy:
import { Pool } from 'pg'
export const db = new Pool({ connectionString: process.env.DATABASE_URL })
A pool is the right shape for a long-running server; open it once at start-up rather than per request.
From here
Every push to the branch deploys again, and every pull request gets a preview environment. If the revision starts and then stops, or never answers, Start and health failures is the page.