ANTIGRAVITY LABJP
Articles/App Development
App Development/2026-05-01Intermediate

Deploying Apps with Antigravity to Railway — A Practical Middle Ground Between Cloudflare Workers and Vercel for Indie Developers

A hands-on guide to deploying from Antigravity to Railway. Covers when Cloudflare Workers and Vercel fall short, and how Railway fills that gap for long-running tasks and persistent connections.

antigravity435railwaydeployment7indie-dev19

"I deployed to Cloudflare Workers and got knocked out by the 30-second limit. Switched to Vercel, then couldn't keep persistent Postgres connections alive." I've been hearing this from indie developers building server-side pieces with Antigravity lately, and I've hit the same wall myself — usually when wiring up an image-generation proxy or a Stripe webhook retry queue.

Railway is the practical escape hatch I keep coming back to in those moments. It isn't fully edge like Cloudflare Workers, and it isn't serverless like Vercel Functions. It's a container-based PaaS that behaves more like a "lightweight VPS you don't have to maintain," which turns out to be a very natural fit for solo projects. In this guide, I'll walk through what it actually takes to get a typical Next.js + Postgres + worker setup onto Railway, using Antigravity's terminal and AI agent to keep the moving parts in check.

When Railway makes more sense than Cloudflare or Vercel

The starting point isn't a generic platform comparison — it's "where did your project actually get stuck?" In my experience, Railway becomes the right answer when one or more of these apply:

  • Your code includes work that takes longer than 30 seconds (PDF generation, AI inference, video transcoding)
  • You want a managed Postgres or Redis with persistent connections
  • You need a background worker (cron jobs, queue consumers) running as a long-lived service
  • You rely on a writable local filesystem for intermediate files
  • You want to run an existing Dockerfile as-is without rewriting it for serverless

For purely static sites, lightweight APIs, or workloads that need extreme edge scale, Cloudflare Workers and Vercel are still better. Think of Railway as "the second deployment target you keep in your back pocket" for the moments when you need something a little thicker.

For background, my Vercel deployment workflow guide and Cloudflare Workers deployment notes cover the other two corners of the triangle. I'd recommend reading them alongside this piece before you commit to a stack.

Preparing your project from inside Antigravity

I'll use a fairly standard setup as the example: Next.js 15 + a Hono server + Postgres. Inside Antigravity, the prompt I usually hand to the agent is short:

Make this project deployable to Railway. Please:
- Add a multi-stage alpine Dockerfile
- Add railway.json with restartPolicyType=ON_FAILURE
- Verify the package.json start script honors PORT
- Add a .dockerignore

When the agent comes back with a diff, the two things you should actually read by hand are the Dockerfile and the start script. Railway injects a PORT environment variable, so a server that hardcodes a port will crash on boot.

# Dockerfile
FROM node:22-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
 
FROM node:22-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
 
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
# Don't hardcode a port; Railway injects PORT at runtime
EXPOSE 3000
CMD ["node", "server.js"]

What to expect: with output: "standalone" enabled in your next.config, the final image lands around 180–220MB and cold-starts in 2–4 seconds. Without standalone mode, the image often balloons past 1GB, so check that flag first.

The minimum viable railway.json looks like this:

{
  "$schema": "https://railway.app/railway.schema.json",
  "build": { "builder": "DOCKERFILE", "dockerfilePath": "Dockerfile" },
  "deploy": {
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 10,
    "healthcheckPath": "/api/healthz",
    "healthcheckTimeout": 30
  }
}

The healthcheck is what I'd actually consider the most useful field. If the new container crashes on boot, Railway rolls back to the previous revision automatically, which has saved me more than once after late-night refactors.

Use Antigravity's review pass to flush out the obvious failures

This is where pairing Railway with an AI IDE earns its keep. After the scaffold is in place, I send the agent another prompt:

Before we deploy this to Railway, please review the codebase strictly for:
1) Any code that doesn't honor the PORT env variable
2) Persistent writes to the local filesystem
3) ORM settings that might explode connections (Prisma prepared statements, pool size)
4) Bare cron / setInterval usage
5) Secrets accidentally exposed via NEXT_PUBLIC_

In practice, this review almost always surfaces one or two real fixes. Prisma projects are the worst offender for me — without an explicit connection_limit, Railway's Postgres tends to saturate within minutes of going live and you end up watching your service throw 502s.

// lib/prisma.ts
import { PrismaClient } from "@prisma/client";
 
const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };
 
export const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({
    datasources: {
      db: {
        // Append ?connection_limit=5 to Railway's DATABASE_URL
        url: process.env.DATABASE_URL,
      },
    },
  });
 
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

What to expect: for indie-scale traffic, connection_limit=5 is plenty. While you don't yet have a clear feel for concurrency, picking a fixed number well below your Postgres plan's ceiling is the boring move that prevents 2 a.m. fire drills.

Wire up environment variables with Reference variables

One of Railway's nicer ergonomics is Reference variables. Once you add the Postgres plugin, your web service can pull the connection URL from ${{Postgres.DATABASE_URL}} instead of manually copying it.

DATABASE_URL=${{Postgres.DATABASE_URL}}
REDIS_URL=${{Redis.REDIS_URL}}
NEXT_PUBLIC_SITE_URL=https://${{RAILWAY_STATIC_URL}}
NEXTAUTH_URL=https://${{RAILWAY_STATIC_URL}}
NEXTAUTH_SECRET=YOUR_NEXTAUTH_SECRET

What to expect: when Railway rotates plugin credentials or URLs, you don't have to touch your service config — Reference variables resolve at deploy time. I ask Antigravity to "rewrite my .env.example assuming Railway Reference variables," and it produces a clean file like the one above in a single step.

For custom domains, add the domain in the Railway dashboard and point a CNAME at XXXX.up.railway.app. If you're fronting Railway with Cloudflare, I'd suggest connecting in DNS-only mode first to verify, then enabling the proxy. This makes troubleshooting TLS or header rewrites much easier.

Run web, worker, and cron from one repository

Railway lets you spin up multiple services from the same repository, which is a perfect match for a typical indie SaaS layout:

  • web: the Next.js + Hono API
  • worker: a queue consumer (BullMQ or similar)
  • cron: a once-a-day batch job

You can keep a single Dockerfile and override the start command per service in Railway's UI.

{
  "scripts": {
    "build": "next build",
    "start": "node server.js",
    "start:worker": "node dist/worker.js",
    "start:cron": "node dist/cron.js"
  }
}

What to expect: pointing the web service to npm run start and the worker to npm run start:worker is enough — three processes, one repo, one Dockerfile. Compared to Cloudflare Workers Cron or Vercel Cron, long-running jobs and always-on workers are noticeably more straightforward on Railway.

If you're shaping a queue topology, my Antigravity multi-tool orchestration notes are a useful companion for deciding how aggressively to split your workers.

The honest constraints to weigh before you commit

A few practical limits worth knowing before you push real traffic:

  • The free tier is execution-time based (around 500 hours of credit per month at the time of writing). Two always-on workers will burn through it fast
  • Regions span US / EU / Asia-Southeast / Asia-Northeast, but mixing regions across services adds inter-service latency. Keep them aligned by default
  • PORT must be honored — any hardcoded port crashes immediately
  • No built-in CDN. Pair Railway with Cloudflare R2 or Vercel Edge Network for static assets if you care about global delivery
  • Logs are stdout-based. Investing in structured logging makes railway logs filtering far less painful

I capture all of these in my agents.md so future projects inherit the same pre-deploy checklist instead of relearning the lessons each time.

Closing thought — keep Railway as your "second deployment target"

Even when Cloudflare Workers and Vercel cover 80% of your projects, the moments where you need long-running tasks, persistent connections, or always-on workers will arrive. Setting up a single Railway service today, before you actually need it, means you have a working escape route the next time you hit those walls.

For a concrete next step: scan your current project for any task that doesn't comfortably finish within 30 seconds. If even one comes to mind, copy the Dockerfile and railway.json from this article and ask Antigravity to "wire up an initial Railway deploy." You should have a staging environment running in about 15 minutes.

Share

Thank You for Reading

Antigravity Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

App Dev2026-05-24
Running iOS Push Notification A/B Tests Weekly With Antigravity Agent — A Self-Improving Loop For Copy, Timing, And Segments
Drawing on 12 years of indie iOS app development across wallpaper and wellness apps with over 50 million cumulative downloads, this article walks through a weekly Push Notification A/B testing loop powered by Antigravity Agent. It covers the FCM bridge, BigQuery measurement, segment design, and a real D7 retention recovery story.
App Dev2026-05-06
How I Tripled Wallpaper App Revenue Using Antigravity — AdMob Optimization to ASO (2026)
A case study on using Antigravity to overhaul a wallpaper app — improving AdMob revenue, App Store ratings, and organic downloads. Only the changes that actually moved the numbers, with real results.
App Dev2026-04-28
Build a Complete SaaS in Antigravity — Stripe Billing, Auth, and Deployment Without Leaving Your IDE
Build an entire SaaS product within Antigravity IDE — from Supabase auth to Stripe billing to Cloudflare Workers deployment, without switching tools.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →