alchemy

IndexedCommit: de7ed3a1 pullsUpdated Jan 29, 2026

Alchemy is a TypeScript-native Infrastructure-as-Code (IaC) library that lets you provision and manage cloud resources using pure TypeScript. Unlike Terraform or Pulumi, Alchemy resources are simple m

Install this reference
Reference

Alchemy

Alchemy is a TypeScript-native Infrastructure-as-Code (IaC) library that lets you provision and manage cloud resources using pure TypeScript. Unlike Terraform or Pulumi, Alchemy resources are simple memoized async functions that run in any JavaScript runtime, making infrastructure code embeddable directly in your application.

Quick References

FilePurpose
alchemy/src/index.tsMain entry point and core exports
alchemy/src/cloudflare/index.tsCloudflare provider resources
alchemy/src/aws/index.tsAWS provider resources
README.mdProject overview and examples

Providers

ProviderImport PathDescription
Cloudflarealchemy/cloudflareWorkers, R2, KV, D1, Queues, Durable Objects
AWSalchemy/awsLambda, S3, DynamoDB, IAM, SQS, SES
Neonalchemy/neonServerless Postgres (projects, branches)
PlanetScalealchemy/planetscaleMySQL database (database, branches, passwords)
GitHubalchemy/githubRepository webhooks, secrets, environments
Dockeralchemy/dockerContainers, images, networks, volumes
Stripealchemy/stripeProducts, prices, webhooks, customers
Upstashalchemy/upstashServerless Redis
Vercelalchemy/vercelProjects and domains
ClickHousealchemy/clickhouseAnalytics database services

When to Use

  • Deploying Cloudflare Workers with bindings to KV, R2, D1, Durable Objects, and Queues
  • Managing multi-cloud infrastructure with a single TypeScript codebase
  • Embedding infrastructure provisioning directly in your application code
  • Creating local development environments that mirror production
  • Building serverless applications with automatic resource lifecycle management

Installation

npm install alchemy

For specific providers, install the required peer dependencies:

# Cloudflare
npm install alchemy wrangler @cloudflare/workers-types

# AWS
npm install alchemy @aws-sdk/client-lambda @aws-sdk/client-s3 @aws-sdk/client-dynamodb

Best Practices

  1. Always call app.finalize() at the end of your alchemy script to trigger cleanup of orphaned resources and ensure proper state management.

  2. Use alchemy.secret() for sensitive values - Secrets are automatically encrypted in state files when a password is provided via the ALCHEMY_PASSWORD environment variable.

  3. Leverage stages for environment isolation - The stage option (defaulting to your username) scopes all resources, allowing multiple developers or environments to coexist safely.

  4. Use explicit resource names with adopt: true - When migrating existing infrastructure, use the adopt option to take ownership of pre-existing resources.

  5. Configure a persistent state store for CI/CD - Use CloudflareStateStore or S3StateStore in production to avoid orphaned resources when running in CI environments.

Common Patterns

Initialize an Alchemy application:

import alchemy from "alchemy";

const app = await alchemy("my-app", {
  stage: process.env.STAGE || "dev",
  password: process.env.ALCHEMY_PASSWORD,
});

// ... create resources ...

await app.finalize();

Create a Cloudflare Worker with bindings:

import alchemy from "alchemy";
import { Worker, R2Bucket, KVNamespace, D1Database, Queue } from "alchemy/cloudflare";

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

const bucket = await R2Bucket("storage", { name: "my-storage" });
const kv = await KVNamespace("cache", { title: "my-cache" });
const db = await D1Database("db", { name: "my-database" });
const queue = await Queue("tasks", { name: "task-queue" });

const worker = await Worker("api", {
  entrypoint: "./src/worker.ts",
  bindings: {
    BUCKET: bucket,
    CACHE: kv,
    DB: db,
    TASKS: queue,
  },
  url: true,
});

console.log(`Worker URL: ${worker.url}`);
await app.finalize();

Use Durable Objects for state management:

import { Worker, DurableObjectNamespace } from "alchemy/cloudflare";

const counter = await DurableObjectNamespace("counter", {
  className: "Counter",
  sqlite: true,
});

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

Create encrypted secrets:

import alchemy from "alchemy";

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

const worker = await Worker("api", {
  entrypoint: "./src/worker.ts",
  bindings: {
    API_KEY: alchemy.secret(process.env.API_KEY),
    // Or use the shorthand for environment variables:
    DB_PASSWORD: alchemy.secret.env.DB_PASSWORD,
  },
});

Deploy AWS Lambda with DynamoDB:

import alchemy from "alchemy";
import { Function, Table, Role, PolicyAttachment } from "alchemy/aws";

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

const table = await Table("users", {
  tableName: "users-table",
  partitionKey: { name: "id", type: "S" },
});

const role = await Role("lambda-role", {
  assumeRolePolicy: {
    Version: "2012-10-17",
    Statement: [{
      Effect: "Allow",
      Principal: { Service: "lambda.amazonaws.com" },
      Action: "sts:AssumeRole",
    }],
  },
});

const fn = await Function("handler", {
  functionName: "my-function",
  handler: "index.handler",
  runtime: "nodejs20.x",
  bundle: { entryPoint: "./src/handler.ts" },
  role: role,
  environment: {
    TABLE_NAME: table.tableName,
  },
});

await app.finalize();

Local development with --dev flag:

// Run with: bun ./alchemy.run.ts --dev
const app = await alchemy("my-app");

// Resources automatically use local emulation when --dev is passed
const db = await D1Database("db", { name: "my-db" });
const worker = await Worker("api", {
  entrypoint: "./src/worker.ts",
  bindings: { DB: db },
  url: true,
});

// Worker is available at localhost with hot reloading
console.log(worker.url); // http://localhost:8787

Nested scopes for grouped resources:

import alchemy from "alchemy";
import { Worker, KVNamespace } from "alchemy/cloudflare";

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

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

await app.finalize();

API Quick Reference

ExportTypeDescription
alchemyfunctionInitialize an Alchemy application scope
alchemy.secret()functionCreate an encrypted secret value
alchemy.secret.envproxyShorthand for alchemy.secret(process.env.X)
alchemy.run()functionCreate a nested resource scope
alchemy.destroy()functionProgrammatically destroy resources
ResourcefunctionDefine custom resource types
ScopeclassManage resource lifecycle and state
SecretclassWrapper for sensitive values

CLI Arguments

Alchemy scripts automatically parse these CLI arguments:

ArgumentDescription
--destroyDelete all resources instead of creating/updating
--dev / --localRun resources locally with emulation
--watchEnable hot reloading for supported resources
--stage <name>Set the deployment stage
--quietSuppress output logging
--adoptAdopt existing resources that match by name
--forceApply updates even without detected changes

Environment Variables

VariableDescription
ALCHEMY_PASSWORDPassphrase for encrypting/decrypting secrets
ALCHEMY_STAGEDefault stage name (falls back to $USER)
ALCHEMY_TELEMETRY_DISABLEDSet to disable anonymous telemetry
DO_NOT_TRACKAlternative way to disable telemetry

State Management

By default, Alchemy stores state locally in .alchemy/{stage}/ directories. For CI/CD environments, configure a persistent state store:

import alchemy from "alchemy";
import { CloudflareStateStore } from "alchemy/cloudflare";

const app = await alchemy("my-app", {
  stateStore: CloudflareStateStore({
    accountId: process.env.CF_ACCOUNT_ID,
    bucketName: "my-state-bucket",
  }),
});

TypeScript Types

Access resource environment types for Workers:

import type { Worker } from "alchemy/cloudflare";

// Use the Worker's Env type in your worker code
type Env = typeof worker.Env;

export default {
  async fetch(request: Request, env: Env) {
    const value = await env.CACHE.get("key");
    return new Response(value);
  },
};

Framework Integrations

Alchemy provides Vite plugins for popular frameworks:

// vite.config.ts for React Router
import { reactRouter } from "@react-router/dev/vite";
import { cloudflare } from "alchemy/cloudflare/react-router";

export default defineConfig({
  plugins: [
    cloudflare(),
    reactRouter(),
  ],
});

Available framework plugins:

  • alchemy/cloudflare/vite - Vite with Cloudflare Workers
  • alchemy/cloudflare/react-router - React Router v7
  • alchemy/cloudflare/tanstack-start - TanStack Start
  • alchemy/cloudflare/sveltekit - SvelteKit
  • alchemy/cloudflare/nuxt - Nuxt 3
  • alchemy/cloudflare/astro - Astro
  • alchemy/cloudflare/redwood - RedwoodJS

“Explore distant worlds.”

© 2026 Oscar Gabriel