Part 1: Your First Stack
In this first part you’ll install Alchemy and Effect, create a Stack with an AWS S3 Bucket, and deploy it — all in under five minutes.
Prerequisites
Section titled “Prerequisites”- Bun (recommended) or Node.js 22+
- An AWS account and an IAM identity with permission to create the resources you plan to deploy
Create a project
Section titled “Create a project”Start with an empty directory and initialize a package.json:
mkdir my-app && cd my-app && bun init -ymkdir my-app && cd my-app && npm init -ymkdir my-app && cd my-app && pnpm initmkdir my-app && cd my-app && yarn init -yInstall dependencies
Section titled “Install dependencies”Install alchemy@next and effect@>=4.0.0-beta.93|| >=4.0.0:
bun add "alchemy@next" "effect@>=4.0.0-beta.93|| >=4.0.0" "@effect/platform-bun@>=4.0.0-beta.93|| >=4.0.0" "@effect/platform-node@>=4.0.0-beta.93|| >=4.0.0"npm install "alchemy@next" "effect@>=4.0.0-beta.93|| >=4.0.0" "@effect/platform-bun@>=4.0.0-beta.93|| >=4.0.0" "@effect/platform-node@>=4.0.0-beta.93|| >=4.0.0"pnpm add "alchemy@next" "effect@>=4.0.0-beta.93|| >=4.0.0" "@effect/platform-bun@>=4.0.0-beta.93|| >=4.0.0" "@effect/platform-node@>=4.0.0-beta.93|| >=4.0.0"yarn add "alchemy@next" "effect@>=4.0.0-beta.93|| >=4.0.0" "@effect/platform-bun@>=4.0.0-beta.93|| >=4.0.0" "@effect/platform-node@>=4.0.0-beta.93|| >=4.0.0"Create the Stack
Section titled “Create the Stack”Every Alchemy program starts with a Stack — a collection of
Resources managed by Providers with state tracked between deploys.
Create an alchemy.run.ts file:
import * as Alchemy from "alchemy";import * as AWS from "alchemy/AWS";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "MyApp", { providers: AWS.providers(), state: AWS.state(), }, Effect.gen(function* () { // we'll add resources here next }),);Alchemy.Stack is the root of every app. The first argument
("MyApp") doubles as a logical id and as the prefix Alchemy uses
when AWS asks for physical resource names.
How credentials resolve
Section titled “How credentials resolve”providers: AWS.providers() registers every AWS resource and IAM
policy binding that ships with Alchemy, and resolves credentials from
your Alchemy profile — SSO, environment
variables, or stored access keys. You’ll pick one interactively the
first time you deploy; see Setup for the details of
each method.
Where state lives
Section titled “Where state lives”state: AWS.state() stores deploy state in an account-regional S3
bucket (alchemy-state-{accountId}-{region}-an), created lazily on
the first deploy. Because the state lives in your AWS account rather
than on disk, the same configuration works locally and in CI with no
extra setup.
Add a Resource
Section titled “Add a Resource”Resources represent cloud infrastructure — buckets, tables, queues,
functions, and so on. Each resource is yield*-ed inside the Stack’s
Effect generator.
Add an S3 Bucket:
import * as Alchemy from "alchemy";import * as AWS from "alchemy/AWS";import * as Effect from "effect/Effect";
export default Alchemy.Stack( "MyApp", { providers: AWS.providers(), state: AWS.state(), }, Effect.gen(function* () { const bucket = yield* AWS.S3.Bucket("Bucket"); }),);yield* AWS.S3.Bucket("Bucket") registers the resource with the
Stack under the logical id Bucket and returns a typed Bucket
handle. We didn’t pass a bucketName, so Alchemy generates a unique
physical name from the app, stage, and logical id.
Return Stack outputs
Section titled “Return Stack outputs”Stack outputs let you see important values after a deploy. Return an object from the generator to expose them:
Effect.gen(function* () { const bucket = yield* AWS.S3.Bucket("Bucket");
return { bucketName: bucket.bucketName, };}),bucket.bucketName is an Output — a typed reference to an attribute
the cloud will produce. It resolves during deploy and prints with the
rest of the stack outputs.
Deploy
Section titled “Deploy”Run alchemy deploy to create the Bucket on AWS:
bun alchemy deploynpm run alchemy deploypnpm alchemy deployyarn alchemy deployThe first time you deploy, Alchemy prompts you to pick an AWS
authentication method — SSO (recommended), environment
variables, or stored access keys — and saves the choice to your
default profile. The region and account
come from whichever method you pick. See Setup for a
walkthrough of all three.
Plan: 1 to create + Bucket (AWS.S3.Bucket) Proceed? ◉ Yes ○ No ✓ Bucket (AWS.S3.Bucket) created { bucketName: "myapp-bucket-a1b2c3d4e5", }
Alchemy shows a plan, asks for confirmation, creates the resource, and prints the stack outputs. Your bucket is live on AWS.
Verify it worked
Section titled “Verify it worked”Your newly created bucket will be listed in the S3 section of the AWS
Console (or via aws s3 ls if you have the AWS CLI installed).
Run alchemy deploy again. Because nothing changed, the bucket shows
as a no-op:
Plan: no changes { bucketName: "myapp-bucket-a1b2c3d4e5", }
This is the core loop — declare resources in code, deploy, and Alchemy figures out what changed.
Destroy (optional)
Section titled “Destroy (optional)”The inverse of deploy is destroy — it plans against an empty
desired state and deletes everything the stack created:
bun alchemy destroyTry it if you like, then run bun alchemy deploy again to bring the
bucket back — we’ll build on it in Part 2.
You now have:
- An
alchemy.run.tswith a Stack and an AWS S3 Bucket - A live bucket deployed to your AWS account
- Stack outputs showing the bucket name
In Part 2, you’ll add a Lambda Function with a public URL that reads and writes objects in this bucket.