This walkthrough deploys a simple Express API to Railway, sets env vars, and notes how to add a second service later for a queue worker.
Disclosure: Some links are affiliate links. I may earn a commission at no extra cost to you.
What you'll end up with
- A deployed Node/TS HTTP service
- HTTPS URL on Railway
- Env-based config (
PORT,DATABASE_URL, etc.) - A clear path to add a worker process (BullMQ etc.) as a second service
Companion repo
Clone or fork the starter and deploy it as-is:
github.com/ivanpetrus/railway-node-ts-api
Prerequisites
- Node 20+ locally
- A GitHub repo (or Railway CLI)
- ~15 minutes
Step 1 — Minimal API
// src/index.ts
import express from "express";
const app = express();
const port = process.env.PORT || 3000;
app.get("/health", (_req, res) => {
res.json({ ok: true });
});
app.listen(port, () => {
console.log(`listening on ${port}`);
});
package.json scripts:
{
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
}
}
Tip: Railway sets PORT for you — don't hardcode 3000 in production.
Step 2 — Create the Railway project
- Sign up / log in via this link (includes starter credits when eligible): Railway
- New Project → Deploy from GitHub (connect the repo) Or deploy the companion repo above.
- Pick the repo + root directory if monorepo
Step 3 — Build & start settings
Step 4 — Environment variables
Add at least:
NODE_ENV=production- any secrets your app needs (
DATABASE_URL,JWT_SECRET, …)
Never commit .env. Rotate anything you pasted into chat.
Step 5 — Public URL & health check
Generate a Railway domain (or custom domain).
Hit /health — you should see { "ok": true }.
Optional: add a worker later
For BullMQ / background jobs:
- Create a second Railway service from the same repo
- Same build, different start command (e.g.
node dist/worker.js) - Share env vars; put Redis as a plugin/add-on or external Redis
- Cap concurrency so one spike doesn't OOM the service
That's where a lot of solo apps get burned — happy to write a follow-up.
Cost mindset (solo)
- Start tiny; watch the usage dashboard after 24h
- Separate web vs worker so a stuck job doesn't take down HTTP
- Set memory limits / restart policy before you "optimize code"
When Railway is a fit
- Solo/small team, Node/TS API + optional worker
- Want GitHub → deploy without babysitting VMs
- Not a fit if you need multi-region edge at Google scale on day one
Wrap-up
Ship the healthcheck first. Add the worker second. Keep env vars boring.
Deploy link (affiliate): Railway
If you want the same app on a classic VPS/PaaS instead, next post compares Railway vs DigitalOcean for a solo Node API.
Questions / stuck on build commands? Drop an error log snippet in the comments.
In the service settings:
-
Build command:
npm run build(orpnpm/yarn) -
Start command:
npm run start - Watch the first deploy logs for
listening on …
If the build fails on TypeScript, ensure typescript is in dependencies/devDependencies and tsconfig emits to dist/.
Top comments (0)