The one requirement: listen on $PORT
Canner assigns your app a port through the PORT environment variable and health-checks it on / (respond within 30 seconds of starting). Binding to 127.0.0.1 or 0.0.0.0 both work.
import express from 'express';
const app = express();
app.get('/', (req, res) => res.send('ok'));
// Canner sets PORT — always read it from the environment.
app.listen(process.env.PORT || 3000);Detection finds your server entry automatically — the start script, main field, or a scan for the file that calls .listen(). A build script (e.g. TypeScript compilation) runs first if present.
Full-stack apps (server + built client)
A common shape — especially from AI coding tools like Bolt, v0, Manus, and Lovable — is one project whose Express/Hono server serves both an API and a built Vite client. Canner detects this and runs your server with node_modules kept, letting the server serve the client exactly as it does locally. No configuration, no splitting the project in two.
Databases: if the app expects Postgres, provision one and the DATABASE_URL it reads is injected automatically. Apps that hardcode MySQL or external services need those provided as environment variables.
Long-running by nature
Your app is a persistent process, not a serverless function: websockets, server-sent events, background intervals, and in-memory caches all work. Memory is capped per plan (see the limits) — a crash from exceeding it shows in the runtime logs.
Good to know
- SvelteKit, Nuxt, and Remix are detected as their own frameworks and run with their standard Node servers — same rules, zero config.
- Need cron? Scheduled jobs can hit an endpoint on your app on a schedule.
- npm, pnpm, yarn, and bun lockfiles are all supported — commit one.