A lightweight TypeScript SDK and tooling around Railway's public GraphQL API. It ships a minimal client, generated operation helpers, and scripts that keep local documents aligned with the platform schema.
Install the package together with your preferred package manager:
npm install @crisog/railway-sdkNote
The SDK is published as ESM-only. Import it usingimport/dynamicimport(); CommonJSrequire()is not supported.
Most operations require an API token. You can pass the token directly when constructing a client or rely on the built‑in environment discovery:
export RAILWAY_API_TOKEN=...Supported environment variables, in lookup order:
RAILWAY_API_TOKEN(account / personal tokens)RAILWAY_TEAM_TOKENRAILWAY_PROJECT_TOKEN
If no token is discovered, the helpers throw MissingTokenError.
import { createRailwayFromEnv } from '@crisog/railway-sdk';
const railway = createRailwayFromEnv();
const projectsResult = await railway.projects.list({
variables: {
first: 5,
includeDeleted: false,
},
});
if (projectsResult.isErr()) {
throw projectsResult.error;
}
const { projects } = projectsResult.value;
for (const project of projects) {
console.log(`${project.id} – ${project.name}`);
}
if (projects.pageInfo.hasNextPage) {
console.log('More projects available…');
}createRailwayFromEnv and createRailway provide two ways to initialise the same namespaced API surface (railway.projects.list, railway.account.me, etc.).
- Use
createRailwayFromEnv()when your Railway token lives in environment variables. You can pass extra client options (custom headers, retries, fetch) via the optional argument. - Use
createRailway(options)when you need to supply the token programmatically (for example, when pulling it from a secret store).
Every generated helper returns ResultAsync<FlattenGraphQLResponse<TData>, GraphQLRequestError>. Awaiting the helper yields a Result; branch with .isOk() / .isErr(), unwrapOr, or .match() to handle success and failure explicitly. FlattenGraphQLResponse<TData> collapses GraphQL connection-style fields (edges/node or nodes) into plain arrays while preserving metadata (such as pageInfo and __typename) on the array object.
import { createRailway } from '@crisog/railway-sdk';
const railway = createRailway({
token: myToken,
tokenType: 'team',
});Both helpers return a Railway client with these namespaces. Use them to discover what each part of the API can do:
| Namespace | Summary |
|---|---|
projects |
Cover the full project lifecycle: CRUD, membership, invitations, feature flags, schedules, tokens, access checks, workflows, and transfers. |
services |
Manage services and deployments, including instance operations (limits, overrides), domains, feature flags, and runtimes. |
deployments |
Inspect and operate deployments: approvals, retries, logs/events, triggers, and snapshots. |
domains |
Work with custom domains attached to Railway services. |
account |
Manage the authenticated account: profile, email updates, invites, flags, passkeys, beta access, terms, and deletion. |
environments |
Manage environment lifecycle, logs, configuration patches (including staged changes), and deploy triggers. |
networking |
Administer private networks, endpoints, egress gateways, nodes, and TCP proxies. |
templates |
Discover, clone, generate, publish, or delete templates (including project sources). |
volumes |
Create, update, delete volumes, and administer backups and schedules. |
variables |
List, upsert, and manage variables, collections, and shared configurations. |
auth |
Handle login sessions, recovery codes, active sessions, and two-factor authentication flows. |
apiTokens |
Create, list, and revoke personal API tokens. |
billing |
Control customer subscriptions, referral info, usage limits, and fair use acknowledgements. |
integrations |
Configure third-party integrations (GitHub, Heroku, Vercel, providers) and their auth records. |
observability |
Access platform observability dashboards, logs, events, metrics, and usage statistics. |
preferences |
Retrieve and update user preferences plus per-resource overrides. |
webhooks |
Create, update, delete, and list project webhooks. |
workspaces |
Inspect and update workspaces, manage users and permissions, invite codes, templates, trusted domains, Slack channels, and identity providers. |
regions |
List available deployment regions. |
misc |
Miscellaneous public platform endpoints such as changelog assets, status, and platform feature flags. |
Refer to
src/api.tsfor the precise helper mapping and regenerate wrappers after schema or document changes (bun run generate:wrappers).
The SDK re-exports every generated wrapper from src/generated/operations.ts. You can cherry‑pick individual helpers if you prefer tree-shaken imports:
import { createRailwayFromEnv, projects } from '@crisog/railway-sdk';
const railway = createRailwayFromEnv();
const result = await projects(railway.client, {
variables: { first: 5 },
});Each helper enforces the correct variables shape and accepts optional GraphQLDocumentRequestOptions (custom headers, alternate fetch, abort signals, retry configuration, …). Responses use the flattened representation described above so you can iterate directly over arrays instead of traversing edges/node wrappers.
Pass retry configuration through the creation helpers:
const railway = createRailwayFromEnv({
retry: {
maxAttempts: 3,
shouldRetry: ({ error, response }) => response?.status >= 500 || error instanceof TypeError, // network errors
delayMs: (attempt) => attempt * 250,
},
});Retries never run by default. shouldRetry must return true to trigger another attempt. Aborted requests (AbortController, signal.aborted, etc.) are never retried and bubble the original abort error back to the caller.
- Generated operations resolve to
ResultAsync<FlattenGraphQLResponse<TData>, GraphQLRequestError>. TheErrvariant includesGraphQLRequestError(or subclasses such asNetworkError,NotFoundError,PermissionError,ValidationError). - Inspect
error.response,error.body, orerror.rawBodyon the error instance for full context. - Missing or empty tokens still throw
MissingTokenErrorduring client construction.
The SDK ships a few helpers that build on neverthrow results:
unwrapField(result, 'field')– ensures the top-level field exists before returning it.unwrapArray(result, 'field')– validates the field is an array.unwrapNested(result, ['path', 'to', 'field'])– walks nested objects safely.
All helpers preserve the original error type when the upstream result is Err, and produce a ResponseFieldError when the requested field is missing.
The repository includes scripts for keeping schema artifacts and wrappers in sync:
-
Fetch the latest schema
bun run codegen:introspect
Requires a valid token; writes
schema/railway-introspection.jsonand regeneratessrc/generated/graphql.ts. -
Emit typed wrappers
bun run generate:wrappers
Produces
src/generated/operations.ts, which powers the namespaced API surface.
Run both commands whenever the upstream schema changes or after adding/editing .graphql documents under src/graphql/.
Example scripts live under examples/. Execute them with Bun:
bun run examples/projects.tsAvailable scripts:
examples/me.ts– basic authenticated call using the high-level API.examples/projects.ts– list the first few projects with pagination variables.
Feel free to copy these as starting points for your own tooling.
bun install
bun run lint
bun run typecheckBun 1.2+ is recommended. The project enforces strict TypeScript options; run formatting/linting before submitting changes.