Skip to content

Railway.Project reference

Source: src/Railway/Group.ts

A Railway.Group organizes services, databases, volumes, and buckets on the project canvas. IaC parity with group("Backend", [api, worker, db]).

Groups have no dedicated create/delete mutation. Alchemy writes EnvironmentConfig.groups (and services[id].groupId) via environmentPatchCommit, matching Railway’s own IaC compiler. Volume membership is observed from environment.canvasGroupRefs. When Railway does not persist a first-class Group id, the resource still records member service/volume/bucket ids. canvasViewMerge / canvasViewMergePreview copy canvas layout between environments.

Pass a Project and the members to group. Alchemy generates a unique name unless you pass one.

const site = yield* Railway.Project("Site");
const api = yield* Railway.Service("Api", {
project: site,
image: "hashicorp/http-echo",
});
const worker = yield* Railway.Service("Worker", {
project: site,
image: "hashicorp/http-echo",
});
const backend = yield* Railway.Group("Backend", {
project: site,
resources: [api, worker],
});

Defaults to the Project’s primary environment. Pass a Railway.Environment (or { environmentId }) to target another one.

const staging = yield* Railway.Environment("Staging", { project: site });
const backend = yield* Railway.Group("Backend", {
project: site,
environment: staging,
resources: [api],
});

Postgres/Redis/MySQL/Mongo group as services (serviceId). Volumes and buckets are accepted as members (volumeId / bucketId).

const db = yield* Railway.Postgres("Db", { project: site });
const backend = yield* Railway.Group("Backend", {
project: site,
resources: [api, db],
});

Declare the Project once. Pass it into every child. Resource-valued props accept the resource or an Effect producing it.

src/backend.ts
import * as Railway from "alchemy/Railway";
export const Site = Railway.Project("Site");
export const Api = Railway.Service("Api", {
project: Site,
image: "hashicorp/http-echo",
});
export const Backend = Railway.Group("Backend", {
project: Site,
resources: [Api],
});

Source: src/Railway/Project.ts

A Railway.Project is a workspace-scoped namespace. It owns environments and services. Names are unique per workspace.

Alchemy generates a unique name unless you pass one. url is the dashboard URL. A production environment is created with the project — do not recreate it as an Environment resource.

const site = yield* Railway.Project("Site");

Pass name when you need a stable project name. Changing it later updates the project in place.

const site = yield* Railway.Project("Site", {
name: "my-site",
});

description is optional and updates in place.

const site = yield* Railway.Project("Site", {
description: "production web app",
});

Workspace defaults to the current token. Pass workspaceId to pin it.

const site = yield* Railway.Project("Site", {
workspaceId: "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
});

defaultEnvironmentName is create-only. Railway’s default is production. Extra environments (staging) are a separate Environment resource.

const site = yield* Railway.Project("Site", {
defaultEnvironmentName: "production",
});

Declare the Project once. Pass it into every child. Resource-valued props accept the resource or an Effect producing it.

src/project.ts
import * as Railway from "alchemy/Railway";
export const Site = Railway.Project("Site");

Source: src/Railway/ProjectEnvironment.ts

A Railway.Environment is an extra deploy environment under a Project (staging, preview, …). The production environment is created with the Project — do not recreate it as an Environment resource.

Alchemy generates a unique name unless you pass one. Production is already on the Project as environmentId.

const site = yield* Railway.Project("Site");
const staging = yield* Railway.Environment("Staging", {
project: site,
});

Pass name when you need a stable environment name (staging). Changing it later updates the environment in place.

const staging = yield* Railway.Environment("Staging", {
project: site,
name: "staging",
});

sourceEnvironmentId copies services, volumes, configuration, and variables from another environment. Create-only.

const staging = yield* Railway.Environment("Staging", {
project: site,
sourceEnvironmentId: site.environmentId,
});

Declare the Project once. Pass it into every child. Resource-valued props accept the resource or an Effect producing it.

src/project.ts
import * as Railway from "alchemy/Railway";
export const Site = Railway.Project("Site");
export const Staging = Railway.Environment("Staging", {
project: Site,
});

Source: src/Railway/ref.ts

Emit a Railway variable-reference template (${{Service.KEY}} or ${{shared.NAME}}). Distinct from the unexported resource-prop Ref<T> — never export that Ref.

Railway.ref(Db, "DATABASE_URL") returns ${{LogicalName.DATABASE_URL}} where LogicalName is resource.LogicalId (Postgres("Db")Db). Shared variables use the "shared" namespace: Railway.ref("shared", "SENTRY_DSN") returns ${{shared.SENTRY_DSN}}.

Store the string as a Variable value (or on Service.env). Railway keeps the template (unrendered: true) and interpolates it at build/runtime — it is not a resolved URI. Use ConnectPostgres when you want a typed client inside an Effect-native Service.

Railway interpolates by service name. Set name on Postgres/Service to the LogicalId if you need the template to resolve to that service.

Pass a resource (or its LogicalId) and the variable key. The result is a template string, not a URI.

const db = yield* Railway.Postgres("Db", { project: site });
yield* Railway.Variable("DatabaseUrl", {
project: site,
service: api,
name: "DATABASE_URL",
value: Railway.ref(db, "DATABASE_URL"),
});

"shared" is the environment-wide namespace (IaC ctx.shared.NAME).

env: {
SENTRY_DSN: Railway.ref("shared", "SENTRY_DSN"),
}

Source: src/Railway/Template.ts

A Railway.Template deploys a marketplace template into a Project. Alchemy looks up the template (template / templates), sends templateDeployV2 with its serializedConfig, and adopts the project/services the workflow creates.

Pass a Project to deploy into an existing one. Omit project and Alchemy creates an owned Project first (the workspace project-create cap is serialized).

templateId is a marketplace UUID or code (postgres). Pass a Project to deploy into it.

const site = yield* Railway.Project("Site");
const db = yield* Railway.Template("Postgres", {
templateId: "postgres",
project: site,
});

Omit project to let Alchemy create one. The name is stamped so nuke can reclaim it.

const db = yield* Railway.Template("Postgres", {
templateId: "postgres",
});

Omit serializedConfig to use the marketplace default. Pass a config (from template.serializedConfig, with service variable values filled in) to override.

const db = yield* Railway.Template("Postgres", {
templateId: "postgres",
project: site,
serializedConfig: config,
});

Defaults to the Project’s primary environment.

const staging = yield* Railway.Environment("Staging", { project: site });
const db = yield* Railway.Template("StagingPostgres", {
templateId: "postgres",
project: site,
environment: staging,
});

Resource-valued props accept the resource or an Effect producing it.

src/db.ts
import * as Railway from "alchemy/Railway";
export const Site = Railway.Project("Site");
export const Postgres = Railway.Template("Postgres", {
templateId: "postgres",
project: Site,
});