Railway CLI
Find a file
Jake Runzer c65c909420
Add dev command for local development with Docker Compose (#710)
* init develop command

* develop: use service names, random ports, project-specific dir

- extract environment config types to controllers/environment_config.rs
- use slugified service names instead of IDs in compose
- generate deterministic external ports (10000-60000) to avoid conflicts
- save compose to ~/.railway/develop/<project_id>/
- always run detached

* develop: show service names and URLs in output

* develop: resolve variables and override Railway networking vars

- Fetch resolved variables via VariablesForServiceDeployment API
- Override RAILWAY_PRIVATE_DOMAIN with docker-compose service slug
- Override RAILWAY_PUBLIC_DOMAIN and RAILWAY_TCP_PROXY_DOMAIN with localhost
- Override RAILWAY_TCP_PROXY_PORT with mapped local port
- Replace *.railway.internal refs in values with service slugs
- Filter deprecated vars (RAILWAY_STATIC_URL, RAILWAY_SERVICE_*_URL)
- Add docker-compose networking for inter-container communication
- Escape $ as $$ in commands for docker-compose interpolation

* develop: add volume support and down subcommand

- Add volumes field to docker-compose output (persist through up/down)
- Add `develop down` subcommand to stop containers
- Use environment ID for compose dir and volume names
- Show volume mount paths in service summary

* run: use local services when develop is active

Add --no-local flag to skip. Extracts shared variable override logic
into controllers/local_override.rs for reuse between run and develop.

* develop down: add --clean flag to remove volumes and files

* restart services on failure

* develop: add local HTTPS with mkcert and pretty URLs

- auto-generate TLS certs via mkcert for {project}.railway.dev
- add Caddy reverse proxy for HTTPS termination
- set RAILWAY_PUBLIC_DOMAIN to https://{domain}:{port}
- auto-add /etc/hosts entry on develop up
- remove hosts entry on develop down --clean
- skip cert generation if already exists

* develop: use .localhost TLD instead of .railway.dev

.localhost resolves to 127.0.0.1 per RFC 6761, eliminating need for
/etc/hosts manipulation and sudo prompts

* process manager

* develop: support port 443 for prettier public URLs

- Try binding to port 443 at startup for cleaner URLs
- Port 443 mode: https://{service}.{project}.railway.localhost
- Fallback mode: https://{project}.railway.localhost:{port}
- Generate wildcard certs (*.project.railway.localhost) for port 443
- SNI-based routing in Caddy when using port 443
- Add http:// prefix to private domain display

* develop: add session lock to prevent concurrent code service runs

- Add DevelopSessionLock using fs2 file locking to prevent multiple
  develop sessions running code services for the same environment
- Check existing https_mode before falling back from port 443
- Lock auto-releases on drop or process crash

* develop: refactor into testable module structure

- Extract shared types to controllers/config/ (EnvironmentConfig)
- Create controllers/develop/ with submodules:
  - ports.rs: slugify, generate_port + tests
  - variables.rs: override_railway_vars + tests
  - session.rs: DevelopSessionLock + tests
  - traits.rs: EnvironmentDataProvider, CommandRunner + mocks
  - compose.rs: DockerCompose types, build_port_infos
  - https_proxy.rs: HttpsConfig, certs, Caddyfile gen
  - code_runner.rs: ProcessManager
  - local_config.rs: LocalDevConfig
- Add async-trait dependency for trait abstractions
- Old controller files re-export for backward compat

* develop: remove unused traits and cleanup backward compat stubs

- Delete unused EnvironmentDataProvider and CommandRunner traits (371 lines)
- Add fetch_environment_config() function to controllers/config
- Update develop.rs to use centralized fetch function
- Delete empty stub files: process_manager.rs, develop_lock.rs,
  local_https.rs, local_dev_config.rs
- Update local_override.rs to import directly from develop module

* develop: remove unused get_env_vars, cleanup dead_code attributes

- Remove unused get_env_vars method from ServiceInstance
- Remove unnecessary #![allow(dead_code)] from compose.rs and output.rs
- Add explanatory comment for dead_code allow in environment.rs
  (needed for API deserialization struct fields)

* dev: rename develop to dev, add clean subcommand

- rename command from `develop` to `dev` (with `develop` alias)
- extract `--clean` flag from `down` into separate `clean` subcommand
- update output: remove "Using port 443" msg, add checkmark to "Started X image services"

* dev: store data in ~/.railway/develop/{projectId} instead of environmentId

* remove unnecessary comments

* dev: add unit tests for compose, https_proxy, local_config

Tests for port building, caddyfile generation, cert existence, and config operations.

* dev: fix cross-platform compatibility for Linux/Windows

- Add extra_hosts to Caddy service for host.docker.internal on Linux
- Use shell execution (sh -c / cmd /C) for proper command parsing
- Replace path unwraps with to_string_lossy()

* dev: check docker compose availability before running

* fix: handle Windows error kind for file lock conflicts

* dev configure: add service menu and --remove <name> support

* dev: clarify comments in up_command

* fix: use fs2 lock_contended_error for cross-platform lock check

* fix: use privateNetworkEndpoint for private domain resolution

Previously used slugified service name which may not match the actual
private network endpoint configured in the environment.

* refactor: extract build_service_endpoints helper for privateNetworkEndpoint

DRYs up duplicate logic between dev.rs and local_override.rs.
Fixes run command using environment_id instead of project_id for
is_local_develop_active check.

* dev: improve empty state messages

Distinguish "no services at all" from "no code services" so users
get actionable guidance (railway add vs railway develop configure)

* fix: only show networking for code services when port configured

* fix: skip canonicalize on windows to avoid UNC path prefix

canonicalize() returns \\?\C:\... paths on Windows which cmd.exe rejects

* dev: improve empty state messages with color

* dev: show command as first log line for code services

* dev: add port selection to configure and detect port conflicts

- prompt for port during service configuration (default: inferred from Railway)
- skip port prompt if service has no networking config
- detect and warn about port conflicts during configure
- force reconfigure conflicting ports during `railway dev up`
- only set PORT env var for services with networking configured

* dev: allow configuring multiple services on first-time setup

Use multi-select prompt instead of single-select, with summary at end

* dev: show OS-specific Docker install URL

* dev: format Docker not found message

* remove test dir

* remove test and to gitignore

* dev: fix cross-service public domain replacement

When service A references service B's RAILWAY_PUBLIC_DOMAIN via variable
interpolation, the production domain wasn't being replaced with the local
equivalent. Now builds a mapping of production -> local public domains
and replaces them in all variable values.

* dev: show next steps when only image services running

* dev: extract constants and refactor up_command

- Add port range constants (PORT_RANGE_MIN, PORT_RANGE_SIZE, RANDOM_PORT_MIN, RANDOM_PORT_MAX)
- Add resolve_path() for cross-platform path canonicalization
- Move generate_random_port() to ports.rs
- Extract helper functions from up_command:
  - print_image_service_summary()
  - print_code_service_summary()
  - build_public_domain_mapping()
  - build_image_service_compose()
  - setup_caddy_proxy()
2025-12-12 18:18:58 -05:00
.cargo Add attribute logging (#455) 2024-05-05 11:32:47 +01:00
.github Add --lines / -n and -f / --filter options to log command (#667) 2025-09-24 16:05:09 -05:00
bin release tarfiles for windows (#325) 2023-03-05 17:28:27 +00:00
npm-install fix npm install on windows (#341) 2023-03-08 14:00:56 -05:00
src Add dev command for local development with Docker Compose (#710) 2025-12-12 18:18:58 -05:00
.dockerignore feat: alpine dockerfile (#470) 2023-12-05 16:52:45 -05:00
.gitignore Add dev command for local development with Docker Compose (#710) 2025-12-12 18:18:58 -05:00
build.rs Template deploy v2 (#563) 2024-10-21 18:55:37 -04:00
Cargo.lock Add dev command for local development with Docker Compose (#710) 2025-12-12 18:18:58 -05:00
Cargo.toml Add dev command for local development with Docker Compose (#710) 2025-12-12 18:18:58 -05:00
CLAUDE.md Add CLAUDE.md with development guidance (#661) 2025-09-09 20:20:10 -04:00
CONTRIBUTING.md Point to railway.com (#585) 2025-01-08 14:33:37 -05:00
Dockerfile fix exec permission not set in railway-cli docker image (#531) 2024-08-14 13:46:58 -04:00
flake.lock Migrate to CLI v3 (#304) 2023-03-03 21:44:32 -05:00
flake.nix Fix CLI compilation (#514) 2024-06-24 16:41:23 -03:00
install.sh get latest version from GitHub release (#586) 2025-01-08 14:49:21 -05:00
LICENSE Migrate to CLI v3 (#304) 2023-03-03 21:44:32 -05:00
package.json chore: Release railwayapp version 4.12.0 2025-11-28 17:57:13 -03:00
pnpm-lock.yaml fix npm install 2023-03-04 09:25:40 -05:00
README.md Add --workspace option to railway init (#656) 2025-08-12 20:11:21 -04:00
release.toml fix release.toml (again) 2023-04-13 11:28:17 -04:00
shell.nix Fix osx compilation (#666) 2025-09-24 10:30:03 -05:00
v2.sh add v2 install script 2023-03-04 17:16:15 -05:00

Railway CLI

Crates.io CI cargo audit

This is the command line interface for Railway. Use it to connect your code to Railway's infrastructure without needing to worry about environment variables or configuration.

View the docs

The Railway command line interface (CLI) connects your code to your Railway project from the command line.

The Railway CLI allows you to

  • Create new Railway projects from the terminal
  • Link to an existing Railway project
  • Pull down environment variables for your project locally to run
  • Create services and databases right from the comfort of your fingertips

Installation

Cargo

cargo install railwayapp --locked

Homebrew

brew install railway

NPM

npm install -g @railway/cli

Bash

# Install
bash <(curl -fsSL cli.new)

# Uninstall
bash <(curl -fsSL cli.new) -r

Scoop

scoop install railway

Arch Linux AUR

Install using Paru

paru -S railwayapp-cli

Install using Yay

yay -S railwayapp-cli

Docker

Before using the CLI in a non-interactive environment, ensure you have created an access token (only project-tokens are supported as of now) and set it as the RAILWAY_TOKEN environment variable. CI environments are automatically detected by the presence of CI=true variable. In these environments, only build logs will be streamed, and the CLI will exit with an appropriate code indicating success or failure.

Install from the command line

docker pull ghcr.io/railwayapp/cli:latest

Use in GitHub Actions

deploy-job:
  runs-on: ubuntu-latest
  container: ghcr.io/railwayapp/cli:latest
  env:
    SVC_ID: my-service
    RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
  steps:
    - uses: actions/checkout@v3
    - run: railway up --service=${{ env.SVC_ID }}

Use in GitLab CICD

deploy-job:
  image: ghcr.io/railwayapp/cli:latest
  variables:
    SVC_ID: my-service
  script:
    - railway up --service=$SVC_ID

Tip

GitLab can access a protected (secret) variable directly, all you need to do is to add it in CI/CD settings.

From source

See CONTRIBUTING.md for information on setting up this repo locally.

Documentation

View the full documentation

Feedback

We would love to hear your feedback or suggestions. The best way to reach us is on Discord.

We also welcome pull requests into this repo. See CONTRIBUTING.md for information on setting up this repo locally.