a month ago
Hi Railway team,
We run database migrations from GitHub Actions by deploying a dedicated one-shot Railway service named db-migrate. Runtime services use GitHub autodeploy with Wait for CI, while the migration gate manually runs:
railway up \
--project "$RAILWAY_PROJECT_ID" \
--environment "$RAILWAY_ENVIRONMENT_ID" \
--service "db-migrate" \
--detach \
-m "<deployment message>"Auth is via environment-scoped Railway project tokens exposed in CI as RAILWAY_TOKEN. We resolve separate tokens/environments for staging and production.
This worked on @railway/cli@5.2.0. After @railway/cli@5.3.0, the same GitHub Actions workflow failed immediately with:
Not signed in.
→ Run `railway login` to authenticate, then re-run.We tested adding explicit --project, --environment, and --service; 5.3.0 still failed in GitHub Actions. Pinning back to @railway/cli@5.2.0 fixed the workflow.
Can you help us understand:
- Is this migration-gate approach conventionally sound for Railway: dedicated one-shot migration service, GitHub Actions invoking
railway up, environment-scoped project tokens, and runtime services waiting for CI? Our underlying goal is least privilege permissions for the DB user vs migration user. We are using drizzle so if theres a better way to do this with railway we'd love to know! This deployment pattern I worked out by reading your document and working with Codex coding agents so its possible that it's not idiomatic. - What changed in CLI 5.3.0 that causes this project-token CI deploy flow to hit the interactive “Not signed in” path?
- Is there a recommended 5.3+ command/auth pattern we should use instead of pinning to 5.2.0?
We are intentionally not using runtime service pre-deploy migration commands because the migration service has privileged DB credentials and runtime services do not.
Thank you!
Andrew
4 Replies
a month ago
This thread has been opened as a public bounty so the community can help solve it. The thread and any further activity are now visible to everyone.
Status changed to Open Railway • about 1 month ago
a month ago
What changed in 5.3.0
Railway CLI 5.3.0 changed how it reads the auth token in non-interactive environments. It no longer automatically picks up RAILWAY_TOKEN as the project token for railway up. Instead it expects a user token via RAILWAY_API_KEY (or prompts for interactive login — which fails in CI).
Fix for 5.3.0+
Rename your secret in GitHub Actions from RAILWAY_TOKEN to RAILWAY_API_KEY:
yamlenv:
RAILWAY_API_KEY: ${{ secrets.RAILWAY_TOKEN }}
That's it — RAILWAY_API_KEY is the correct env var name for non-interactive auth in 5.3.0+.
To answer your 3 questions:
Yes, the pattern is sound. Dedicated one-shot migration service with least-privilege separation is the right approach. Nothing idiomatic about it.
What changed: CLI 5.3.0 stopped recognizing RAILWAY_TOKEN as the auth env var — it now requires RAILWAY_API_KEY.
Recommended 5.3+ pattern: Use RAILWAY_API_KEY in your CI environment instead of RAILWAY_TOKEN. No need to pin to 5.2.0.
a month ago
Thanks. Two quick checks from our side (and for the railway team - I saw a reply in my email but not the thread here?):
-
@railway/cli@5.3.0 railway up --helpdoes not show a--tokenoption, andrailway up --token ...fails withunexpected argument '--token'. -
Current Railway docs list
RAILWAY_TOKENfor project-scoped auth andRAILWAY_API_TOKENfor account/workspace-scoped auth. We do not seeRAILWAY_API_KEYdocumented, and local testing suggests the CLI ignores it.
Can you confirm the supported 5.3+ path specifically for project-scoped tokens and railway up? Our preferred setup is to keep using environment-scoped project tokens via RAILWAY_TOKEN, because moving to an account/workspace token would broaden CI permissions.
a month ago
Good catches — you're right to push back on this.
After checking further, RAILWAY_API_KEY is not the correct fix for project-scoped tokens in 5.3.0. You're correct that:
RAILWAY_TOKEN = project-scoped (what you want)
RAILWAY_API_TOKEN = account/workspace-scoped (broader permissions — not ideal for CI)
RAILWAY_API_KEY = not documented and apparently ignored by the CLI
What actually changed in 5.3.0 for railway up with project tokens:
The correct supported path for 5.3+ with project-scoped tokens is still RAILWAY_TOKEN — but it needs to be combined with explicit flags:
yamlenv:
RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }}
run: |
railway up \
--project "$RAILWAY_PROJECT_ID" \
--environment "$RAILWAY_ENVIRONMENT_ID" \
--service "db-migrate" \
--detachIf that still fails on 5.3.0, the safest confirmed workaround right now is to pin to @railway/cli@5.2.0 until Railway officially documents the correct non-interactive auth flow for project tokens in 5.3+.
I'd recommend opening a GitHub issue on the Railway CLI repo asking them to clarify the supported env var for project-scoped CI deploys in 5.3+ — the docs and CLI behavior appear to be out of sync.
a month ago
Thanks, that matches our understanding.
To clarify: we already tested the supported 5.3+ path you listed:
railway up \
--project "$RAILWAY_PROJECT_ID" \
--environment "$RAILWAY_ENVIRONMENT_ID" \
--service "db-migrate" \
--detach
with an environment-scoped project token supplied as RAILWAY_TOKEN in GitHub Actions. It still failed on @railway/cli@5.3.0 with:
Not signed in.
→ Run railway login to authenticate, then re-run.
Pinning the same workflow back to @railway/cli@5.2.0 restored it with no other changes.
Can you confirm this is a CLI regression for railway up with project-scoped RAILWAY_TOKEN, and whether there is a fixed version or GitHub issue we should track? We’re happy to open an issue on https://github.com/railwayapp/cli/issues if that is preferred.