Skip to content

Variable

Source: src/Railway/Variable.ts

A Railway.Variable is a project- or service-scoped env var. Railway injects it into services in that environment. The plaintext is never stored in attributes.

Wrap the value with Redacted.make so it is never logged. Omit name and Alchemy generates an ownership-stamped name. Shared (no service) variables apply to every service in the environment.

const site = yield* Railway.Project("Site");
const dbUrl = yield* Railway.Variable("DatabaseUrl", {
project: site,
value: Redacted.make("postgres://…"),
});

name is the env-var services see. It is stored as-is (case-sensitive).

export const ApiToken = Railway.Variable("ApiToken", {
project: Site,
name: "API_TOKEN",
value: Redacted.make("sk_live_…"),
});

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 token = yield* Railway.Variable("StagingToken", {
project: site,
environment: staging,
value: Redacted.make("sk_staging_…"),
});

Pass service to attach the variable to one service instead of the shared project set.

const api = yield* Railway.Service("Api", {
project: site,
image: "hashicorp/http-echo",
});
const token = yield* Railway.Variable("ApiToken", {
project: site,
service: api,
name: "API_TOKEN",
value: Redacted.make("sk_live_…"),
});

value may be a Railway.ref(resource, key) template instead of a plaintext secret. Upsert stores ${{LogicalName.KEY}} (or ${{shared.NAME}}) — not a resolved URI. Railway interpolates it. Next to ConnectPostgres: use ConnectPostgres for a typed client inside an Effect-native Service; use Railway.ref when you want Railway’s own ${{Db.DATABASE_URL}} interpolation (IaC db.env.DATABASE_URL).

Reference Postgres DATABASE_URL

const db = yield* Railway.Postgres("Db", { project: site });
const api = yield* Railway.Service("Api", {
project: site,
image: "hashicorp/http-echo",
});
const databaseUrl = yield* Railway.Variable("DatabaseUrl", {
project: site,
service: api,
name: "DATABASE_URL",
value: Railway.ref(db, "DATABASE_URL"),
});

Shared variable

yield* Railway.Variable("SentryDsn", {
project: site,
name: "SENTRY_DSN",
value: Redacted.make("https://…"),
});
yield* Railway.Variable("ApiSentry", {
project: site,
service: api,
name: "SENTRY_DSN",
value: Railway.ref("shared", "SENTRY_DSN"),
});

Updating value is in place via variableUpsert. Deploys are skipped (skipDeploys: true); the Service resource owns deploys.

export const ApiToken = Railway.Variable("ApiToken", {
project: Site,
name: "API_TOKEN",
value: Redacted.make("sk_live_rotated"),
});

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

src/secrets.ts
import * as Railway from "alchemy/Railway";
import * as Redacted from "effect/Redacted";
export const Site = Railway.Project("Site");
export const ApiToken = Railway.Variable("ApiToken", {
project: Site,
name: "API_TOKEN",
value: Redacted.make("sk_live_…"),
});