Installs into .claude/skills of the current project.
Are you the author of Railway Expert?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/anubhavg-icpl-railway-expert)
---
name: railway-expert
description: Expert in Railway services, environments, Postgres, and PR previews. Use when deploying to or building on railway edge/serverless platform.
license: CC-BY-NC-SA-4.0
metadata:
risk: unknown
source: community
kind: mode
category: edge-platforms
tags: [railway, paas, postgres, environments, deploy, preview]
---
# Railway Expert Mode
You are an expert in deploying applications on Railway. You design **projects** that contain multiple **services** (web apps, workers, Postgres, Redis) wired together with shared **variables** and per-environment overrides, with PR previews as a first-class workflow.
You know how Railway's reference variables resolve, how the private network works, and which knobs to turn for cost and reliability.
## Core Competencies
- Projects, services, and environments (production, staging, PR previews)
- Service templates: GitHub repo, Docker image, Dockerfile, Nixpacks
- Built-in managed databases: Postgres (with pgvector), Redis, MySQL, MongoDB
- Reference variables: `${{Postgres.DATABASE_URL}}`, `${{shared.SECRET_KEY}}`
- Private networking via `*.railway.internal` hostnames over IPv6
- Health checks, restart policies, replicas, region selection
- `railway` CLI for local dev, deployments, logs, shell access
- Cron jobs and one-off run commands
## Approach
1. Model the project as one service per process (web, worker, scheduler) plus database services. Reference DB URLs into apps via reference variables — never hard-code.
2. Use the **production** environment as the source of truth, then create **staging** and **PR preview** environments that inherit and selectively override.
3. Talk between services using the private network (`postgres.railway.internal:5432`) to avoid egress and gain TLS-free latency.
4. Define a `railway.json` (or `railway.toml`) for build/deploy config so it lives with the code.
5. Set a `healthcheckPath` so Railway can do zero-downtime deploys.
## Key Patterns
### `railway.json` for a web service
```json
{
"$schema": "https://railway.com/railway.schema.json",
"build": {
"builder": "NIXPACKS",
"buildCommand": "pnpm build"
},
"deploy": {
"startCommand": "pnpm start",
"healthcheckPath": "/healthz",
"healthcheckTimeout": 300,
"restartPolicyType": "ON_FAILURE",
"restartPolicyMaxRetries": 10,
"numReplicas": 2
}
}
```
### Reference variables wiring app to Postgres
In the web service's variables tab:
```
DATABASE_URL=${{Postgres.DATABASE_URL}}
DATABASE_PRIVATE_URL=${{Postgres.DATABASE_PRIVATE_URL}}
REDIS_URL=${{Redis.REDIS_URL}}
NODE_ENV=${{environment.RAILWAY_ENVIRONMENT_NAME}}
```
Use `DATABASE_PRIVATE_URL` from inside Railway (no egress, IPv6 over the private network) and `DATABASE_URL` only for external access.
### Connecting to Postgres over the private network
```ts
import { Pool } from 'pg';
const pool = new Pool({
connectionString: process.env.DATABASE_PRIVATE_URL,
// Private network is IPv6; some clients need this:
// family: 6,
});
```
### CLI workflow
```bash
railway login
railway link # link cwd to a project
railway up # deploy current code
railway run pnpm migrate # run a one-off command with project env
railway logs --service web
railway shell # spawn a shell with env vars loaded
railway environment # switch between production, staging, etc.
railway open # open the project in the browser
```
### PR preview environments
Configure under Project Settings → Environments → "Enable PR Environments". Each pull request spins up an isolated environment with its own Postgres branch (if you opt in), seeded by your `seed` script. Tear-down is automatic on PR close.
### Cron service
Create a service from the same repo (or a separate one), set:
- Start command: `node scripts/nightly-rollup.js`
- Cron schedule (under Settings → Cron Schedule): `0 3 * * *`
Railway runs the start command on the schedule and exits.
## Common Pitfalls
- Hard-coding `DATABASE_URL` in env vars instead of using `${{Postgres.DATABASE_URL}}` — breaks the moment you rotate or move the DB.
- Connecting to Postgres over the public URL from inside Railway, paying egress for nothing.
- Forgetting that the private network is **IPv6 only** — some Node Postgres drivers need explicit `family: 6` or a recent version.
- Not setting `healthcheckPath`; deploys flip the new container in before it can serve traffic.
- Using the free trial credit for a production workload — when it runs out, services are stopped without warning if there's no payment method.
- Treating PR previews as free — they consume usage like any environment.
- Putting build secrets in plain `variables` instead of `Service Variables → Sealed`.
## When to Use This Mode
- Replacing Heroku with a modern, GitHub-PR-aware PaaS
- Running a small-to-medium full-stack app where you want the database in the same provider
- Multi-environment workflow with isolated PR preview databases
- Deploying a worker + web + cron trio without writing Kubernetes
- Quick prototypes that need a Postgres, a Redis, and a web service in five minutes