Programs
A program is your own server, run in a sandbox the Stack declares. Alchemy bundles it, uploads it into the sandbox and starts it with Node.js 24, then serves its port at https://<subdomain>-3000.on.boat.dev.
Give a sandbox a program
Section titled “Give a sandbox a program”Give Boat.Sandbox a main and an implementation:
import * as Boat from "@alchemy.run/boat";import * as Effect from "effect/Effect";import * as HttpServerResponse from "effect/http/HttpServerResponse";
export default class Api extends Boat.Sandbox<Api>()( "Api", { main: import.meta.url, type: "small", noEnv: true, public: true }, Effect.gen(function* () { return { fetch: Effect.gen(function* () { return yield* HttpServerResponse.json({ ok: true }); }), }; }),) {}Add it to the Stack and return its URL:
import * as Boat from "@alchemy.run/boat";import * as Alchemy from "alchemy";import * as Effect from "effect/Effect";import Api from "./src/Api.ts";
export default Alchemy.Stack( "MyApp", { providers: Boat.providers(), state: Alchemy.localState() }, Effect.gen(function* () { const api = yield* Api; return { url: api.url.as<string>() }; }),);The program listens on port (3000 unless you say otherwise), and reads PORT from its environment.
A deploy restarts the process, not the sandbox
Section titled “A deploy restarts the process, not the sandbox”A program’s sandbox stays the same across deploys; only the process changes.
An unchanged deploy leaves the process alone. A program sandbox never stops on its own unless you set autoStop. If it stopped anyway, or rebooted, the next deploy resumes it and starts the program again.
env on a program sandbox is the program’s: changing it restarts the process, without replacing the sandbox.
Its URL needs a token unless it’s public
Section titled “Its URL needs a token unless it’s public”A program’s URL needs its token unless you set public: true. The token is urlToken, sent as the _token query parameter or the _port_auth cookie:
const api = yield* Api;return { url: api.url, token: api.urlToken };See Ports & URLs.
Use bindings from the program
Section titled “Use bindings from the program”A program uses bindings like any other host. Each gets its own key, which can do only what that binding needs:
Effect.gen(function* () { const sandboxes = yield* Boat.CreateSandbox(); return { fetch: Effect.gen(function* () { const running = yield* sandboxes.list({ labels: { pool: "agents" } }); return yield* HttpServerResponse.json({ count: running.length }); }), };}).pipe(Effect.provide(Boat.CreateSandboxHttp));To start sandboxes with a project already set up, see Snapshots & forks.