Skip to main content

Scope

A Scope represents a hierarchical container for resources in Alchemy. Scopes manage resource state, lifecycle, and provide utilities for resource management. The root scope is created by calling alchemy(), and child scopes can be created using alchemy.run().

Properties

name
string
The name of the scope.
scopeName
string
The identifier for this scope level.
appName
string
The name of the root application.
parent
Scope | undefined
The parent scope, or undefined if this is the root scope.
stage
string
The stage name for this scope (e.g., “dev”, “prod”).
phase
'up' | 'destroy' | 'read'
The current lifecycle phase.
local
boolean
Whether resources should be simulated locally.
watch
boolean
Whether to watch for changes and automatically update resources.
quiet
boolean
Whether to suppress log output.
force
boolean
Whether to force resource updates.
adopt
boolean
Whether to adopt existing resources.
password
string | undefined
The password used for encrypting secrets in this scope.
resources
Map<string, PendingResource>
Map of all resources in this scope.
children
Map<string, Scope>
Map of child scopes.
root
Scope
The root scope of the application.

Methods

createPhysicalName()

Creates a physical name for a resource based on the application, stage, and resource ID.
createPhysicalName(
  id: string,
  delimiter?: string,
  maxLength?: number
): string
id
string
required
The resource identifier.
delimiter
string
default:"'-'"
The delimiter to use between name components.
maxLength
number
Maximum length for the physical name. If exceeded, components will be truncated.
Returns: A physical name in the format {appName}-{scope-chain}-{id}-{stage} Example:
const name = scope.createPhysicalName("bucket");
// Returns: "my-app-bucket-dev"

const name = scope.createPhysicalName("bucket", "_", 20);
// Returns: "my_app_bucket_dev" (truncated if needed)

fqn()

Generates a fully qualified name for a resource.
fqn(resourceID: string): string
resourceID
string
required
The resource identifier.
Returns: Fully qualified name in the format {appName}/{scope-chain}/{resourceID} Example:
const fqn = scope.fqn("my-resource");
// Returns: "my-app/dev/my-resource"

has()

Checks if a resource with the given ID exists in the scope’s state.
has(id: string, type?: string): Promise<boolean>
id
string
required
The resource identifier.
type
string
Optional resource type to match.
Returns: true if the resource exists (and matches the type if provided)

get()

Retrieves a value from the scope’s data storage.
get<T>(key: string): Promise<T>
key
string
required
The key to retrieve.
Returns: The stored value.

set()

Stores a value in the scope’s data storage.
set<T>(key: string, value: T): Promise<void>
key
string
required
The key to store.
value
T
required
The value to store.

delete()

Deletes a value from the scope’s data storage.
delete(key: string): Promise<void>
key
string
required
The key to delete.

run()

Runs a function within this scope’s context.
run<T>(fn: (scope: Scope) => Promise<T>): Promise<T>
fn
function
required
The async function to run within the scope.
Returns: The result of the function. Example:
const result = await scope.run(async (scope) => {
  const resource = await MyResource("id", { prop: "value" });
  return resource.id;
});

finalize()

Finalizes the scope, destroying orphaned resources and cleaning up.
finalize(options?: { force?: boolean; noop?: boolean }): Promise<void>
options.force
boolean
default:"false"
Force finalization even if not the root scope.
options.noop
boolean
default:"false"
Skip actual deletion operations.
Example:
const app = await alchemy("my-app");
// ... create resources ...
await app.finalize();

defer()

Defers execution of a function until the scope finalizes.
defer<T>(fn: () => Promise<T>): Promise<T>
fn
function
required
The async function to defer.
Returns: A promise that resolves when the deferred function completes. Example:
const result = scope.defer(async () => {
  // This runs during finalize
  return await someAsyncOperation();
});

// Later...
await scope.finalize();
const value = await result; // Now available

spawn()

Spawns an idempotent process managed by the scope.
spawn<E extends ((line: string) => string | undefined) | undefined>(
  id: string,
  options: {
    command: string;
    args?: string[];
    cwd?: string;
    env?: Record<string, string>;
    extract?: E;
  }
): Promise<E extends undefined ? undefined : string>
id
string
required
Unique identifier for the process.
options.command
string
required
The command to execute.
options.args
string[]
Command arguments.
options.cwd
string
Working directory for the command.
options.env
Record<string, string>
Environment variables.
options.extract
function
Function to extract a value from process output lines.
Returns: Extracted value if extract is provided, otherwise undefined. Example:
const url = await scope.spawn("dev-server", {
  command: "npm",
  args: ["run", "dev"],
  extract: (line) => {
    const match = line.match(/Local:\s+(https?:\/\/.+)/);
    return match?.[1];
  }
});
console.log(`Server running at ${url}`);

exec()

Executes a command and returns the result.
exec(
  id: string,
  command: string
): Promise<{ exitCode: number; stdout: string; stderr: string }>
id
string
required
Unique identifier for logging.
command
string
required
The command to execute.
Returns: Object containing exit code and output.

onCleanup()

Registers a cleanup function to run when the process exits.
onCleanup(fn: () => Promise<void>): void
fn
function
required
The async cleanup function.
Example:
const proc = spawn('server', ['--port', '3000']);
scope.onCleanup(async () => {
  proc.kill();
  await waitForExit(proc);
});

Static Methods

Scope.current

Gets the current scope from the async context.
static get current(): Scope
Returns: The current scope. Throws: Error if not running within an Alchemy scope. Example:
const scope = Scope.current;
console.log(scope.stage);

Scope.root

Gets the root scope of the current application.
static get root(): Scope
Returns: The root scope.

Examples

Creating a Root Scope

import { alchemy } from "alchemy";

const app = await alchemy("my-app", {
  stage: "prod",
  password: process.env.SECRET_PASSPHRASE
});

console.log(app.stage); // "prod"
console.log(app.appName); // "my-app"

await app.finalize();

Creating Child Scopes

const app = await alchemy("my-app");

await alchemy.run("api", async (apiScope) => {
  const worker = await Worker("api-worker", {
    entrypoint: "./src/api.ts"
  });

  console.log(apiScope.fqn("api-worker")); // "my-app/dev/api/api-worker"
});

await app.finalize();

Using Scope Data Storage

const app = await alchemy("my-app");

// Store metadata
await app.set("deployedAt", Date.now());
await app.set("version", "1.0.0");

// Retrieve metadata
const deployedAt = await app.get<number>("deployedAt");
const version = await app.get<string>("version");

console.log(`Deployed v${version} at ${new Date(deployedAt)}`);

await app.finalize();

Deferred Operations

const app = await alchemy("my-app");

const worker = await Worker("api", {
  entrypoint: "./src/worker.ts"
});

// Defer a warmup request until after deployment
const warmupResult = app.defer(async () => {
  const response = await fetch(worker.url);
  return response.status;
});

await app.finalize();

const status = await warmupResult;
console.log(`Warmup status: ${status}`);

Build docs developers (and LLMs) love