Railway Deployment Scripts
Documentation for Deployment
Railway Smart Deploy CLI
A smart deployment tool for Railway that handles git branches, work-in-progress, and automated merging without disrupting development work.
Overview
This CLI automates the process of deploying backend APIs to Railway using git branch-based deployments. It safely:
- Handles uncommitted changes (commit or stash)
- Merges your session branch INTO deploy branches (preserving deploy-specific commits)
- Pushes to trigger Railway builds
- Returns you to your original working state
Quick Start
# Interactive deployment (recommended)
yarn deploy
# Preview what will happen without executing
yarn deploy --dry-run
# Check current deployment status
yarn deploy --status
# Deploy specific APIs
yarn deploy --apis api,ai-api
# Deploy all APIs non-interactively
yarn deploy:all
Available Commands
| Command | Description |
|---|---|
yarn deploy |
Interactive deployment with prompts |
yarn deploy --dry-run |
Preview operations without executing |
yarn deploy --status |
Show current branch/commit status |
yarn deploy:api |
Deploy only backend-api |
yarn deploy:ai-api |
Deploy only backend-ai-api |
yarn deploy:docs-api |
Deploy only backend-docs-api |
yarn deploy:vitto-api |
Deploy only backend-vitto-api |
yarn deploy:sandbox-orchestrator |
Deploy sandbox-orchestrator (optional; see deployment/sandbox-orchestrator/RAILWAY.md) |
yarn deploy:all |
Deploy all APIs at once |
yarn deploy --help |
Show help and available APIs |
CLI Flags
| Flag | Description |
|---|---|
--dry-run |
Preview all operations without executing |
--skip-health-check |
Don't wait and verify health endpoints after push |
--no-interactive |
Use defaults (all APIs, include work) |
--apis api,ai-api |
Pre-select specific APIs (comma-separated) |
--include-work |
Pre-select to commit uncommitted changes |
--stash-work |
Pre-select to stash uncommitted changes |
--status |
Show deployment status and exit |
--help |
Show help and exit |
Deployment Targets
| API | Branch | Health Check |
|---|---|---|
api |
deploy/api |
/api/health |
ai-api |
deploy/ai-api |
/ai-api/health |
docs-api |
deploy/docs-api |
/docs-api/health |
vitto-api |
deploy/vitto-api |
/vitto-api/health |
sandbox-orchestrator |
deploy/sandbox-orchestrator |
/health |
How It Works
Work-in-Progress Handling
When you have uncommitted changes, you can choose:
- Include Work - Commits your changes before deploying
- Stash Work - Temporarily stashes changes, deploys, then restores them
Merge Strategy (One-Way Flow)
The CLI merges your session branch INTO the deploy branches, not the other way around. This is a one-way merge by design.
┌─────────────────────────────────────────────────────────────┐
│ Session Branch (editor2-session-62) │
│ ├── All your development work │
│ └── railway.toml → default config │
└─────────────────────────────────────────────────────────────┘
│
│ merged INTO (one-way)
▼
┌─────────────────────────────────────────────────────────────┐
│ deploy/api → has session code + backend-api config │
│ deploy/ai-api → has session code + ai-api config │
│ deploy/docs-api → has session code + docs-api config │
└─────────────────────────────────────────────────────────────┘
Branch Relationship (Important!)
| Branch | Contains | Purpose |
|---|---|---|
| Session branch | Development work | Source of truth for code |
deploy/api |
Session + api config | Railway deployment target |
deploy/ai-api |
Session + ai-api config | Railway deployment target |
deploy/docs-api |
Session + docs-api config | Railway deployment target |
Key Points:
- Deploy branches are supersets of your session branch
- Deploy branches have everything from session PLUS their specific
railway.toml - Session branch does NOT need changes merged back from deploy branches
- Each deploy branch has a different
railway.toml(that's why we don't merge back)
Why No Merge Back?
The CLI intentionally does NOT merge deploy branches back to session because:
- Each deploy branch has different railway.toml - Merging back would cause conflicts
- Session is source of truth - It already has all the actual code
- Deploy branches are deployment targets - They're meant to diverge slightly with deploy-specific configs
- Cleaner git history - Avoids unnecessary merge commits in your development branch
After deployment, your session branch appears "behind" the deploy branches by 1 commit (the merge commit). This is correct and expected - you're not missing any actual code.
Safety Features
- Git lock detection: Detects and cleans stale
.git/index.lockfiles automatically - Smart rollback detection: Auto-cleans stale rollback states when deployment actually succeeded
- Pre-flight checks: Verifies clean merge is possible before touching anything
- Atomic rollback: Saves branch refs before operations, restores on failure
- Auto-retry on lock: Retries git commands if lock files appear during execution
- Health verification: Waits for Railway build and checks health endpoints
- Named stashes: Uses unique stash names to avoid conflicts
Stability Features (v2)
- Context-based state: Uses deployment context objects instead of global state
- Push verification: Verifies remote ref matches local after push
- Merge cleanup: Automatically cleans up failed merge/rebase state
- Race condition handling: Auto-stashes transient changes (MCP/Cursor writes)
- Unique stash IDs: Stashes use deployment ID to prevent conflicts
- Exponential backoff: Push retries with increasing delays
- Branch validation: Verifies all target branches exist before starting
Workflow Diagram
┌─────────────────────────────────────────────────────────┐
│ yarn deploy │
├─────────────────────────────────────────────────────────┤
│ 1. Pre-Flight Checks │
│ ├── Check for stale git locks │
│ ├── git fetch origin │
│ ├── Verify branches are in sync │
│ └── Check for uncommitted changes │
├─────────────────────────────────────────────────────────┤
│ 2. API Selection (interactive or via --apis) │
├─────────────────────────────────────────────────────────┤
│ 3. Merge Feasibility Check │
│ └── Abort if conflicts detected │
├─────────────────────────────────────────────────────────┤
│ 4. Handle Work-in-Progress │
│ ├── [Include] → Commit changes │
│ └── [Stash] → Create named stash │
├─────────────────────────────────────────────────────────┤
│ 5. For Each Selected API: │
│ ├── git checkout deploy/[api] │
│ ├── git merge ${sessionBranch} │
│ └── git push origin deploy/[api] │
├─────────────────────────────────────────────────────────┤
│ 6. Restore State │
│ ├── Return to original branch │
│ └── Pop stash if used │
├─────────────────────────────────────────────────────────┤
│ 7. Health Check (unless --skip-health-check) │
│ ├── Wait 120s for Railway build │
│ └── Verify health endpoints │
└─────────────────────────────────────────────────────────┘
Troubleshooting
"Git lock exists" or "index.lock" error
The CLI detected a .git/index.lock file. This happens when:
- Another git process is running (IDE, another terminal)
- A previous git command crashed
Automatic handling: The CLI will:
- Check if the lock is stale (older than 60 seconds)
- Remove stale locks automatically
- Retry commands if locks appear during execution
Manual fix (if auto-cleanup fails):
rm -f .git/index.lock
"Merge conflicts detected"
The CLI detected that merging would cause conflicts. Options:
- Manually merge the branches and resolve conflicts
- Check which files conflict:
git merge-tree $(git merge-base deploy/api HEAD) deploy/api HEAD
"Branch out of sync with remote"
Your local deploy branch differs from origin. Run:
git fetch origin
git checkout deploy/api
git reset --hard origin/deploy/api
Rollback after failure
If deployment fails, the CLI automatically rolls back. If you need manual recovery:
- Check for
.deploy-rollback-state.jsonin project root - Run
yarn deploy- it will detect and offer rollback options
Health check fails
This means deployment succeeded but the API isn't responding. Check:
- Railway dashboard for build logs
- Wait longer (builds can take 2-5 minutes)
- Check API logs for startup errors
File Structure
tools/scripts/deployment/
├── railway-deploy-cli.js # Main CLI entry point
├── lib/
│ ├── deployment-config.js # API configurations
│ ├── git-operations.js # Safe git commands
│ ├── branch-manager.js # Branch operations
│ └── state-manager.js # Rollback state
└── README.md # This file
Deployment History
Deployments are logged to deployment/deploy-history.json. View recent deployments:
cat deployment/deploy-history.json | head -50