From unicore-skills
Use when a company service is ready to connect to Railway, configure production settings, and resolve the correct production URL/domain.
How this skill is triggered — by the user, by Claude, or both
Slash command
/unicore-skills:deploying-to-railwayThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Use this skill when the repository, database, and auth wiring are ready and the service needs a production deployment.
Use this skill when the repository, database, and auth wiring are ready and the service needs a production deployment.
Resolve the company context before any Railway action. Use docs/RAILWAY_WORKSPACES.md.
Known contexts:
| Context | Railway workspace | GitHub org | Production URL/domain |
|---|---|---|---|
| Unicore | Universe Unicore | unicore-railway | unicore-railway.io |
| GuruApps | GuruApps | unicore-railway | Railway-provided *.up.railway.app domain |
If the context is not obvious from the user request, git remote, README, domain, or railway status --json, ask:
Unicore or GuruApps?
Do not continue until the workspace is known. Never create or link a Railway project in a personal or default workspace by accident.
Never use railway up. That command uploads files directly from your local machine and bypasses the GitHub-connected deploy pipeline. It breaks auto-deploy, leaves no audit trail in git, and is easy to forget to run when things change.
The only sanctioned deploy path is:
main on GitHub.This means the Railway service must be connected to the GitHub repo before the first real deploy. The agent can still create the Railway project, databases, empty app services, variables, domains, and service settings before that manual GitHub source connection.
The Railway project name must match the GitHub repo name exactly (e.g. if the repo is unicore-railway/vendor-portal, the Railway project is also vendor-portal). This keeps the two in sync and makes it obvious which Railway project belongs to which repo.
Add a short description to the Railway project so anyone opening the workspace knows what the service does without having to open it. In the Railway dashboard: open the project → Settings → Description. One sentence is enough — what it does and who uses it (e.g. "Internal TOTP seed manager for Okta-enrolled employees").
railway init --name <project-name> --workspace <workspace>
Use the resolved workspace name, such as "Universe Unicore" or "GuruApps".
If the project already exists, link it with the workspace:
railway link --workspace <workspace> --project <project-id>
Create one or more app services in the project before the GitHub source is connected:
railway add --service <service-name>
Name each app service from the product architecture, README, package scripts, or repo layout. Use one Railway service for each independently deployed process.
Add managed resources only when the service needs them:
railway add --database postgres
Keep all services and managed resources for one product in one Railway project unless the user explicitly asks for separate projects.
Before the manual GitHub connection, configure what the CLI can configure: service variables, build command, start command, healthcheck for HTTP services, public domain for the public HTTP service, and project description.
Connect the GitHub repo via the Railway dashboard. Do not run railway add --repo as the normal flow — it can fail with an auth error because the Railway token may not carry the GitHub OAuth scope.
In the dashboard: open the project → select the existing app service → connect the GitHub repo as that service's source → select main and the correct root directory if the repo is a monorepo. Repeat this for each app service that deploys from GitHub.
Tell the user exactly what remains manual:
Railway project, resources, and service settings are prepared. Please connect the GitHub repo to these Railway services in the dashboard:
- <service-name>: <github-org>/<repo>, branch main, root <path-or-repo-root>
While the user is in the dashboard, have them set the project description too if it was not set earlier (see Naming above).
Use the production URL policy for the resolved context:
| Context | Production URL |
|---|---|
| Unicore | https://<service-name>.unicore-railway.io |
| GuruApps | Railway-provided URL generated for the public app service, for example https://<public-service-name>-production-abc123.up.railway.app |
For GuruApps, do not assume or configure a custom domain by default. Generate the Railway-provided domain in the Railway dashboard: service → Settings → Networking → Public Networking → Generate Domain. Railway-provided public domains use the *.up.railway.app pattern.
Confirm the final production URL with the user if the request or README names a different URL.
The shared Okta app was created in setting-up-nextauth-okta with the production redirect URI already included. Before deploying, confirm the app's sign-in redirect URIs contain the resolved production callback URL:
| Context | Callback URL |
|---|---|
| Unicore | https://<service-name>.unicore-railway.io/api/auth/callback/okta |
| GuruApps | generated Railway URL, for example https://<public-service-name>-production-abc123.up.railway.app/api/auth/callback/okta |
If the production URL changed, update the Okta app's redirect URIs to match. The Okta admin can edit them in Applications → <service-name> → General → Edit.
Use managing-service-env for CLI examples, --stdin, Railway staged changes, and the seal policy. This section lists the required production values for this deployment.
Set these base variables on each app service that needs them:
| Key | Value |
|---|---|
DATABASE_URL | ${{Postgres.DATABASE_URL}} |
AUTH_SECRET | fresh openssl rand -base64 32 output |
AUTH_URL | production URL for the resolved context |
AUTH_TRUST_HOST | true (Railway terminates TLS in front of the app) |
Also set these shared Okta variables:
| Key | Value |
|---|---|
OKTA_CLIENT_ID | from the shared Okta app (same as dev) |
OKTA_CLIENT_SECRET | from the shared Okta app (same as dev) |
OKTA_ISSUER | https://universe.okta.com |
Railway variables are the source of truth for production secrets. Names follow the Auth.js v5 convention (AUTH_*); the legacy NEXTAUTH_* names are no longer used.
Seal only high-sensitivity values: DATABASE_URL, AUTH_SECRET, OKTA_CLIENT_SECRET, and any password, signing key, encryption key, or API token. Leave IDs, URLs, domains, and flags readable.
After setting or auditing these values, show the Required Railway Seal actions list from managing-service-env. The list must say which variables the user must seal in the Railway dashboard and which variables must stay readable. If the user has not confirmed sealing yet, keep this as a pending manual step.
Use:
npm ci && npm run build — for services without Prismanpm ci && npx prisma generate && npx prisma migrate deploy && npm run build — for services with Prismanpm startUse the Prisma build command only when the service has a database. prisma migrate deploy is expected on each deploy.
main — this is the only deploy mechanismrailway up — see "Deployment method" aboveConfigure each public HTTP app service to use /api/health as its healthcheck path when that service exposes the shared health endpoint.
This endpoint is defined in bootstrapping-nextjs-service and extended by every dependency skill (setting-up-prisma-postgres, setting-up-nextauth-okta). It returns:
200 with { status: 'ok' | 'degraded', checks: [...] } when the app and every registered dependency are reachable503 with { status: 'down', checks: [...] } when any dependency is downRailway uses this signal to gate traffic during deploys — a failed healthcheck keeps the previous version serving instead of replacing it with a broken one.
Use the production URL policy for the resolved context:
| Context | Production URL |
|---|---|
| Unicore | https://<service-name>.unicore-railway.io |
| GuruApps | generated Railway URL, for example https://<public-service-name>-production-abc123.up.railway.app |
Confirm the final production URL with the user if the request or README names a different URL.
For GuruApps, skip custom domain setup unless the user explicitly says a custom domain is approved. Use the Railway-provided domain generated from the public service settings.
For Unicore custom domains, custom domain management requires workspace admin access. The CLI (railway domain) fails with an auth error for non-owners. Use the Railway dashboard: open the service → Settings → Domains → Add Domain → enter the final production domain.
Wait for the certificate to issue when using a custom domain, then confirm AUTH_URL and the production Okta callback URLs match the final production URL.
Once the domain is live, add the production URL and Railway project link to the top of the project's README.md:
**Production:** https://<resolved-production-url>
**Railway:** https://railway.com/project/<projectId>/service/<serviceId>?environmentId=<environmentId>
**Railway workspace:** <workspace>
Get the IDs from the CLI:
railway status
This prints the project ID, service ID, and environment ID for the linked service. The Railway link gives any developer a one-click jump to logs, variables, and deploy history without hunting through the dashboard.
Commit and push:
git add README.md
git commit -m "docs: add production URL and Railway project link"
git push
Current observability baseline:
console.logconsole.errorNot standardized yet:
npx claudepluginhub unicore-railway/unicore-skills --plugin unicore-skillsGuides creation, editing, and verification of skills for AI coding agents using test-driven development with subagent scenarios. Use when authoring or debugging skills.