CLI
Deploy, tail logs, run commands and manage apps from your terminal.
railyard is a single Go binary over the Railyard REST API:
deploy, tail logs, run commands, manage env vars, domains, databases and
servers from your terminal. No runtime required.
Install
One binary, no dependencies, for macOS and Linux on arm64 and amd64. Nothing is hardcoded — the CLI talks to whichever Railyard you sign in to.
brew install almokhtarbr/railyard/railyard # Homebrew
curl -fsSL https://app.railyard.run/install.sh | sh # one-line installer (verifies the sha256)
Or download railyard-<os>-<arch> from a cli-v* release at
github.com/almokhtarbr/railyard-app/releases,
chmod +x it and put it on your PATH.
Later, instead of brew upgrade:
railyard upgrade # replaces this binary with the newest build your Railyard serves
railyard version # prints the installed build
Sign in
railyard login https://app.railyard.run
Confirm code ABCD2345 in your browser: https://app.railyard.run/cli/auth/ABCD2345
Logged in to https://app.railyard.run
This is the device flow (same idea as gh auth login or fly auth login):
the CLI opens that URL in your browser, you type the code shown in the
terminal into the already-signed-in dashboard, and the CLI picks up a token
minted for you — no password or token ever typed into the terminal. If you
run railyard login with no URL it reuses whatever’s already configured.
railyard whoami # team, token scope, limits (alias: me)
railyard logout # forget the saved token
Config and CI
The token and API URL are saved to ~/.railyard/config.json (mode 0600).
For CI or containers, skip login and set environment variables instead —
they always win over the file:
| Variable | Overrides |
|---|---|
RAILYARD_API (or RAILYARD_API_URL) | the control plane URL |
RAILYARD_TOKEN | the bearer token |
RAILYARD_CONFIG | the config file path (default ~/.railyard/config.json) |
--json on any command prints the raw API response instead of a table.
Linking an app to a directory
cd my-app && railyard link my-app # writes ./.railyard.json: {"app": "my-app"}
railyard deploy --follow # app argument now optional in this directory
railyard unlink
Commands that take [app] fall back to the linked app, found by walking up
from the current directory to the first .railyard.json. Everywhere else,
<app> is an id or a name (an unambiguous prefix works too).
Shell completion
railyard completion zsh > "${fpath[1]}/_railyard"
railyard completion bash > /etc/bash_completion.d/railyard
railyard completion fish > ~/.config/fish/completions/railyard.fish
Apps
railyard apps
railyard app [app]
railyard open [app]
railyard create <name> <git-url> [flags]
railyard templates [--verified]
railyard launch <template> [--server id]
railyard clone [app]
railyard promote [app]
apps— id · name · last deploy status · url, one per line.app— full JSON for one app.open— prints and opens the app’s URL in your browser.createflags:--server <id|hostname>,--ref <branch>,--port <n>(detected from the repo when omitted),--addons postgres,redis,…,--db-extensions <ext,…>.templates— the one-click catalog;launchdeploys one now.clone— copies the app into a staging copy;promoteships a staging app’s release to production (like Heroku pipelines).
railyard create my-app https://github.com/me/my-app --ref main --port 3000
railyard clone my-app && railyard promote my-app-staging
Deploys
railyard deploy [app] [flags]
railyard deploys [--app <app>] [--status <s>]
railyard deploy:logs <id> [--follow]
railyard deploy:approve|reject|cancel <deploy-id>
railyard releases [app]
railyard rollback <app> <version> [--code-only] [--message "note"]
railyard deploy-window <app> off | <mon,tue,...> <09:00> <17:00> [zone]
deploy flags: --ref <branch|tag|sha> deploys that ref once without
changing the tracked branch, --message "note", --follow streams the
build and release log, --force skips first-deploy checks, --at <ISO 8601>
schedules it (cancel with deploy:cancel), --anyway deploys outside the
deploy window.
deploy --local builds the current directory with your Docker instead of
the team’s builder, pushes it, and deploys that image once — like
fly deploy --local-only:
railyard deploy [app] --local [--image repo[:tag]]
--image pushes to your own registry (your docker login) instead of the
team’s build registry; an untagged repo gets :local-<UTC timestamp>.
deploy-window — pushes and auto-deploys outside the window wait until it
opens; deploy --anyway overrides it. rollback redeploys an earlier
release’s commit and restores its env vars (--code-only keeps today’s).
railyard deploy --ref v1.4.2 --message "hotfix" --follow
railyard rollback my-app 112 --message "bad migration"
railyard deploy-window my-app mon,tue,wed,thu,fri 09:00 17:00 America/New_York
Git deploys
railyard git:remote [app] [--remote name]
railyard git:strict <app> on|off
git:remote adds a railyard git remote pointing at this app and a git
credential helper that answers with your token, so git push railyard main
deploys that exact commit and streams the build log back. git:strict
(on by default) rejects a push whose build fails, so the branch stays on its
old commit; off accepts the push first and deploys after.
cd my-app && railyard git:remote
git push railyard main
Each push is capped at 1 GB. Pushed repositories also count against a
per-team quota (5 GB by default); going over it rejects the push with the
usage and a suggestion to delete apps you no longer push to. Railyard runs
git gc on pushed repositories every night to keep them small.
Runtime
railyard logs [app] [--follow] [--process web] [--tail 200]
railyard logs:search <app> <text|/regex/> [--level error] [--range 24h] [--process web]
railyard ps [app]
railyard restart [app] [--process web]
railyard run <app> [--process worker] [--exec] -- <command...>
railyard scale <app> <process>=<n> …
railyard wake [app]
railyard sleep <app> <10|30|60|360|1440|off>
run starts a fresh one-off container from the current release (like
heroku run), or execs inside the already-running container with --exec;
it streams output and exits with the remote command’s own exit code.
sleep stops the app’s containers after that many idle minutes and
wake/the next request brings it back; off disables it.
railyard logs my-app --follow --process web
railyard run my-app -- bin/rails db:migrate
railyard scale my-app web=2 worker=1
railyard sleep my-app 30
Config vars and domains
railyard env [app] [--reveal[=KEY]]
railyard env:set <app> KEY=VALUE …
railyard env:unset <app> KEY
railyard configs
railyard domains [app]
railyard domain:add <app> <hostname> [--redirect]
railyard domain:rm <app> <domain-id>
env masks values unless --reveal (all) or --reveal KEY (one).
configs lists team-wide config entries (read-only from the CLI).
railyard env my-app --reveal SECRET_KEY_BASE
railyard env:set my-app RAILS_ENV=production LOG_LEVEL=info
railyard domain:add my-app www.example.com --redirect
Database and volumes
railyard db:query <app> "<sql>" [--write]
railyard db:backups [app]
railyard db:backup [app]
railyard db:restore <backup-id>
railyard db:url <backup-id>
railyard volumes [app]
railyard volume:backup <app> <volume-name>
railyard volume:restore <backup-id>
db:query is read-only unless --write (needs a write-scoped token).
db:url returns a signed download link for a backup.
railyard db:query my-app "select count(*) from users"
railyard db:backup my-app
railyard volume:backup my-app data
Manifest
railyard manifest:pull [app] [--secrets] [--out railyard.yml]
railyard manifest:apply [app] <file.yml>
manifest:pull prints the app as a railyard.yml (--secrets includes
variable values); manifest:apply applies one to the app.
railyard manifest:pull my-app --out railyard.yml
railyard manifest:apply my-app railyard.yml
Observability
railyard metrics [app] [--range 1h|24h|7d|30d]
railyard autoscale <app> --max N [--min N] [--p95 ms] [--cpu %]
railyard autoscale <app> off
metrics prints requests, p95, error rate and slowest endpoints.
autoscale scales web replicas between --min/--max once p95 latency or
CPU crosses the given thresholds; off removes the bounds.
railyard metrics my-app --range 7d
railyard autoscale my-app --max 5 --min 1 --p95 300 --cpu 80
Notifications and webhooks
railyard notify
railyard webhooks
Team-wide listings of notification rules and webhook endpoints (read-only from the CLI; create and edit them from the dashboard).
Servers
railyard servers
railyard server <id>
railyard server:cordon <server-id>
railyard server:uncordon <server-id>
railyard server:reboot <server-id>
railyard server:power-cycle <server-id>
railyard server:prune <server-id>
railyard server:resize <server-id> <size>
cordon stops new apps from being placed on a server without moving what’s
already there; prune clears unused Docker images and volumes.
railyard server:cordon srv-7
railyard server:resize srv-7 s-4vcpu-8gb
Networking
railyard tunnel [app] [web|db|postgres|redis|<process>] [-p local-port]
Alias: proxy. Forwards a local port to a container or database on the
app’s server — like fly proxy / railway connect. Listens on localhost
(the remote port by default); a database tunnel prints a ready
postgres://…@localhost:<port>/… URL. Nothing is opened to the internet:
bytes travel CLI → control plane (your token) → agent → container.
railyard tunnel my-app db -p 5433
Search and imports
railyard search:reindex [app]
railyard import
search:reindex runs the app’s reindex command in a fresh one-off
container. import opens the Heroku/Render/Fly importer in your browser.
Exit codes
0 ok · 2 the API returned an error (message on stderr) · 3 not signed
in or bad usage · 64 bad command usage. railyard run instead exits with
the remote command’s own exit code.
See also
docs/API.md— the REST API the CLI talks to.