Railway has become one of the best platforms for deploying backend applications. It's fast, the free tier is generous, and PostgreSQL is built in. This guide walks you through deploying a NestJS application from zero to production in about ten minutes.
Prerequisites
- A NestJS application in a GitHub repository
- A Railway account (free tier works)
- PostgreSQL as your database (Railway provides it)
Step 1: Add a Dockerfile
Railway can detect Node.js projects automatically, but a Dockerfile gives you full control over the build. Here's a production-optimized Dockerfile for NestJS:
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 8080
CMD ["node", "dist/main"]
This uses a multi-stage build β the first stage compiles TypeScript, the second stage copies only the compiled output and production dependencies. The final image is lean and fast to start.
Step 2: Configure Your App to Listen on PORT
Railway assigns a dynamic port via the PORT environment variable. Your NestJS main.ts must read it:
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const port = process.env.PORT || 3000;
await app.listen(port);
console.log(`Application running on port ${port}`);
}
bootstrap();
Step 3: Create a Railway Project
- Go to railway.app and sign in with GitHub
- Click New Project β Deploy from GitHub repo
- Select your repository
- Railway will detect the Dockerfile and start building
Step 4: Add PostgreSQL
- In your Railway project, click New β Database β PostgreSQL
- Railway creates the database and automatically provides
DATABASE_URL - In your NestJS service, reference it:
process.env.DATABASE_URL
If you're using Prisma, add a postinstall script to generate the client automatically:
// package.json
"scripts": {
"postinstall": "prisma generate",
"build": "nest build"
}
Step 5: Set Environment Variables
In Railway's dashboard, go to your service β Variables and add:
NODE_ENV=production
JWT_SECRET=your-secret-key
FRONTEND_URL=https://your-frontend.vercel.app
Railway automatically injects DATABASE_URL from the PostgreSQL service β you don't need to set it manually.
Step 6: Run Prisma Migrations
The safest approach is to run migrations before starting the server. Add this to your Dockerfile CMD or a start script:
CMD ["sh", "-c", "npx prisma migrate deploy && node dist/main"]
Or use Railway's Start Command override in the service settings.
Step 7: Custom Domain
- In Railway, go to your service β Settings β Networking β Custom Domain
- Enter your domain (e.g.,
api.yourdomain.com) - Add a CNAME record at your DNS provider pointing to the Railway-provided hostname
- Railway provisions an SSL certificate automatically
Monitoring Your Deployment
Railway shows real-time logs in the Deployments tab. If your build fails, the logs will tell you exactly why. Common issues:
- PORT not set: Make sure your app reads
process.env.PORT - Prisma client not generated: Add
prisma generateto your build step - Missing env vars: Check the Variables tab for typos
Automating This With PromptForge
Every project generated by PromptForge includes a production-ready Dockerfile, a railway.json configuration, and a Prisma setup that's compatible with Railway's PostgreSQL. You can go from prompt to deployed API in under 15 minutes β no manual configuration required. Try it free.