with one click
railway
Deploy backend services and databases to Railway using the Railway CLI
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Menu
Deploy backend services and databases to Railway using the Railway CLI
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Based on SOC occupation classification
Deploy web services, static sites, and workers to Render using the Render CLI
Deploy frontend applications to Vercel using the Vercel CLI
Handle interactive CLI commands safely using tmux (local execution only)
| name | railway |
| description | Deploy backend services and databases to Railway using the Railway CLI |
| metadata | {"version":"2.1.0","author":"OpenOps Team"} |
| risk_level | write |
| platforms | ["railway"] |
| requires | {"cli":"railway","install":"npm install -g @railway/cli"} |
Use this skill when:
Verify installation:
railway --version
To in stall Railway CLI, using:
npm install -g @railway/cli
Or using Homebrew (macOS):
brew install railway
The user must be logged in to Railway CLI:
Verify railway authentication by using
railway whoami
If not authenticated: try to login using non-interactive mode with RAILWAY_TOKEN / RAILWAY_API_TOKEN (when the user provides a token in the environment)
railway login
If this raise error because of non-interactive enviroment does not support, use handling-interactive-commands skill to handle the error and retry with the same command in tmux:
railway login
Expected output (authenticated):
Logged in as user@example.com (User ID: xxx)
Railway uses Nixpacks for automatic detection:
| Framework | Language | Auto-detected |
|---|---|---|
| FastAPI | Python | Yes |
| Django | Python | Yes |
| Flask | Python | Yes |
| Express | Node.js | Yes |
| NestJS | Node.js | Yes |
| Gin | Go | Yes |
| Actix | Rust | Yes |
| Spring Boot | Java | Yes |
Container for related services. Think of it as an environment.
Individual deployable units within a project:
Each project has environments (production, staging, etc.) with isolated:
Do not rely on interactive railway link or menu-driven deploy when acting as an agent. Those prompts often break without a real TTY (e.g. “Available options can not be empty”). For deploy, use this flow:
List projects (JSON) — run from the directory you will deploy (or after cd into the service root):
railway list --json
Each entry includes workspace (id, name), id / name for the project, environments, and services. Use this to build a clear list for the user.
Workspaces only — if you need workspace ids/names separately:
railway whoami --json
The workspaces array lists id and name for each workspace.
Ask the user to choose — present project (name + id). If multiple environments or services apply, ask which environment (and service if needed) before running commands.
Link without prompts (creates/updates .railway in the current directory):
railway link --workspace <workspace_id> --project <project_id_or_name> --environment <environment_name_or_id> [--service <service_name_or_id>] --json
Omit --workspace when the account has a single workspace or the default is correct.
Deploy (after link):
railway up
Non-blocking logs:
railway up --detach
If your CLI supports deploying without a prior link in that directory, you may use:
railway up --project <project_id> --environment <environment_name_or_id> [--service <service_name_or_id>]
(When using --project, --environment is required per Railway docs.)
Automation / CI — prefer RAILWAY_TOKEN (project token) or RAILWAY_API_TOKEN per Railway docs; still use explicit project, environment, and service flags where applicable—do not depend on interactive menus.
Railway CLIs frequently “block” when there are multiple valid targets (multiple workspaces, projects, environments, or services) and the command needs an explicit selection (e.g. it requires --service). As an agent, never stop at a blocker message. Instead, resolve ambiguity with a repeatable “choose one” loop.
Trigger this workflow whenever you see any of the following patterns (stdout/stderr) or equivalent wording:
--service”, “please specify --project”, “environment is required”, “multiple workspaces found”).Fetch canonical options (JSON):
railway list --json
railway whoami --json
Build an option set from the JSON:
workspace.name + workspace.idproject.name + project.idenvironment.name (and id if present)service.name (and id if present)Ask the user to choose (always offer a numbered list):
Retry using explicit flags (non-interactive):
.railway), then run deploy:
railway link --workspace <workspace_id> --project <project_id_or_name> --environment <environment_name_or_id> --service <service_name_or_id> --json
Then:
railway up
railway up --project <project_id> --environment <environment_name_or_id> --service <service_name_or_id>
When prompting the user, keep it short and deterministic:
I found multiple Railway <things>. Which one should I use?
1) <name> — <id>
2) <name> — <id>
...
Reply with the number (or paste the id/name).
If you need multiple picks (project + environment + service), ask them in one message:
Reply with:
- project: (number/id/name)
- environment: (name/id)
- service: (name/id)
Preferred: non-interactive link (see Agent workflow above).
Interactive fallback (human in a real terminal only):
cd /path/to/project
railway link
Or create new project directly:
railway init
For agents, always use JSON:
railway list --json
Human-readable table (optional):
railway list
Expected output (table):
┌──────────────────────────────────┬─────────────────────────────────┐
│ Project │ ID │
├──────────────────────────────────┼─────────────────────────────────┤
│ my-app-prod │ abc123-def456-... │
│ my-app-staging │ xyz789-uvw012-... │
└──────────────────────────────────┴─────────────────────────────────┘
Deploy the current directory:
cd /path/to/project
railway up
Expected output:
☁️ Deploying from /path/to/project
☁️ Build logs available at https://railway.app/project/xxx/deployments/yyy
======= Build Succeeded =======
☁️ Deployment successful 🎉
With detached mode (don't stream logs):
railway up --detach
railway status
Expected output:
Project: my-app-prod (abc123)
Service: api
Environment: production
Latest Deployment:
Status: SUCCESS
URL: https://api-production.up.railway.app
Deployed: 5 minutes ago
railway logs
With follow:
railway logs --follow
railway variables set KEY=value
Or multiple:
railway variables set KEY1=value1 KEY2=value2
railway variables
Expected output:
DATABASE_URL=postgresql://...
REDIS_URL=redis://...
PORT=3000
railway add
Expected output:
? What would you like to add?
Empty Service
> PostgreSQL
MySQL
MongoDB
Redis
railway open
Opens the project in browser.
railway run <command>
Example - run migrations:
railway run python manage.py migrate
railway --version
If CLI not installed:
npm install -g @railway/cli (or brew install railway on macOS)railway --versionrailway whoami
railway list --json
Present projects (and environments/services from the JSON). Ask the user which project (and environment/service if needed) to use.
From the directory to deploy:
railway link --workspace <workspace_id> --project <project_id_or_name> --environment <environment_name_or_id> [--service <service_name_or_id>] --json
Avoid interactive railway link unless the user is at a real terminal and chooses that path.
railway up
Use railway up --detach for non-blocking deploy. You may use railway up --project … --environment … without a prior railway link if the CLI version supports it and the situation calls for it.
railway init
Then run railway up (or railway up --detach) as in step 4.
railway status
Railway provides one-click database deployments:
| Database | Plugin Name | Default Port |
|---|---|---|
| PostgreSQL | postgresql | 5432 |
| MySQL | mysql | 3306 |
| Redis | redis | 6379 |
| MongoDB | mongodb | 27017 |
Database connection strings are automatically injected as environment variables:
DATABASE_URL for PostgreSQL/MySQLREDIS_URL for RedisMONGO_URL for MongoDB| Error Output | Cause | Action |
|---|---|---|
Not logged in | Not authenticated | Ask permission, then run railway login in interactive mode (tmux) when no RAILWAY_TOKEN / RAILWAY_API_TOKEN is available; re-check with railway whoami |
No project linked | Not linked to project | Run railway list --json, ask user to choose project/env/service, then railway link --project … --environment … [--workspace …] [--service …] --json (avoid interactive railway link in agent runs) |
| Mentions multiple projects/workspaces/environments or requires selection | Ambiguous target | Run railway list --json (and railway whoami --json if needed), present a numbered list, ask user to choose, then retry with explicit flags (--workspace/--project/--environment/--service) |
Mentions “needs an explicit --service” (or similar) | Multiple services in the selected project/environment | From railway list --json, present services for the chosen project/env, ask user which service, then rerun railway link ... --service ... --json (or railway up ... --service ...) |
| Mentions environment required / multiple environments | Environment not specified or ambiguous | From railway list --json, list environments for the chosen project, ask user which environment, then rerun with --environment ... |
Build failed | Build error | Execute railway logs to diagnose, then fix |
Project not found | Invalid project | Run railway list --json and reconcile ids/names with the user |
command not found: railway | CLI not installed | Ask permission, then install CLI |
Look for:
☁️ Deployment successful or Deployment successful 🎉======= Build Succeeded =======Look for:
======= Build Failed =======Error: prefixParse railway status output for:
Status: SUCCESS or Status: FAILEDURL: line for public URLOptional configuration file:
{
"$schema": "https://railway.app/railway.schema.json",
"build": {
"builder": "NIXPACKS",
"buildCommand": "npm run build"
},
"deploy": {
"startCommand": "npm start",
"healthcheckPath": "/health",
"restartPolicyType": "ON_FAILURE"
}
}
Alternative for start command:
web: uvicorn main:app --host 0.0.0.0 --port $PORT
worker: python worker.py
Deploy backend API (already set up):
User: "Deploy my FastAPI backend to Railway"
Agent: [executes: railway whoami]
Agent: "You're logged in. Fetching projects..."
Agent: [executes: railway list --json]
Agent: "Projects: my-app-prod, my-app-staging. Which project and environment?"
User: "my-app-prod, production"
Agent: [executes: railway link --project my-app-prod --environment production --json]
Agent: [executes: railway up --detach]
Agent: "Deployed! Service is building. URL: https://api-production.up.railway.app"
Deploy blocked because multiple services (requires --service):
User: "Deploy my backend to Railway"
Agent: [executes: railway whoami]
Agent: "You're logged in. Listing projects/services so we can select the right target..."
Agent: [executes: railway list --json]
Agent: "I found multiple services in the selected project/environment. Which service should I deploy?
1) api — id …
2) worker — id …
3) postgres — id …
Reply with:
- project: (number/id/name)
- environment: (name/id)
- service: (number/id/name)"
User: "project: 1, environment: production, service: api"
Agent: [executes: railway link --project <id_or_name> --environment production --service api --json]
Agent: [executes: railway up --detach]
Agent: "Deploy started. I’ll report the build URL / public URL once it appears in `railway status`."
Check deployment status:
User: "What's the status of my Railway deployment?"
Agent: [executes: railway status]
Agent: "Your service is running:
- Status: SUCCESS
- URL: https://api-production.up.railway.app
- Deployed: 5 minutes ago"
railway list --json → user picks project (and env/service) → railway link … --json → railway up; avoid interactive CLI wizards in agent subprocesses/health endpoint for automatic restartrailway up --detach for non-blocking deployments