@tachyon-gg/railway-deploy 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +353 -0
- package/dist/index.js +39977 -0
- package/package.json +48 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Tachyon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
# railway-deploy
|
|
2
|
+
|
|
3
|
+
[](https://github.com/tachyon-gg/railway-deploy/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/tachyon-gg/railway-deploy/actions/workflows/integration.yml)
|
|
5
|
+
[](https://codecov.io/gh/tachyon-gg/railway-deploy)
|
|
6
|
+
[](https://www.typescriptlang.org/)
|
|
7
|
+
[](https://bun.sh/)
|
|
8
|
+
[](https://biomejs.dev/)
|
|
9
|
+
|
|
10
|
+
Declarative infrastructure management for [Railway](https://railway.com). Define your Railway project's services, variables, domains, volumes, and buckets in YAML, and `railway-deploy` will diff against the live state and apply changes -- like Terraform, but purpose-built for Railway.
|
|
11
|
+
|
|
12
|
+
## Quick start
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
# Install
|
|
16
|
+
npx @tachyon-gg/railway-deploy --help
|
|
17
|
+
|
|
18
|
+
# Validate a config file
|
|
19
|
+
npx @tachyon-gg/railway-deploy --validate environments/production.yaml
|
|
20
|
+
|
|
21
|
+
# Dry-run (show what would change)
|
|
22
|
+
npx @tachyon-gg/railway-deploy environments/production.yaml
|
|
23
|
+
|
|
24
|
+
# Apply changes
|
|
25
|
+
npx @tachyon-gg/railway-deploy --apply environments/production.yaml
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## CLI flags
|
|
29
|
+
|
|
30
|
+
| Flag | Description |
|
|
31
|
+
|------|-------------|
|
|
32
|
+
| `--apply` | Execute changes (default: dry-run) |
|
|
33
|
+
| `-y, --yes` | Skip confirmation for destructive ops |
|
|
34
|
+
| `--env-file <path>` | Load `.env` file for `${VAR}` resolution |
|
|
35
|
+
| `-v, --verbose` | Show detailed diffs (old -> new values) |
|
|
36
|
+
| `--no-color` | Disable ANSI color output |
|
|
37
|
+
| `--validate` | Validate config without connecting to Railway |
|
|
38
|
+
|
|
39
|
+
## Environment variables
|
|
40
|
+
|
|
41
|
+
| Variable | Description |
|
|
42
|
+
|----------|-------------|
|
|
43
|
+
| `RAILWAY_TOKEN` | Railway API token (required for all API operations) |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Config reference
|
|
48
|
+
|
|
49
|
+
Environment configs are YAML files describing the desired state of a Railway environment. Add schema support to your editor:
|
|
50
|
+
|
|
51
|
+
```yaml
|
|
52
|
+
# yaml-language-server: $schema=./schemas/environment.schema.json
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Top-level fields
|
|
56
|
+
|
|
57
|
+
```yaml
|
|
58
|
+
project: My Project # Railway project name (must match exactly)
|
|
59
|
+
environment: production # Railway environment name
|
|
60
|
+
|
|
61
|
+
shared_variables: # Variables shared across all services
|
|
62
|
+
APP_ENV: production
|
|
63
|
+
DATABASE_URL: ${{Postgres.DATABASE_URL}}
|
|
64
|
+
|
|
65
|
+
services: # Map of service name -> config
|
|
66
|
+
web: { ... }
|
|
67
|
+
worker: { ... }
|
|
68
|
+
|
|
69
|
+
buckets: # S3-compatible buckets
|
|
70
|
+
media:
|
|
71
|
+
name: media-uploads
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Service configuration
|
|
75
|
+
|
|
76
|
+
Each service can be defined inline or via a template:
|
|
77
|
+
|
|
78
|
+
```yaml
|
|
79
|
+
services:
|
|
80
|
+
# Inline service (Docker image)
|
|
81
|
+
redis:
|
|
82
|
+
source:
|
|
83
|
+
image: redis:7
|
|
84
|
+
variables:
|
|
85
|
+
ALLOW_EMPTY_PASSWORD: "yes"
|
|
86
|
+
|
|
87
|
+
# Inline service (GitHub repo)
|
|
88
|
+
api:
|
|
89
|
+
source:
|
|
90
|
+
repo: myorg/my-api
|
|
91
|
+
branch: main
|
|
92
|
+
|
|
93
|
+
# Template-based service
|
|
94
|
+
web:
|
|
95
|
+
template: ../services/web.yaml
|
|
96
|
+
params:
|
|
97
|
+
tag: v1.2.3
|
|
98
|
+
variables:
|
|
99
|
+
EXTRA_VAR: override-value
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Full service options
|
|
103
|
+
|
|
104
|
+
Every option below can be used on both inline services and service templates.
|
|
105
|
+
|
|
106
|
+
#### Source
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
source:
|
|
110
|
+
image: nginx:latest # Docker image (Docker Hub, GHCR, etc.)
|
|
111
|
+
# OR
|
|
112
|
+
repo: myorg/my-repo # GitHub repository
|
|
113
|
+
|
|
114
|
+
branch: main # Branch to deploy from (GitHub repos)
|
|
115
|
+
check_suites: true # Wait for GitHub Actions to pass before deploying
|
|
116
|
+
|
|
117
|
+
registry_credentials: # For private container registries
|
|
118
|
+
username: ${REGISTRY_USER}
|
|
119
|
+
password: ${REGISTRY_PASS}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
#### Build
|
|
123
|
+
|
|
124
|
+
```yaml
|
|
125
|
+
builder: NIXPACKS # RAILPACK (default), DOCKERFILE, NIXPACKS, HEROKU, PAKETO
|
|
126
|
+
build_command: npm run build # Custom build command
|
|
127
|
+
dockerfile_path: Dockerfile.prod # Path to Dockerfile (when builder is DOCKERFILE)
|
|
128
|
+
root_directory: /packages/api # Root directory (monorepo support)
|
|
129
|
+
watch_patterns: # File patterns that trigger deploys
|
|
130
|
+
- /packages/api/src/**
|
|
131
|
+
- /packages/shared/**
|
|
132
|
+
railway_config_file: railway.toml # Path to railway.json/toml for config-as-code
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
#### Deploy
|
|
136
|
+
|
|
137
|
+
```yaml
|
|
138
|
+
start_command: npm start # Custom start command
|
|
139
|
+
pre_deploy_command: # Run before deployment (e.g., migrations)
|
|
140
|
+
- npm run migrate
|
|
141
|
+
- npm run seed
|
|
142
|
+
cron_schedule: "*/5 * * * *" # Cron schedule (for scheduled jobs)
|
|
143
|
+
healthcheck: # HTTP healthcheck
|
|
144
|
+
path: /health
|
|
145
|
+
timeout: 300 # Timeout in seconds (default: 300)
|
|
146
|
+
restart_policy: ON_FAILURE # ALWAYS, NEVER, or ON_FAILURE
|
|
147
|
+
restart_policy_max_retries: 10 # Max retries (only with ON_FAILURE)
|
|
148
|
+
sleep_application: true # Enable serverless sleeping
|
|
149
|
+
draining_seconds: 30 # Graceful shutdown timeout (seconds between SIGTERM and SIGKILL)
|
|
150
|
+
overlap_seconds: 10 # Blue-green deploy overlap duration
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
#### Networking
|
|
154
|
+
|
|
155
|
+
```yaml
|
|
156
|
+
# Custom domains
|
|
157
|
+
domains:
|
|
158
|
+
- app.example.com # Simple domain
|
|
159
|
+
- domain: api.example.com # Domain with target port
|
|
160
|
+
target_port: 8080
|
|
161
|
+
domain: simple.example.com # Shorthand for a single domain
|
|
162
|
+
|
|
163
|
+
# Railway-provided domain
|
|
164
|
+
railway_domain: true # Generate a .up.railway.app domain
|
|
165
|
+
railway_domain: # ...with a specific target port
|
|
166
|
+
target_port: 3000
|
|
167
|
+
|
|
168
|
+
# TCP proxies (for non-HTTP services like databases)
|
|
169
|
+
tcp_proxy: 5432 # Single port
|
|
170
|
+
tcp_proxies: [5432, 6379] # Multiple ports
|
|
171
|
+
|
|
172
|
+
# Outbound networking
|
|
173
|
+
ipv6_egress: true # Enable IPv6 outbound traffic
|
|
174
|
+
static_outbound_ips: true # Assign permanent outbound IP addresses
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
#### Scaling
|
|
178
|
+
|
|
179
|
+
```yaml
|
|
180
|
+
region: # Deployment region
|
|
181
|
+
region: us-east-1
|
|
182
|
+
num_replicas: 3 # Horizontal replicas (default: 1)
|
|
183
|
+
|
|
184
|
+
limits: # Resource limits per replica
|
|
185
|
+
memory_gb: 8
|
|
186
|
+
vcpus: 4
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
#### Storage
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
volume: # Persistent volume
|
|
193
|
+
mount: /data # Mount path (must be absolute)
|
|
194
|
+
name: my-data
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### Variables
|
|
198
|
+
|
|
199
|
+
```yaml
|
|
200
|
+
variables:
|
|
201
|
+
PORT: "3000"
|
|
202
|
+
DATABASE_URL: ${{Postgres.DATABASE_URL}} # Railway runtime reference
|
|
203
|
+
API_KEY: ${LOCAL_API_KEY} # Resolved from local env at config time
|
|
204
|
+
OLD_VAR: null # Marks for deletion
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Variable syntax
|
|
208
|
+
|
|
209
|
+
| Syntax | Resolved | Description |
|
|
210
|
+
|--------|----------|-------------|
|
|
211
|
+
| `${ENV_VAR}` | At config load time | Reads from local environment (or `--env-file`) |
|
|
212
|
+
| `${{service.VAR}}` | At Railway runtime | Railway reference variable (cross-service) |
|
|
213
|
+
| `%{param}` | At config load time | Template parameter substitution |
|
|
214
|
+
| `null` | N/A | Marks a variable for deletion |
|
|
215
|
+
|
|
216
|
+
### Service templates
|
|
217
|
+
|
|
218
|
+
Templates extract reusable service definitions with parameterized values:
|
|
219
|
+
|
|
220
|
+
```yaml
|
|
221
|
+
# services/web.yaml
|
|
222
|
+
params:
|
|
223
|
+
tag:
|
|
224
|
+
required: true
|
|
225
|
+
replicas:
|
|
226
|
+
default: "1"
|
|
227
|
+
|
|
228
|
+
source:
|
|
229
|
+
image: ghcr.io/org/app:%{tag}
|
|
230
|
+
|
|
231
|
+
variables:
|
|
232
|
+
APP_VERSION: "%{tag}"
|
|
233
|
+
DATABASE_URL: ${{Postgres.DATABASE_URL}}
|
|
234
|
+
|
|
235
|
+
domain: "%{tag}.example.com"
|
|
236
|
+
|
|
237
|
+
healthcheck:
|
|
238
|
+
path: /health
|
|
239
|
+
timeout: 300
|
|
240
|
+
|
|
241
|
+
region:
|
|
242
|
+
region: us-east-1
|
|
243
|
+
num_replicas: 1
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Referenced from an environment config:
|
|
247
|
+
|
|
248
|
+
```yaml
|
|
249
|
+
services:
|
|
250
|
+
web:
|
|
251
|
+
template: ../services/web.yaml
|
|
252
|
+
params:
|
|
253
|
+
tag: v2.0.0
|
|
254
|
+
replicas: "3"
|
|
255
|
+
variables:
|
|
256
|
+
EXTRA: added-by-env # Merged with template variables
|
|
257
|
+
APP_VERSION: null # Deletes the template-defined variable
|
|
258
|
+
domains:
|
|
259
|
+
- production.example.com # Overrides template domain
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Template override precedence: environment config values override template values for `source`, `domains`, and `variables`.
|
|
263
|
+
|
|
264
|
+
### Complete example
|
|
265
|
+
|
|
266
|
+
```yaml
|
|
267
|
+
# yaml-language-server: $schema=./schemas/environment.schema.json
|
|
268
|
+
project: My SaaS App
|
|
269
|
+
environment: production
|
|
270
|
+
|
|
271
|
+
shared_variables:
|
|
272
|
+
APP_ENV: production
|
|
273
|
+
SENTRY_DSN: ${SENTRY_DSN}
|
|
274
|
+
|
|
275
|
+
services:
|
|
276
|
+
web:
|
|
277
|
+
source:
|
|
278
|
+
repo: myorg/web-app
|
|
279
|
+
branch: main
|
|
280
|
+
check_suites: true
|
|
281
|
+
builder: NIXPACKS
|
|
282
|
+
build_command: npm run build
|
|
283
|
+
start_command: npm start
|
|
284
|
+
root_directory: /packages/web
|
|
285
|
+
pre_deploy_command: npm run migrate
|
|
286
|
+
healthcheck:
|
|
287
|
+
path: /health
|
|
288
|
+
timeout: 60
|
|
289
|
+
restart_policy: ON_FAILURE
|
|
290
|
+
restart_policy_max_retries: 5
|
|
291
|
+
domains:
|
|
292
|
+
- app.example.com
|
|
293
|
+
- domain: api.example.com
|
|
294
|
+
target_port: 8080
|
|
295
|
+
railway_domain: true
|
|
296
|
+
region:
|
|
297
|
+
region: us-east-1
|
|
298
|
+
num_replicas: 2
|
|
299
|
+
limits:
|
|
300
|
+
memory_gb: 4
|
|
301
|
+
vcpus: 2
|
|
302
|
+
variables:
|
|
303
|
+
PORT: "3000"
|
|
304
|
+
DATABASE_URL: ${{Postgres.DATABASE_URL}}
|
|
305
|
+
|
|
306
|
+
postgres:
|
|
307
|
+
source:
|
|
308
|
+
image: postgres:16
|
|
309
|
+
volume:
|
|
310
|
+
mount: /var/lib/postgresql/data
|
|
311
|
+
name: pg-data
|
|
312
|
+
tcp_proxy: 5432
|
|
313
|
+
variables:
|
|
314
|
+
POSTGRES_DB: myapp
|
|
315
|
+
|
|
316
|
+
redis:
|
|
317
|
+
source:
|
|
318
|
+
image: redis:7-alpine
|
|
319
|
+
volume:
|
|
320
|
+
mount: /data
|
|
321
|
+
name: redis-data
|
|
322
|
+
tcp_proxy: 6379
|
|
323
|
+
|
|
324
|
+
worker:
|
|
325
|
+
template: ../services/worker.yaml
|
|
326
|
+
params:
|
|
327
|
+
queue: default
|
|
328
|
+
sleep_application: false
|
|
329
|
+
|
|
330
|
+
buckets:
|
|
331
|
+
uploads:
|
|
332
|
+
name: user-uploads
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## JSON schemas
|
|
336
|
+
|
|
337
|
+
Editor support (autocompletion, validation) is available via JSON schemas:
|
|
338
|
+
|
|
339
|
+
- `schemas/environment.schema.json` -- environment config files
|
|
340
|
+
- `schemas/service-template.schema.json` -- service template files
|
|
341
|
+
|
|
342
|
+
## Development
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
bun install # Install dependencies
|
|
346
|
+
bun run test # Run unit tests
|
|
347
|
+
bun run test:integration # Run integration tests (requires RAILWAY_TOKEN)
|
|
348
|
+
bun run typecheck # Type check
|
|
349
|
+
bun run lint # Lint (Biome)
|
|
350
|
+
bun run lint:fix # Auto-fix lint issues
|
|
351
|
+
bun run codegen # Regenerate GraphQL types
|
|
352
|
+
bun run build # Build for distribution
|
|
353
|
+
```
|