feat(registry/bpmct/templates/railway): add Railway (via GraphQL) template#954
Merged
Conversation
…plate
Adds a Railway-backed Coder template that provisions each workspace as
its own Railway project via direct GraphQL calls (no community
Terraform provider). Uses a pre-built image on GHCR and
serviceInstanceUpdate(source: { image }) + serviceInstanceDeployV2 to
keep median start time at ~6s.
See https://github.com/bpmct/coder-railway for the reasoning behind
GraphQL over the Terraform provider and the reliability suite (three
other variants tried along the way).
🤖 Generated with Coder Agents using Claude, on behalf of @bpmct
- Reformats 10 shell scripts to prettier-plugin-sh style (multi-line brace groups, spacing around redirects, aligned pipes). - Replaces `<your-railway-token>` with `YOUR_RAILWAY_TOKEN` in README code fences. Angle brackets were being parsed as HTML tags by prettier and mangled inside sh fences with line continuations. 🤖 Generated with Coder Agents using Claude, on behalf of @bpmct
Copies build/Dockerfile and build/entrypoint.sh from bpmct/coder-railway into the template so users don't have to leave the registry to inspect the image contract. README's 'Custom workspace image' section now spells out two extend patterns: - Extend the default image (FROM ghcr.io/bpmct/railway-coder-workspace:latest, layer tools on top). This is the recommended path for most teams since it inherits the entrypoint + Coder agent wiring. - Duplicate build/ and swap the base image entirely. Copy entrypoint.sh verbatim, since the volume-chown + CODER_INIT_SCRIPT_B64 decode + drop-to-coder contract lives there, not in the base image. 🤖 Generated with Coder Agents using Claude, on behalf of @bpmct
Collaborator
|
@bpmct Everything works well for me as well. I just wanted to test it as well because I haven't had a chance to mess with railway much but I picked out a few things maybe worth changing before we commit but otherwise LGTM! |
Co-authored-by: DevCats <christofer@coder.com>
Co-authored-by: DevCats <christofer@coder.com>
DevelopmentCats
approved these changes
Jul 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds a Railway-backed Coder template under
registry/bpmct/templates/railway. Each workspace becomes a fully isolated Railway project (own environment, own volume, own service token), running a container built from a pre-built image on GHCR.What makes this different from what you'd get with the community
terraform-community-providers/railwayprovider:railway_volumewrites to a service before the service is fully attached (and Railway rejectsvolumeCreateon services that have had deployments), andvariableUpserttriggers extra redeploys that intermittently fail with "Cannot redeploy without a snapshot" / "Cannot redeploy yet, please wait for the original deployment to finish building". This template bypasses the provider and calls the Railway public API directly withcurl.skipDeploys: trueonvariableUpsert. Undocumented flag that persists the value without enqueuing a redeploy.serviceInstanceDeployV2is what actually deploys, and picks up the freshly-set variables.serviceInstanceUpdate(source: { image }) + serviceInstanceDeployV2for the image deploy, rather thanserviceConnect(which builds from a repo on every start). Median start time drops from ~62s (repo build) to ~6s (pre-built image).volumeCreatebefore any deployment activity, with backoff on the "creating volumes too quickly" rate limit.Full write-up, benchmark suite, and three other approaches (Terraform-provider-based, hybrid, Railway-CLI-based) live at bpmct/coder-railway. The
variants/wip/image/directory in that repo is the exact source this template was extracted from.Demo (Loom, ~5 min)
Note
The Loom was recorded before startup was optimized (per-start Docker build, ~62s median). This template now uses
serviceInstanceUpdate(source: { image })against a pre-built image, so median start time is ~6s. The rest of the flow in the demo (workspace creation, project isolation, Railway CLI) still applies.Type of Change
Template Information
Path:
registry/bpmct/templates/railwayTesting & Validation
bun test)bun fmt)Pushed and running on a Railway-hosted Coder deployment (
coder.up.railway.app) as templaterailway-optimized. Bench numbers against that deployment with the default public image (ghcr.io/bpmct/railway-coder-workspace:latest, no registry credentials):coder startto agent connected.coder createto first agent connect.The reliability suite that produced those numbers (parallel start stress test, create stress test, provider-error-scanner) lives at bpmct/coder-railway/scripts/.
Related Issues
None.
File layout
Bash bodies live in
scripts/*.sh, one file per (resource, action).main.tfonly wirescommand = "bash ${path.module}/scripts/X.sh"and passes runtime values viaenvironment {}blocks. Destroy provisioners referenceself.input.*because vars/locals/data are not allowed in destroy scopes.🤖 Generated with Coder Agents using Claude, on behalf of @bpmct