Skip to content

Commit f8b549d

Browse files
PAMulliganclaude
andauthored
feat: add Railway deployment target (#117)
Add --railway to setup-project.sh alongside --cloudflare, --node, and --lambda. Railway deploys the same multi-stage Docker image as the Node.js target, so the runtime code is shared: the railway platform reuses the node snippets and node-server Dockerfile/compose, adding Railway config-as-code on top. - templates/railway/: railway.toml (Dockerfile build, /health check, start command, restart policy) and nixpacks.toml (pnpm + Node 22 pins for the non-Docker build) - setup-project.sh: --railway flag, .env.example with Railway reference-variable notes (DATABASE_URL via Postgres reference), README deployment instructions (dashboard setup, root directory, service variables, auto-deploy, migrations via railway run) - No deploy workflow generated: Railway auto-deploys the connected GitHub repo, gated by the /health check - CI: require templates/railway; no new snippets to type-check - deployment-config-generator (Step 2d) and schema-intake skills, pipeline.config.json, and docs updated for the fourth target Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent c05990b commit f8b549d

15 files changed

Lines changed: 256 additions & 29 deletions

File tree

.claude/CUSTOM-AGENTS-GUIDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Integration testing, contract testing, load testing for APIs.
8989

9090
### devops-automator (blue)
9191
Docker, CI/CD pipeline generation, deployment automation.
92-
- **When to use:** Setting up Docker, creating CI/CD, deploying to Cloudflare Workers, Node.js, or AWS Lambda
92+
- **When to use:** Setting up Docker, creating CI/CD, deploying to Cloudflare Workers, Node.js, AWS Lambda, or Railway
9393
- **Key capabilities:** Multi-stage Docker, GitHub Actions, wrangler deploy, PM2, health endpoints
9494

9595
---

.claude/agents/devops-automator.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
---
22
name: devops-automator
3-
description: API deployment and CI/CD specialist for Docker, GitHub Actions, Cloudflare Workers, Node.js, and AWS Lambda deployments. Use when setting up deployment pipelines, configuring Docker, managing Workers deployments, deploying with SAM, or automating build processes.
3+
description: API deployment and CI/CD specialist for Docker, GitHub Actions, Cloudflare Workers, Node.js, AWS Lambda, and Railway deployments. Use when setting up deployment pipelines, configuring Docker, managing Workers deployments, deploying with SAM, configuring Railway services, or automating build processes.
44
color: blue
55
tools: Bash, Read, Write, Grep, MultiEdit
66
---

.claude/pipeline.config.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
"noAnyTypes": true
6969
},
7070
"deployment": {
71-
"targets": ["cloudflare-workers", "node-docker", "aws-lambda"],
71+
"targets": ["cloudflare-workers", "node-docker", "aws-lambda", "railway"],
7272
"defaultTarget": "cloudflare-workers",
7373
"cloudflareWorkers": {
7474
"compatibilityDate": "2024-12-01",
@@ -96,6 +96,15 @@
9696
"framework": "sam",
9797
"provisionedConcurrency": 0
9898
},
99+
"railway": {
100+
"builder": "dockerfile",
101+
"healthcheckPath": "/health",
102+
"healthcheckTimeoutSeconds": 300,
103+
"restartPolicy": "on-failure",
104+
"restartPolicyMaxRetries": 10,
105+
"managedPostgres": true,
106+
"autoDeployFromGitHub": true
107+
},
99108
"cicd": {
100109
"provider": "github-actions",
101110
"runTests": true,

.claude/skills/deployment-config-generator/SKILL.md

Lines changed: 73 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ description: >
55
build-spec.json. For Cloudflare Workers, generates wrangler.toml with bindings.
66
For Node.js, generates Dockerfile and docker-compose.yml with PostgreSQL. For
77
AWS Lambda, generates a SAM template (API Gateway HTTP API), esbuild bundling
8-
config, and an OIDC deploy workflow. Always generates GitHub Actions CI/CD
9-
workflow and .env.example. Keywords: deploy, deployment, wrangler, cloudflare,
10-
workers, docker, dockerfile, docker-compose, aws, lambda, sam, api-gateway,
11-
serverless, esbuild, oidc, cold-start, github-actions, ci-cd, pipeline, env,
12-
configuration, infrastructure
8+
config, and an OIDC deploy workflow. For Railway, generates railway.toml
9+
(Dockerfile build, health check, start command) and nixpacks.toml. Always
10+
generates GitHub Actions CI/CD workflow and .env.example. Keywords: deploy,
11+
deployment, wrangler, cloudflare, workers, docker, dockerfile, docker-compose,
12+
aws, lambda, sam, api-gateway, serverless, esbuild, oidc, cold-start, railway,
13+
nixpacks, paas, github-actions, ci-cd, pipeline, env, configuration,
14+
infrastructure
1315
---
1416

1517
# Deployment Config Generator (Phase 5)
@@ -45,7 +47,7 @@ const spec = JSON.parse(
4547
await readFile('.claude/plans/build-spec.json', 'utf-8'),
4648
);
4749

48-
const target = spec.deployment.target; // 'cloudflare-workers' | 'node' | 'aws-lambda'
50+
const target = spec.deployment.target; // 'cloudflare-workers' | 'node' | 'aws-lambda' | 'railway'
4951
const authStrategy = spec.auth.strategy;
5052
```
5153

@@ -347,6 +349,67 @@ permissions:
347349
--parameter-overrides "DatabaseUrl=${{ secrets.DATABASE_URL }} JwtSecret=${{ secrets.JWT_SECRET }}"
348350
```
349351

352+
### Step 2d -- Railway Configuration
353+
354+
If target is `railway`, reuse the Node.js Dockerfile from Step 2b and generate
355+
Railway config-as-code. Canonical templates live in `templates/railway/`
356+
(`railway.toml`, `nixpacks.toml`). Railway builds the service from the
357+
Dockerfile, so the deployed image is identical to the local
358+
`docker compose up` image.
359+
360+
```toml
361+
# api/railway.toml
362+
[build]
363+
builder = "DOCKERFILE"
364+
dockerfilePath = "Dockerfile"
365+
watchPatterns = ["src/**", "package.json", "pnpm-lock.yaml", "Dockerfile"]
366+
367+
[deploy]
368+
startCommand = "node dist/index.js"
369+
healthcheckPath = "/health"
370+
healthcheckTimeout = 300
371+
restartPolicyType = "ON_FAILURE"
372+
restartPolicyMaxRetries = 10
373+
numReplicas = 1
374+
```
375+
376+
No deploy workflow is generated: Railway auto-deploys the connected GitHub
377+
repo on every push, gated by the `/health` check. (CLI deploys from CI are
378+
possible with `railway up` and a `RAILWAY_TOKEN` secret, but not required.)
379+
380+
Environment variables live on the Railway service (Variables tab), not in
381+
config files. Generate this reference table into the project README:
382+
383+
| Variable | Value |
384+
|---|---|
385+
| `DATABASE_URL` | `${{Postgres.DATABASE_URL}}` (reference to managed PostgreSQL) |
386+
| `JWT_SECRET` | generated secret, 32+ chars |
387+
| `NODE_ENV` | `production` |
388+
| `LOG_LEVEL` | `info` |
389+
390+
`PORT` is injected by Railway; the Node.js entry point already binds it.
391+
Remind the user of the one dashboard setting config-as-code cannot express:
392+
service **Root Directory** must be `api` so Railway finds `railway.toml` and
393+
the Dockerfile.
394+
395+
Nixpacks alternative (`builder = "NIXPACKS"`) for building without the
396+
Dockerfile -- `nixpacks.toml` pins the toolchain:
397+
398+
```toml
399+
# api/nixpacks.toml
400+
[phases.setup]
401+
nixPkgs = ["nodejs_22", "pnpm"]
402+
403+
[phases.install]
404+
cmds = ["pnpm install --frozen-lockfile"]
405+
406+
[phases.build]
407+
cmds = ["pnpm build"]
408+
409+
[start]
410+
cmd = "node dist/index.js"
411+
```
412+
350413
### Step 3 -- Generate GitHub Actions CI/CD
351414

352415
```yaml
@@ -449,6 +512,8 @@ jobs:
449512
# role-to-assume: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
450513
# aws-region: ${{ vars.AWS_REGION }}
451514
# - run: cd api && pnpm run build:lambda && sam deploy --no-confirm-changeset
515+
# For Railway: no deploy step -- Railway auto-deploys the connected
516+
# GitHub repo on push, gated by the /health check (see Step 2d).
452517

453518
deploy-production:
454519
runs-on: ubuntu-latest
@@ -525,6 +590,8 @@ Ensure the API package.json has all necessary scripts:
525590
| SAM template | `api/template.yaml` | AWS Lambda + API Gateway HTTP API stack |
526591
| SAM config | `api/samconfig.toml` | Stack name, region, deploy defaults |
527592
| esbuild config | `api/esbuild.config.mjs` | Single-file Lambda bundle build |
593+
| Railway config | `api/railway.toml` | Build, health check, start command, restart policy |
594+
| Nixpacks config | `api/nixpacks.toml` | Toolchain pins for the non-Docker Railway build |
528595
| CI/CD workflow | `.github/workflows/ci.yml` | GitHub Actions pipeline |
529596
| Deploy workflow | `.github/workflows/deploy.yml` | OIDC-based AWS Lambda deploy (Lambda target) |
530597
| Env template | `.env.example` | Environment variable template |

.claude/skills/schema-intake/SKILL.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ continuing. Adapt follow-up questions based on responses.
8484
8585
**Question 6 -- Deployment Target**
8686
> Where will this API be deployed?
87-
> Options: Cloudflare Workers (default), Node.js / Docker, AWS Lambda
87+
> Options: Cloudflare Workers (default), Node.js / Docker, AWS Lambda, Railway
8888
8989
**Question 7 -- Additional Requirements** (optional)
9090
> Any special requirements? (pagination style, rate limiting, soft deletes, etc.)
@@ -294,7 +294,7 @@ interface BuildSpec {
294294
sourceType: 'file' | 'interview';
295295
};
296296
deployment: {
297-
target: 'cloudflare-workers' | 'node' | 'aws-lambda';
297+
target: 'cloudflare-workers' | 'node' | 'aws-lambda' | 'railway';
298298
runtime: string;
299299
};
300300
auth: {
@@ -553,7 +553,7 @@ function validateBuildSpec(spec: BuildSpec): string[] {
553553
| `tdd-from-schema` (Phase 2) | Reads `endpoints` and `auth` to generate test cases |
554554
| `route-generation` (Phase 3) | Reads `endpoints` to scaffold Hono route handlers |
555555
| `api-authentication` | Reads `auth` to configure JWT/API key middleware |
556-
| `deployment-config-generator` | Reads `deployment` to generate wrangler.toml, Dockerfile, or SAM template |
556+
| `deployment-config-generator` | Reads `deployment` to generate wrangler.toml, Dockerfile, SAM template, or railway.toml |
557557
| `api-documentation` | Reads the generated OpenAPI spec or regenerates from build-spec |
558558

559559
### Triggering the Next Phase

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ jobs:
166166
fi
167167
done
168168
169-
for dir in templates/shared templates/cloudflare-workers templates/node-server templates/docker templates/aws-lambda; do
169+
for dir in templates/shared templates/cloudflare-workers templates/node-server templates/docker templates/aws-lambda templates/railway; do
170170
if [ -d "$dir" ]; then
171171
echo " $dir: OK"
172172
else

CLAUDE.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
44

55
## Project Overview
66

7-
This is a **Claude Code-integrated API & backend development framework** providing specialized agents, skills, scripts, and schema-to-API conversion pipelines. Built with TypeScript, Hono (HTTP framework), Drizzle ORM, and PostgreSQL. Deployed to Cloudflare Workers, Node.js, or AWS Lambda.
7+
This is a **Claude Code-integrated API & backend development framework** providing specialized agents, skills, scripts, and schema-to-API conversion pipelines. Built with TypeScript, Hono (HTTP framework), Drizzle ORM, and PostgreSQL. Deployed to Cloudflare Workers, Node.js, AWS Lambda, or Railway.
88

99
Nerva is the backend counterpart to **Aurelius** (frontend framework).
1010

1111
The framework is designed for:
1212
- Schema-first API development (OpenAPI spec to working API)
1313
- OpenAPI-to-working-API conversion with TDD-mandatory development
1414
- Comprehensive testing (integration tests, contract tests, load tests with k6)
15-
- Deployment to Cloudflare Workers, Node.js (Docker), or AWS Lambda (SAM)
15+
- Deployment to Cloudflare Workers, Node.js (Docker), AWS Lambda (SAM), or Railway
1616
- Full product lifecycle support (engineering, database, testing, DevOps, operations)
1717

1818
## Project Structure
@@ -39,6 +39,7 @@ project-root/
3939
│ ├── cloudflare-workers/ # Wrangler config
4040
│ ├── node-server/ # Node.js server config
4141
│ ├── aws-lambda/ # SAM template, esbuild config, OIDC deploy workflow
42+
│ ├── railway/ # Railway config-as-code (railway.toml, nixpacks.toml)
4243
│ └── docker/ # Dockerfile, docker-compose
4344
├── docs/
4445
│ ├── schema-to-api/ # Pipeline guide
@@ -58,7 +59,7 @@ project-root/
5859

5960
```bash
6061
# Setup a new API project
61-
./scripts/setup-project.sh my-api --cloudflare # or --node / --lambda
62+
./scripts/setup-project.sh my-api --cloudflare # or --node / --lambda / --railway
6263

6364
# Run tests with coverage
6465
./scripts/run-tests.sh
@@ -233,7 +234,7 @@ Autonomous 10-phase pipeline that converts an OpenAPI specification into a worki
233234
- **Schema-first** — OpenAPI spec drives database schema, types, handlers, and tests
234235
- **Contract testing** — generated tests validate API responses against OpenAPI spec
235236
- **Load testing** — k6 scripts generated for performance-critical endpoints
236-
- **Multi-target deployment** — Cloudflare Workers, Node.js, Docker, AWS Lambda with single config change
237+
- **Multi-target deployment** — Cloudflare Workers, Node.js, Docker, AWS Lambda, Railway with single config change
237238
- **Type safety end-to-end** — Drizzle schema to Zod validators to TypeScript types
238239
- Quality gate: 80%+ coverage, TypeScript strict, security audit, bundle analysis
239240
- Resumable: TodoWrite tracks progress across interrupted sessions
@@ -489,6 +490,7 @@ pnpm drizzle-kit studio # Open database GUI
489490
./scripts/setup-project.sh my-api --cloudflare # New Cloudflare Workers project
490491
./scripts/setup-project.sh my-api --node # New Node.js project
491492
./scripts/setup-project.sh my-api --lambda # New AWS Lambda (SAM) project
493+
./scripts/setup-project.sh my-api --railway # New Railway project
492494
```
493495

494496
---

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ A Claude Code-integrated API & backend development framework with TypeScript, Ho
1717
- **12 Development Skills** — Automated workflows for schema parsing, TDD, route generation, authentication, validation, documentation
1818
- **10-Phase Schema-to-API Pipeline** — Convert OpenAPI specs into fully working, tested API servers with a single command
1919
- **TDD-Mandatory Development** — Integration tests written before route handlers, hard gate enforced
20-
- **Three Deployment Targets** — Cloudflare Workers (edge), Node.js (Docker), or AWS Lambda (SAM) with one config change
20+
- **Four Deployment Targets** — Cloudflare Workers (edge), Node.js (Docker), AWS Lambda (SAM), or Railway (PaaS) with one config change
2121
- **Testing Stack** — Vitest, supertest, contract tests against OpenAPI, k6 load tests
2222
- **Schema-First Design** — Database schemas, types, and validators all derived from your API spec
2323

@@ -37,7 +37,7 @@ cd Nerva
3737
pnpm install
3838

3939
# Initialize a new API project
40-
./scripts/setup-project.sh my-api --cloudflare # or --node / --lambda
40+
./scripts/setup-project.sh my-api --cloudflare # or --node / --lambda / --railway
4141

4242
# Start development
4343
cd api && pnpm dev
@@ -176,6 +176,7 @@ Full catalog: [`.claude/CUSTOM-AGENTS-GUIDE.md`](.claude/CUSTOM-AGENTS-GUIDE.md)
176176
| `templates/cloudflare-workers/` | Wrangler config with Hyperdrive |
177177
| `templates/node-server/` | Dockerfile + docker-compose with PostgreSQL |
178178
| `templates/aws-lambda/` | SAM template, esbuild config, OIDC deploy workflow |
179+
| `templates/railway/` | Railway config-as-code + Nixpacks build config |
179180
| `templates/docker/` | Extended Docker with Redis + pgAdmin |
180181

181182
## Part of the PMDS Framework Series

docs/onboarding/architecture.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ Shell scripts for common development tasks:
6161

6262
| Script | Purpose |
6363
|--------|---------|
64-
| `setup-project.sh` | Initialize a new API project (--cloudflare, --node, or --lambda) |
64+
| `setup-project.sh` | Initialize a new API project (--cloudflare, --node, --lambda, or --railway) |
6565
| `run-tests.sh` | Vitest test suite with coverage |
6666
| `check-types.sh` | TypeScript strict mode checking |
6767
| `security-scan.sh` | Dependency and code security audit |
@@ -71,7 +71,7 @@ Shell scripts for common development tasks:
7171
| `generate-openapi-docs.sh` | Build API documentation |
7272
| `generate-client.sh` | Generate typed API client for frontends |
7373

74-
### Templates (5 directories)
74+
### Templates (6 directories)
7575

7676
Starter configurations for different deployment targets:
7777

@@ -81,6 +81,7 @@ Starter configurations for different deployment targets:
8181
| `templates/cloudflare-workers/` | Wrangler config with D1/KV/Hyperdrive bindings |
8282
| `templates/node-server/` | Dockerfile + docker-compose with PostgreSQL |
8383
| `templates/aws-lambda/` | SAM template (API Gateway HTTP API), esbuild config, OIDC deploy workflow |
84+
| `templates/railway/` | Railway config-as-code (Docker build, health check) + Nixpacks config |
8485
| `templates/docker/` | Extended Docker setup with Redis + pgAdmin |
8586

8687
## Pipelines

docs/onboarding/quickstart.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ If you have an OpenAPI specification file:
3232

3333
```bash
3434
# Initialize the project structure
35-
./scripts/setup-project.sh my-api --cloudflare # or --node / --lambda
35+
./scripts/setup-project.sh my-api --cloudflare # or --node / --lambda / --railway
3636

3737
# Open Claude Code and run the pipeline
3838
/build-from-schema path/to/openapi-spec.yaml

0 commit comments

Comments
 (0)