Skip to content

Sprite

Source: src/Fly/Sprite.ts

A Sprite is an Effect program running in a Fly.io Sprite. Sprites are org-scoped Linux sandboxes. They hibernate when idle and wake on demand. There is no parent App. Unlike a Service, Alchemy does not build a Docker image.

A Sprite is a class. Props describe the sandbox. The Effect is the program that runs on it. There is no parent App.

main: import.meta.url is the bundle entrypoint. Alchemy bundles this file with Rolldown, writes it onto the Sprite, and runs it as a Sprite service on port. Auth is FLY_API_TOKEN.

export default class Box extends Fly.Sprite<Box>()(
"Box",
{ main: import.meta.url },
Effect.gen(function* () {
return {};
}),
) {}

Return fetch from the init Effect to boot an HTTP server. The Sprite URL proxies to port.

export default class Box extends Fly.Sprite<Box>()(
"Box",
{ main: import.meta.url },
Effect.gen(function* () {
return {
fetch: Effect.succeed(HttpServerResponse.text("hello")),
};
}),
) {}

Yield the Sprite in the Stack. box.url is https://{name}-….sprites.app.

export default Alchemy.Stack(
"MyApp",
{ providers: Fly.providers(), state: Alchemy.localState() },
Effect.gen(function* () {
const box = yield* Box;
return { url: box.url };
}),
);

urlAuth is public or sprite. Default is public so url answers without a Sprites token.

export default class Box extends Fly.Sprite<Box>()(
"Box",
{ main: import.meta.url, urlAuth: "sprite" },
Effect.gen(function* () {
return {
fetch: Effect.succeed(HttpServerResponse.text("hello")),
};
}),
) {}

Yield Config in init. Alchemy reads the value from the env of whoever deploys and writes it onto the Sprite. Do not pass env: { ... } on a Sprite.

Yield FileSystem.FileSystem in init, never inside fetch.

import * as Config from "effect/Config";
import * as FileSystem from "effect/FileSystem";
import * as Redacted from "effect/Redacted";
export default class Box extends Fly.Sprite<Box>()(
"Box",
{ main: import.meta.url },
Effect.gen(function* () {
const apiKey = yield* Config.redacted("API_KEY");
const fs = yield* FileSystem.FileSystem;
yield* fs.makeDirectory("/tmp", { recursive: true });
return {
fetch: Effect.gen(function* () {
const token = Redacted.value(apiKey);
return HttpServerResponse.text("ok");
}),
};
}),
) {}

Exec runs a command on the Sprite. Provide ExecHttp.

const exec = yield* Fly.Exec(Box);
const result = yield* exec({ cmd: ["ls", "-la"] });

Checkpoint snapshots and restores the Sprite disk. Provide CheckpointHttp.

const checkpoint = yield* Fly.Checkpoint(Box);
yield* checkpoint.create({ comment: "before" });
yield* checkpoint.restore("v1");

Omit name and Alchemy generates one from the stack, stage, and logical ID.

export default class Box extends Fly.Sprite<Box>()(
"Box",
{ main: import.meta.url, name: "box" },
Effect.gen(function* () {
return {
fetch: Effect.succeed(HttpServerResponse.text("hello")),
};
}),
) {}

handler is the named export to load from main. Default is "default".

export default class Box extends Fly.Sprite<Box>()(
"Box",
{ main: import.meta.url, handler: "box" },
Effect.gen(function* () {
return {
fetch: Effect.succeed(HttpServerResponse.text("hello")),
};
}),
) {}