Railway and Render Deploys skill for Codex

Your whole PaaS stack declared in the repo. Codex declares web services, workers, cron jobs and managed Postgres or Redis in render.yaml or railway.json instead of dashboard clicks. It binds apps to the injected PORT, wires services with variable references over the private network, runs migrations in the pre-deploy step so a failure never ships, and flags disks and sleeping free instances before they cause outages.

  • Cloud Platforms
  • $paas-deploys
  • 194 lines
  • 2 files
  • ~1,850 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- paas-deploys

Installs to ~/.agents/skills/paas-deploys/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $paas-deploys, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Ships web services, workers, cron jobs and managed Postgres or Redis on Railway and Render - render.yaml Blueprints, railway.json config as code, PORT binding, health checks, pre-deploy migrations, variable references between services, private networking, persistent disks and free-tier limits. Use when deploying an app to Railway or Render, moving off Heroku, wiring a database URL between services, a deploy fails health checks, a free service sleeps, or you want the infrastructure checked into git instead of clicked in a dashboard.

Use it when

  • Deploying a web app, worker or cron job to Railway or Render
  • Migrating off Heroku to a modern PaaS
  • Connecting services and databases with private URLs and variable references
  • Turning a dashboard-configured setup into config checked into git

Use something else when

  • You need multi-region VMs with volumes: use fly-io
  • You want to run everything on your own server: use vps-deploys

How to check the result

A fresh preview or staging environment deploys from the committed config alone, the health check passes, and the database accepts only private connections.

The mistake it prevents

Running migrations in the start command, so every instance races to migrate and a failed migration crash-loops the service.

~/.agents/skills/paas-deploys/SKILL.md

--- name: paas-deploys description: Ships web services, workers, cron jobs and managed Postgres or Redis on Railway and Render - render.yaml Blueprints, railway.json config as code,… license: MIT ---

A good PaaS setup is reproducible from the repo: services, databases and variables are declared in render.yaml or railway.json, migrations run in a pre-deploy step rather than at boot, the app binds to the injected PORT, and services talk over the private network instead of public URLs.

Inspect first

  1. Read AGENTS.md, package.json or equivalent, the Dockerfile if any, and existing render.yaml, railway.json or railway.toml, Procfile.
  2. Find how the app reads its port and database URL. Both platforms inject PORT; the app must listen on 0.0.0.0 (Railway private networking may need ::).
  3. List what the app needs: web service, background worker, cron, Postgres, Redis, disk.
  4. Platform CLIs and dashboards need network and login. In an offline sandbox, write the config files and hand deploy commands to the user.

Choosing between them

FactorRailwayRender
Config as coderailway.json / railway.toml per serviceOne render.yaml Blueprint for the whole stack
BuildsRailpack auto-detect or DockerfileNative runtimes (node, python, ruby, go, rust, elixir) or Docker
Pricing modelUsage-based (CPU, RAM, egress)Per-instance plans
PreviewsPR environmentsPreview environments from the Blueprint
Good fitMany small services, quick experiments, variable referencesStable stacks wanting declarative Blueprints and predictable plan costs

Either is fine for a typical web plus worker plus Postgres app. Pick the one the team already uses; migration between them is mostly config translation.

Render Blueprint

# render.yaml
services:
  - type: web
    name: api
    runtime: node
    plan: starter
    region: oregon
    buildCommand: npm ci && npm run build
    startCommand: node dist/server.js
    preDeployCommand: npm run migrate
    healthCheckPath: /healthz
    envVars:
      - key: DATABASE_URL
        fromDatabase: { name: main-db, property: connectionString }
      - key: REDIS_URL
        fromService: { type: keyvalue, name: cache, property: connectionString }
      - key: SESSION_SECRET
        generateValue: true
      - key: STRIPE_SECRET_KEY
        sync: false            # entered in the dashboard, never in git
      - fromGroup: shared-settings

  - type: worker
    name: jobs
    runtime: node
    plan: starter
    buildCommand: npm ci && npm run build
    startCommand: node dist/worker.js
    envVars:
      - key: DATABASE_URL
        fromDatabase: { name: main-db, property: connectionString }

  - type: cron
    name: nightly-report
    runtime: node
    schedule: "0 4 * * *"
    buildCommand: npm ci && npm run build
    startCommand: node dist/report.js

  - type: keyvalue
    name: cache
    plan: starter
    ipAllowList: []            # private network only

databases:
  - name: main-db
    plan: basic-256mb
    postgresMajorVersion: "17"
    ipAllowList: []

envVarGroups:
  - name: shared-settings
    envVars:
      - key: LOG_LEVEL
        value: info

Plan names change over time; confirm current values in the Render dashboard or docs before committing. Apply a Blueprint from the dashboard (New, Blueprint) the first time; later pushes sync it.

Railway config as code

{
  "$schema": "https://railway.com/railway.schema.json",
  "build": { "builder": "RAILPACK", "buildCommand": "npm run build" },
  "deploy": {
    "startCommand": "node dist/server.js",
    "preDeployCommand": ["npm run migrate"],
    "healthcheckPath": "/healthz",
    "healthcheckTimeout": 120,
    "restartPolicyType": "ON_FAILURE",
    "restartPolicyMaxRetries": 5
  }
}

Each service in a Railway project has its own config file path; set it in the service settings when a monorepo holds several.

railway login
railway link                               # choose project and environment
railway add --database postgres            # adds a Postgres service
railway variables --set "LOG_LEVEL=info"
railway run npm run migrate                # runs locally with the service's variables
railway up                                 # deploy current directory (confirm for production)
railway logs

Variable references wire services together without copying secrets:

DATABASE_URL = ${{Postgres.DATABASE_URL}}          # private connection string
API_INTERNAL = http://${{api.RAILWAY_PRIVATE_DOMAIN}}:${{api.PORT}}
SHARED_FLAG  = ${{shared.SHARED_FLAG}}

Use the private URL for service-to-service and app-to-database traffic; the public URL (DATABASE_PUBLIC_URL) costs egress and is exposed to the internet.

Migrations and releases

  • Run migrations in the pre-deploy step. If it fails, the new version is not released and the old one keeps serving.
  • Never run migrations in the start command of a multi-instance service: every instance races to migrate.
  • Make migrations backward compatible with the running version (expand, migrate code, contract later), because old and new instances overlap during the rollout.

Disks and state

Attaching a persistent disk on either platform pins the service to one instance and usually means a short downtime on each deploy, since the disk cannot attach to two instances. Prefer managed Postgres, Redis and object storage; use disks only for things like a self-hosted CMS that insists on local files, and back them up.

Free tiers and sleeping

  • Render free web services spin down after about 15 minutes idle and take tens of seconds to wake; free Postgres instances expire after a fixed period. Fine for demos, never for production or anything receiving webhooks.
  • Railway trial and hobby credits run out; a service stops when they do. Set usage alerts and limits.

Debug table

SymptomCheck
Deploy fails health checkListening on PORT and 0.0.0.0, health path returns 200 without auth, timeout long enough for boot
ECONNREFUSED to databaseUsing a public URL blocked by allow list, or private hostname from outside the project
Railway private DNS failsApp bound to IPv4 only; listen on ::
Works locally, crashes on bootMissing variable; compare railway variables or the Render env tab with .env.example
Webhooks time outFree instance asleep; upgrade plan or move the endpoint

Verification

  • Config file validates (Render Blueprint preview, Railway schema in the editor).
  • A preview or staging environment deploys from the config with no dashboard edits.
  • Health endpoint returns 200; logs show the pre-deploy migration ran once.
  • Database is reachable only privately; ipAllowList or public networking reviewed.
  • Production deploys, database deletions and plan changes only after explicit user confirmation.

Gotchas

  • generateValue: true creates the secret once; changing the Blueprint later does not rotate it.
  • Deleting a Render database or a Railway Postgres service deletes its data; confirm a fresh backup and get explicit approval first.
  • Build-time and runtime variables differ on Render Docker services; secrets needed during docker build must be passed as build args or secret files deliberately.
  • Cron services run in their own container; they do not share memory or disk with the web service.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Railway and Render Deploys"
  short_description: "Your whole PaaS stack declared in the repo"
  default_prompt: "$paas-deploys Write a render.yaml for our API, worker, cron job and Postgres database"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem