You built a Node.js API or a small Express app and you want it online without paying $20 a month for something that serves a few hundred requests a day. This guide shows the cheapest way to host a Node app in 2026 for each situation: free for a hobby project, about $2 a month for a small always-on API, and about $4 a month with a real Postgres database. It also shows the one memory setting that keeps a Node app stable on a small 256 MB or 512 MB plan, because the cheapest plan is useless if the app keeps dying.
Try it on Hubfly space →: run a small Node API always-on for about $2.23 a month, or free on the shared tier (after a one-time $5 prepaid deposit).
The cheapest way to host a Node app: short answer
| Your situation | Cheapest sensible option | Monthly cost |
|---|---|---|
| Hobby project, OK if the first request is slow | A free tier that sleeps (Hubfly space shared tier after a $5 prepaid deposit, Render Free) | $0 |
| Small API that must answer instantly | An always-on 512 MB container | $2.23–$7 |
| API plus a Postgres database | 512 MB container + the smallest managed Postgres | about $4.15 and up |
| You enjoy running Linux servers | A $4–$6 VPS | $4–$6 plus your time |
| Static frontend only (React, Vite build) | A static host's free plan | $0 |
The rest of this post shows where those numbers come from, what each free tier really gives you, and how to fit a Node app into the smallest plan without crashes.
How much memory a Node.js app needs
Most "cheapest Node hosting" lists skip this question, yet it decides your price. Every platform below charges by RAM size, so the smallest size your app fits in is the cheapest plan you can use.
A minimal Express 5 API on Node.js 22 (one JSON route and a health route, NODE_ENV=production) used:
- About 55 MB of RAM (resident memory) when idle.
- About 130 MB at peak under 50 concurrent connections, serving roughly 12,700 requests a second on 2 CPU cores.
So a typical small API fits in 256 MB, and 512 MB leaves room for a database driver, an ORM and a few dependencies. You only need 1 GB or more for heavy work: image processing with sharp, PDF generation, large in-memory caches, or server-side rendering of big pages.
Why it matters: jumping from 512 MB to 1 GB roughly doubles the price on every usage-priced platform. Measure first, then pick the size.
To check your own app, run it locally and read its memory:
NODE_ENV=production node server.js & ps -o rss= -p $! | awk '{print $1/1024 " MB"}' Then put it under load (for example with npx autocannon -c 50 -d 20 http://localhost:3000/your-route) and check again. Size your plan at about twice the peak you see.
The 256 MB trap: set Node's heap limit yourself
Here's the gotcha that makes small plans look unreliable. On a container with a 256 MB memory limit, Node.js 22 sets its JavaScript heap limit to about 259 MB: more than the whole container. Node notices the container limit, but the heap it picks is still too large for it.
What happens when memory grows (a leak, a big upload, a huge JSON response):
- Without a heap limit: the container hits 256 MB first and the kernel kills it with exit code 137. The logs are empty: no error, no stack trace. You just see a restart.
- With
--max-old-space-size=192: Node stops at 192 MB of heap and printsFATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memoryin your logs, so you know exactly what happened.
On a 512 MB limit, Node 22 picks a heap of about 259 MB, and on 1 GB about 524 MB, so larger plans are safe by default. On the smallest plans, set the limit yourself with an environment variable. Leave about a quarter of the RAM for everything that isn't heap (buffers, native modules, the Node runtime itself):
| Container RAM | Set NODE_OPTIONS to |
|---|---|
| 256 MB | --max-old-space-size=192 |
| 512 MB | --max-old-space-size=384 |
| 1 GB | --max-old-space-size=768 |
NODE_OPTIONS works on every platform in this post because it's read by Node itself, so you don't need to change your start command. If your app already restarts with exit code 137, the fix list under "What can go wrong" below covers the usual causes.
Node.js hosting prices compared (November 2026)
Prices below are for the smallest plan that can run a long-lived Node server (Express, Fastify, NestJS, a WebSocket server), read from each official pricing page on 6 November 2026.
| Platform | Free option for a Node server | Smallest always-on plan | Notes |
|---|---|---|---|
| Hubfly space | Shared tier: 0.3 vCPU, 256 MB, sleeps when idle, 360 active hours a month free | $2.23: 0.5 vCPU, 512 MB, 4 GB disk | Usage-priced (per vCPU-hour and GB-hour); managed Postgres from $1.92 |
| Render | Free: 512 MB, spins down after 15 min without traffic, about 1 min to wake, 750 h per workspace | $7: 512 MB, "less than 1 CPU" | Free instances have no persistent disk |
| Railway | 30-day trial with $5 credit, then $1 a month | Hobby $5 minimum, which includes $5 of usage | Usage at $10 per GB of RAM and $20 per vCPU a month |
| Fly.io | $1 free to start, then pay as you go | $2.19: shared-cpu-1x, 256 MB; 512 MB about $3.69 | Extra RAM $6 per GB a month; North America prices |
| Heroku | None | Basic $7: 0.5 GB | Eco $5 sleeps after 30 min of inactivity |
| DigitalOcean App Platform | Static sites only (3 apps) | $5: 1 vCPU, 512 MiB | 50 GiB transfer included |
| DigitalOcean Droplet (VPS) | None | $4: 1 vCPU, 512 MiB, 10 GiB SSD | You manage the OS, updates, TLS and restarts |
| Vercel | Hobby: free, personal non-commercial use only | Pro $20 | Runs Node as serverless functions, not a long-lived server |
The Fly.io 512 MB figure is the 256 MB preset ($2.19) plus 256 MB of extra RAM at $6 per GB ($1.50).
Where others win, honestly:
- DigitalOcean's $4 Droplet gives you 1 shared vCPU, 512 MiB and 500 GiB of transfer. If you're comfortable patching Ubuntu, setting up Nginx, Certbot and a process manager, it's hard to beat on raw resources. Your time is the hidden cost.
- Render Free gives 750 hours a month, more than Hubfly space's 360 free hours, if a one-minute wake-up is fine for you.
- Vercel Hobby is the easiest free home for a Next.js frontend that you don't sell. It's the wrong tool for a long-running Express server, WebSockets or background jobs.
- Railway's Hobby plan suits people who run several tiny services: the $5 covers all of them as long as total usage stays under $5.
The total bill: Node API plus Postgres
Almost every real app needs a database, and that's where cheap hosting stops being cheap. Here is one always-on Node API (512 MB) plus the smallest managed Postgres each platform sells:
| Platform | Node API | Smallest managed Postgres | Total per month |
|---|---|---|---|
| Hubfly space | $2.23 (0.5 vCPU, 512 MB) | $1.92 (Nano: 0.25 vCPU, 512 MiB, 1 GiB) | $4.15 |
| Render | $7 | $6 (256 MB RAM, storage $0.30 per GB) | $13 plus storage |
| Heroku | $7 (Basic) | $5 (Essential-0, 1 GB) | $12 |
| Railway | Hobby $5 minimum covers small usage | Runs inside the same usage | $5 or more |
Render and Heroku database prices come from the cheapest database for a small app comparison, which also covers Neon, Supabase and Turso free tiers. If you'd rather keep the database on SQLite, put the file on a persistent volume: a 1 GB Standard volume on Hubfly space costs about $0.01 a month. Never keep SQLite on a container's normal disk, because that disk is wiped on every redeploy.
How the Hubfly space numbers add up
Hubfly space charges $0.004 per vCPU-hour, $0.002 per GB-hour of RAM and $0.00001536 per GB-hour of Standard storage, over a 730-hour month:
- CPU: 0.5 vCPU × $0.004 × 730 h = $1.46
- RAM: 0.5 GB × $0.002 × 730 h = $0.73
- Disk: 4 GB × $0.00001536 × 730 h = $0.04
- Total: $2.23 a month, running 24/7.
The shared tier (0.3 vCPU, 256 MB) is free for up to 360 active hours a month and sleeps when idle, so a hobby API that is idle most of the day can stay within the free hours. Creating resources needs a one-time deposit of $5 or more; it's prepaid credit that your usage draws from, not a fee.
Deploy a Node app on about $2 a month
This works on any container platform. The example uses Hubfly space.
1. Make the app container-friendly
Two lines matter most. Read the port from the PORT variable, and listen on 0.0.0.0, not localhost:
// server.js const express = require('express'); const app = express(); const port = process.env.PORT || 3000; app.get('/health', (req, res) => res.send('ok')); app.get('/api/products', (req, res) => res.json([{ id: 1, name: 'Mug', price: 12 }])); app.listen(port, '0.0.0.0', () => console.log(`shop-api listening on ${port}`)); Why 0.0.0.0: an app bound to 127.0.0.1 only answers from inside its own container, so the platform's proxy gets a 502. The 502 Bad Gateway fix explains it in detail.
In package.json, make sure start runs plain Node, not nodemon, and list only what the app needs at runtime in dependencies:
{ "name": "shop-api", "scripts": { "start": "node server.js" }, "dependencies": { "express": "^5.1.0" } } 2. Create the container
- In the Hubfly space dashboard, create a Hubfly space Cell project and pick the region closest to your users.
- Click Create Container and choose your Git repository (GitHub, GitLab, Bitbucket, Gitea or Forgejo) as the source. Hubfly space detects a Node app from its package files, so no Dockerfile is needed.
- Pick the tier: Shared for a free hobby app that may sleep, or Dedicated at 0.5 vCPU / 512 MB for an always-on API. Turn Auto Sleep off if the first request must be fast; the cost panel then shows $2.23/mo.
- Under environment variables, add
NODE_ENV=productionand the heap limit from the table above, for exampleNODE_OPTIONS=--max-old-space-size=384for 512 MB. - Deploy, then open Network → Add Domain → Auto Endpoint to get an HTTPS address for port 3000.
3. Add a database only when you need it
Create a Managed service → PostgreSQL instance at the Nano size (from $1.92 a month) and paste its connection string into a DATABASE_URL variable. Public access is on by default, so restrict it to the addresses that need it before you store real data. The $2 managed PostgreSQL guide covers the connection settings and access rules.
4. Put a ceiling on the bill
Set a monthly budget cap on the project. You get emails at 80% and 90%, and the dashboard says the project's running workloads stop at 100% instead of running up a surprise bill. For a $2 app, a $5 cap is plenty.
Cheap options that cost you later
- Shared web hosting (cPanel plans at $2–$3): some support Node through a "Node.js app" button, but often with old Node versions, no WebSockets and process limits that kill long-running servers. Fine for a static site, risky for an API.
- Serverless for an Express app: you can wrap Express in a function, but every cold start reloads the app, WebSockets don't work, and background timers die between requests.
- Free tiers for anything with users: a sleeping app makes the first visitor wait (about a minute on Render Free), and cron jobs or queue workers inside it simply don't run while it sleeps.
- PM2 cluster mode on a tiny plan: on 0.5 vCPU, four workers just fight over the same half core and multiply memory use by four. In a container, run one Node process and let the platform restart it.
What can go wrong
- The app restarts with exit code 137 and no logs. It ran out of container memory. Set
NODE_OPTIONS=--max-old-space-size=…from the table above, then look for the leak or move up one size. -
502 Bad Gatewayright after deploy. The app listens onlocalhostor on a different port than the one you exposed. Listen on0.0.0.0andprocess.env.PORT. -
JavaScript heap out of memoryin the logs. Good news: the limit works and you can see the problem. Find what grows (often an unbounded cache or loading a whole file into memory), or raise the plan and the limit together. - The first request takes seconds, then it's fast. The app was asleep. Use an always-on plan (Auto Sleep off) if that's a problem for your users.
- Uploaded files or SQLite data vanish after a redeploy. The container disk is temporary. Store files in object storage and databases on a volume or a managed database.
- The build fails at the install step.
package-lock.jsonis often missing or out of sync withpackage.json. Runnpm installlocally, commit the lock file and redeploy.
FAQ
Can I host a Node.js app for free?
Yes, if it can sleep. Hubfly space's shared tier (256 MB, 360 active hours a month) and Render Free (512 MB, 750 hours, about a minute to wake) both run a real Node server for $0 (Hubfly space asks for a one-time $5 deposit of prepaid credit before you create resources). Railway and Fly.io only give starter credit, and Heroku has no free plan.
What is the cheapest way to host a Node app that never sleeps?
An always-on 512 MB container: $2.23 a month on Hubfly space, about $3.69 on Fly.io, $5 on DigitalOcean App Platform, or $7 on Render and Heroku. A $4 VPS is cheaper than most, but you run the server yourself.
Is Vercel free for a Node.js backend?
Only for personal, non-commercial projects, and only as serverless functions. A long-running Express server, WebSockets or background workers need a container or a VPS.
How much RAM does a Node.js app need?
A small Express API idles around 55 MB and peaks around 130 MB under 50 concurrent connections, so 256 MB works and 512 MB is comfortable. Image processing, server-side rendering or big caches need 1 GB or more.
Is a VPS cheaper than a PaaS for Node?
On paper, sometimes: $4 for 512 MiB on DigitalOcean. But you also handle OS updates, firewall rules, TLS certificates, restarts and backups. For one small app, a $2–$5 container usually costs less once your time counts.
Do I need PM2 to host a Node app?
On a VPS, yes, or a systemd service, so the app restarts after a crash or reboot. In a container platform, no: the platform restarts the container, and one Node process per container is the right setup.
Why does my Node app keep restarting on a small plan?
Usually memory. On a 256 MB container, Node 22's default heap limit is bigger than the container, so the kernel kills the app with exit code 137 before Node can log anything. Set NODE_OPTIONS=--max-old-space-size=192.
What's the cheapest way to host Node.js with a database?
A 512 MB container plus the smallest managed Postgres: about $4.15 a month on Hubfly space, $12 on Heroku and $13 plus storage on Render. Or keep SQLite on a persistent volume for about a cent a month extra.
Go further on Hubfly space
- Deploy on every push: connect GitHub Actions so each merge ships automatically. See deploy on push with GitHub Actions and the deployment pipelines docs.
- Add a managed database: Postgres or SQLite (libSQL) from $1.92 a month, MySQL from $3.82. Start with the Managed Databases docs.
- Compare pricing models: if your traffic is spiky, the fixed vs pay-as-you-go break-even guide shows when each one wins.
Try it on Hubfly space →: put your Node app online for free on the shared tier (after a one-time $5 prepaid deposit), or always-on for $2.23 a month.
By Octave · drafted with AI, reviewed by Octave · Last updated 6 November 2026 · Applies to Node.js 22 LTS and Express 5
Originally published on the Hubfly space blog.
