Skip to content

Railway.Sandbox reference

Source: src/Railway/Sandbox.ts

A Railway.Sandbox is an ephemeral Linux VM in an environment. Create it, execSandbox commands, snapshot with checkpoints, and destroy it when the task is done. Sandboxes are available on every plan.

Railway has no labels and sandboxes have no names. Identity is the Railway sandbox id. There is no in-place update — changing environment, region, idleTimeoutMinutes, networkIsolation, template, variables, publicDomains, resources, or sourceSandboxId replaces the Sandbox. Removing a previously configured option also replaces it.

Pass a Project (or Environment). Alchemy waits until the sandbox is RUNNING and ready to exec.

const site = yield* Railway.Project("Site");
const box = yield* Railway.Sandbox("Box", {
environment: site,
});

Railway auto-destroys a sandbox after it sits idle. Active exec sessions and SSH foreground work defer teardown; background processes alone do not. Hobby/Pro default is 30 minutes (max 120), with 0 disabling idle teardown. Trial/Free default and max is 5 minutes. A sandbox with idle teardown disabled remains billable until explicitly destroyed.

const box = yield* Railway.Sandbox("Box", {
environment: site,
idleTimeoutMinutes: 5,
});

Baked into the sandbox at create time. Available to every command.

const box = yield* Railway.Sandbox("Box", {
environment: site,
variables: { NODE_ENV: "production" },
});

Boot from a named checkpoint, or from build instructions.

const box = yield* Railway.Sandbox("Box", {
environment: site,
template: { name: "after-deps" },
});
const preview = yield* Railway.Sandbox("Preview", {
environment: site,
networkIsolation: "PRIVATE",
publicDomains: [{ port: 3000 }],
resources: { cpu: 1, memoryGB: 1 },
});

Start the HTTP server on 0.0.0.0:3000. Published hostnames are available in preview.domains; creating a route does not start the server.

const fork = yield* Railway.Sandbox("Attempt", {
environment: site,
sourceSandboxId: box.sandboxId,
idleTimeoutMinutes: 5,
});

Files are copied, but running processes and memory are not. Keep the source declared while replacing a fork. For a reusable named disk snapshot, use Railway.SandboxCheckpoint and pass its name as template.name.

Run a command after deploy with execSandbox or Exec.

const result = yield* Railway.execSandbox({
sandboxId: box.sandboxId,
environmentId: box.environmentId,
command: "echo hello",
});

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

src/box.ts
import * as Railway from "alchemy/Railway";
export const Site = Railway.Project("Site");
export const Box = Railway.Sandbox("Box", {
environment: Site,
idleTimeoutMinutes: 10,
});

Source: src/Railway/SandboxCheckpoint.ts

A managed, named snapshot of a running Railway sandbox’s disk. Capture is synchronous: the checkpoint is bootable when deployment completes. Files survive restoration, but running processes and memory do not.

The snapshot is captured once, not on every deploy. Changing the source replaces it; changing the name renames it. Existing explicit names require adoption. Persisted ID and capture time protect against deleting or overwriting a different capture that later occupies the same name. Interrupted renames are recovered from the persisted attempted name and original capture time. Recovery never searches arbitrary names by timestamp; losing either piece of evidence requires explicit operator recovery. Railway exposes no conditional mutations, so concurrent external writers must not mutate the same checkpoint while Alchemy is reconciling it.

const box = yield* Railway.Sandbox("Box", { environment: site });
const checkpoint = yield* Railway.SandboxCheckpoint("Prepared", {
sandbox: box,
});
const restored = yield* Railway.Sandbox("Restored", {
environment: site,
template: { name: checkpoint.key },
});

SandboxCheckpoint: Adopt an existing checkpoint

Section titled “SandboxCheckpoint: Adopt an existing checkpoint”
const checkpoint = yield* Railway.SandboxCheckpoint("Prepared", {
sandbox: box,
name: "after-deps",
}).pipe(Alchemy.adopt(true));