6 min read
How to deploy a Node.js app with a single git push
Deploying a Node.js app with git push is the simplest way to put it online: you push your code to GitHub or GitLab, and Omeganodes installs the dependencies, builds the app and serves it on an HTTPS address. There is no server to set up, no Dockerfile to write and no pipeline to configure.
This guide takes a small app, a page and a JSON endpoint, from an empty folder to a live URL, then adds environment variables, a database and your own domain, and ends with the errors people hit most. If your project has a package.json, the same steps apply to Express, NestJS or Next.js.
What you need
Three things, all free:
- A GitHub or GitLab account with the repository you want to deploy. Public and private repositories both work.
- Node.js on your computer, to run the app once before you push it.
- An Omeganodes account with a verified email address. The Free plan needs no card.
1. Write a minimal app
Two files are enough. The app listens on the port in the PORT variable, or 3000 when PORT is not set, and on all interfaces (0.0.0.0): a server that listens only on localhost cannot be reached from outside its container.
{
"name": "hello-api",
"version": "1.0.0",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"engines": {
"node": "22.x"
}
}const http = require("node:http");
const port = Number(process.env.PORT) || 3000;
const page =
"<!doctype html><html lang='en'><head><meta charset='utf-8'><title>Hello from Node.js</title></head>" +
"<body><h1>Hello from Node.js</h1><p>Deployed with git push on Omeganodes.</p></body></html>";
const server = http.createServer((req, res) => {
if (req.url === "/api/hello") {
res.writeHead(200, { "content-type": "application/json" });
return res.end(JSON.stringify({ message: "Hello from Node.js", time: new Date().toISOString() }));
}
res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
res.end(page);
});
server.listen(port, "0.0.0.0", () => {
console.log(`Listening on ${port}`);
});Run npm start and open http://localhost:3000 to check that it answers. The engines field pins the Node.js major version; Nixpacks, the build pack Omeganodes uses for a repository without a Dockerfile, reads it when it picks the runtime. Omeganodes runs your start script, so keep it pointing at the file that starts the server.
2. Push it to GitHub
Create an empty repository on GitHub, then push the two files from your project folder:
git init
git add package.json server.js
git commit -m "Hello API"
git branch -M main
git remote add origin https://github.com/<you>/hello-api.git
git push -u origin main3. Create the project
In Omeganodes, open Projects and click New project. Give it a name, for example hello-api, and check the address the page proposes, such as hello-api.sites.omeganodes.com; you can pick another zone (sites, apps, ai, shop or dev) and there are no DNS records to create.
Under the source, paste the repository URL or pick it from the list once GitHub or GitLab is connected, set the branch to main, and leave the root directory on / unless the app lives in a subfolder of a monorepo, for example /apps/api. Click Create project.
4. Watch the first build
The first build starts by itself. Open Logs → Deploy to follow it: you see the dependencies install, the image build and the container start. A first deploy usually takes one to three minutes, and later ones are faster because the layers are cached. When the badge turns Running, open the address: the page says Hello from Node.js, and /api/hello answers with JSON, both over HTTPS with a certificate we issue and renew for you.
From now on every push to main builds and deploys a new version. If a release goes wrong, roll back to any earlier deployment that succeeded. On a monorepo, set watch paths such as apps/api/** so that a push redeploys this app only when its own files change.
5. Add environment variables
Secrets and settings belong in the Env Vars tab, not in the repository. Add each KEY=value pair, or click Paste .env to import a whole file, then click Save & Redeploy: the app restarts with the new values. Values are encrypted at rest and never appear in build logs.
6. Connect a database
Open Databases, click New database, and pick the project and an engine: PostgreSQL, MySQL, Redis or MongoDB. When the database is active, its connection string is injected into the project as DATABASE_URL (REDIS_URL for Redis) and the app redeploys, so your code only reads the variable:
const { Pool } = require("pg");
// DATABASE_URL is injected by Omeganodes when you add a PostgreSQL database.
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
async function countVisits() {
const { rows } = await pool.query("SELECT count(*) AS visits FROM visits");
return Number(rows[0].visits);
}The database has no separate bill: its data counts toward your plan's disk, 1 GB on Free and 5 GB on Starter. Paid plans can restore a database from a backup.
7. Use your own domain
Custom domains start on the Starter plan, €5 a month or €3 in Africa, Latin America and most of Asia. Open Domains on the project and add the records shown there at your registrar: a CNAME for www pointing at your platform address, an A record for the bare domain, and a TXT record that proves you own it. Click Check again once they are published; DNS can take up to an hour. HTTPS is issued automatically as soon as the TXT record matches.
When the build fails
Read the last 20 lines of Logs → Build: the real error is almost always there. The usual causes, and their fixes:
- “no start script” or “command not found”: add a start script to package.json, or set the start command in Settings → Build configuration.
- “ENOENT package.json”: the root directory is wrong. In a monorepo, set it to the app's folder.
- “JavaScript heap out of memory”: the build needs more RAM than the plan has. The Free plan has 256 MB, Starter 512 MB and Pro 1 GB; a large Next.js build usually needs a paid plan.
- The deploy succeeds but the address does not answer: the app listens on 127.0.0.1 or on a fixed port. Listen on 0.0.0.0 and on PORT, as in server.js above, then check Logs → Runtime for a crash at start.
- “permission denied (publickey)”: the repository is private and not connected. Connect GitHub or GitLab under Settings → Git connections, or add a token.
What the Free plan includes
One project with 256 MB of RAM, 1 GB of disk, automatic HTTPS and unlimited deployments, with no card and no end date. Apps on the Free plan run on shared servers on a best-effort basis and show a small “Hosted free on omeganodes.com” banner. For a custom domain, more memory or more projects, Starter, Pro and Business go from €5 to €25 a month, or €3 to €18 in Africa, Latin America and most of Asia.
No Git repository at hand? The same app also deploys from a zip of up to 20 MB, or from the in-browser editor.
Deploy at the speed of Africa
World-class hosting, open to every developer, wherever you build and however you pay. Start free in a couple of minutes — no credit card, no lock-in.