1---
2title: "Part 1: Your First Stack"
3description: Install Alchemy, create a Stack with an AWS S3 Bucket, and deploy it.
4sidebar:
5 order: 1
6---
7
8import Terminal from "../../../../components/Terminal.astro";
9import { Code, Tabs, TabItem } from "@astrojs/starlight/components";
10import { effectVersion } from "../../../../versions";
11
12export const pkgs = `"alchemy@latest" "effect@${effectVersion}" "@effect/platform-bun@${effectVersion}" "@effect/platform-node@${effectVersion}"`;
13
14In this first part you'll install Alchemy and Effect, create a Stack
15with an AWS S3 Bucket, and deploy it — all in under five minutes.
16
17## Prerequisites
18
19- [Bun](https://bun.sh) or Node.js 22+
20- An AWS account and an IAM identity with permission to create the
21 resources you plan to deploy
22
23## Create a project
24
25Start with an empty directory and initialize a `package.json`:
26
27<Tabs syncKey="pkgManager">
28 <TabItem label="bun" icon="bun">
29 <Code code="mkdir my-app && cd my-app && bun init -y" lang="sh" />
30 </TabItem>
31 <TabItem label="npm" icon="npm">
32 <Code code="mkdir my-app && cd my-app && npm init -y" lang="sh" />
33 </TabItem>
34 <TabItem label="pnpm" icon="pnpm">
35 <Code code="mkdir my-app && cd my-app && pnpm init" lang="sh" />
36 </TabItem>
37 <TabItem label="yarn" icon="seti:yarn">
38 <Code code="mkdir my-app && cd my-app && yarn init -y" lang="sh" />
39 </TabItem>
40</Tabs>
41
42## Install dependencies
43
44Install <code>alchemy@latest</code> and <code>effect@{effectVersion}</code>:
45
46<Tabs syncKey="pkgManager">
47 <TabItem label="bun" icon="bun">
48 <Code code={`bun add ${pkgs}`} lang="sh" />
49 </TabItem>
50 <TabItem label="npm" icon="npm">
51 <Code code={`npm install ${pkgs}`} lang="sh" />
52 </TabItem>
53 <TabItem label="pnpm" icon="pnpm">
54 <Code code={`pnpm add ${pkgs}`} lang="sh" />
55 </TabItem>
56 <TabItem label="yarn" icon="seti:yarn">
57 <Code code={`yarn add ${pkgs}`} lang="sh" />
58 </TabItem>
59</Tabs>
60
61## Create the Stack
62
63Every Alchemy program starts with a `Stack` — a collection of
64Resources managed by Providers with state tracked between deploys.
65
66Create an `alchemy.run.ts` file:
67
68```typescript
69// alchemy.run.ts
70import * as Alchemy from "alchemy";
71import * as AWS from "alchemy/AWS";
72import * as Effect from "effect/Effect";
73
74export default Alchemy.Stack(
75 "MyApp",
76 {
77 providers: AWS.providers(),
78 state: AWS.state(),
79 },
80 Effect.gen(function* () {
81 // we'll add resources here next
82 }),
83);
84```
85
86`Alchemy.Stack` is the root of every app. The first argument
87(`"MyApp"`) doubles as a logical id and as the prefix Alchemy uses
88when AWS asks for physical resource names.
89
90## How credentials resolve
91
92`providers: AWS.providers()` registers every AWS resource and IAM
93policy binding that ships with Alchemy, and resolves credentials from
94your Alchemy [profile](/environments/profiles). Connect SSO or stored access
95keys with `alchemy profile edit --add AWS`. See
96[Setup](/aws/setup) for the details of each method.
97
98## Where state lives
99
100`state: AWS.state()` stores deploy state in an account-regional S3
101bucket (`alchemy-state-{accountId}-{region}-an`), created lazily on
102the first deploy. Because the state lives in your AWS account rather
103than on disk, the same configuration works locally and in CI with no
104extra setup.
105
106:::note[Other state stores]
107For purely local iteration you can use `Alchemy.localState()`
108instead, which writes state under `.alchemy/` next to your code — or
109[write your own](/state-store).
110:::
111
112## Add a Resource
113
114Resources represent cloud infrastructure — buckets, tables, queues,
115functions, and so on. Each resource is `yield*`-ed inside the Stack's
116Effect generator.
117
118Add an S3 Bucket:
119
120```diff lang="typescript"
121// alchemy.run.ts
122import * as Alchemy from "alchemy";
123import * as AWS from "alchemy/AWS";
124import * as Effect from "effect/Effect";
125
126export default Alchemy.Stack(
127 "MyApp",
128 {
129 providers: AWS.providers(),
130 state: AWS.state(),
131 },
132 Effect.gen(function* () {
133+ const bucket = yield* AWS.S3.Bucket("Bucket");
134 }),
135);
136```
137
138`yield* AWS.S3.Bucket("Bucket")` registers the resource with the
139Stack under the logical id `Bucket` and returns a typed `Bucket`
140handle. We didn't pass a `bucketName`, so Alchemy generates a unique
141physical name from the app, stage, and logical id.
142
143## Return Stack outputs
144
145Stack outputs let you see important values after a deploy. Return an
146object from the generator to expose them:
147
148```diff lang="typescript"
149 Effect.gen(function* () {
150 const bucket = yield* AWS.S3.Bucket("Bucket");
151+
152+ return {
153+ bucketName: bucket.bucketName,
154+ };
155 }),
156```
157
158`bucket.bucketName` is an Output — a typed reference to an attribute
159the cloud will produce. It resolves during deploy and prints with the
160rest of the stack outputs.
161
162## Deploy
163
164Run `alchemy deploy` to create the Bucket on AWS:
165
166<Tabs syncKey="pkgManager">
167 <TabItem label="bun" icon="bun">
168 <Code code="bun alchemy deploy" lang="sh" />
169 </TabItem>
170 <TabItem label="npm" icon="npm">
171 <Code code="npm run alchemy deploy" lang="sh" />
172 </TabItem>
173 <TabItem label="pnpm" icon="pnpm">
174 <Code code="pnpm alchemy deploy" lang="sh" />
175 </TabItem>
176 <TabItem label="yarn" icon="seti:yarn">
177 <Code code="yarn alchemy deploy" lang="sh" />
178 </TabItem>
179</Tabs>
180
181Connect AWS first with `alchemy profile edit --add AWS` and pick a
182local authentication method: **SSO** (recommended) or **stored access
183keys**. The choice is saved to your **`default`**
184[profile](/environments/profiles); the region and account come from
185whichever method you pick, and a deploy with nothing configured fails
186with that exact command to run. CI instead reads AWS environment
187credentials directly. See [Setup](/aws/setup) for the full walkthrough.
188
189:::tip
190To re-run the credential prompt later (e.g. to switch from stored
191keys to SSO), use `alchemy profile edit --reconfigure AWS`. For a
192separate profile, run `alchemy profile create prod` followed by
193`alchemy profile edit --profile prod`.
194:::
195
196<Terminal content={`[u]Plan[/u]: [g]1 to create[/g]
197[g]+[/g] [b]Bucket[/b] [d](AWS.S3.Bucket)[/d]
198
199Proceed?
200◉ Yes ○ No
201[g]✓[/g] [b]Bucket[/b] [d](AWS.S3.Bucket)[/d] [g]created[/g]
202{
203[s2]bucketName: "myapp-bucket-a1b2c3d4e5",
204}`} />
205
206Alchemy shows a plan, asks for confirmation, creates the resource,
207and prints the stack outputs. Your bucket is live on AWS.
208
209:::tip
210By convention, Alchemy looks for `alchemy.run.ts` at the root of your
211project. You can specify a different file with
212`alchemy deploy --config <file>`.
213:::
214
215## Verify it worked
216
217Your newly created bucket will be listed in the S3 section of the AWS
218Console (or via `aws s3 ls` if you have the AWS CLI installed).
219
220Run `alchemy deploy` again. Because nothing changed, the bucket shows
221as a no-op:
222
223<Terminal content={`[u]Plan[/u]: [d]no changes[/d]
224
225{
226[s2]bucketName: "myapp-bucket-a1b2c3d4e5",
227}`} />
228
229This is the core loop — declare resources in code, deploy, and
230Alchemy figures out what changed.
231
232## Destroy (optional)
233
234The inverse of `deploy` is `destroy` — it plans against an empty
235desired state and deletes everything the stack created:
236
237```sh
238bun alchemy destroy
239```
240
241Try it if you like, then run `bun alchemy deploy` again to bring the
242bucket back — we'll build on it in Part 2.
243
244## Recap
245
246You now have:
247
248- An `alchemy.run.ts` with a Stack and an AWS S3 Bucket
249- A live bucket deployed to your AWS account
250- Stack outputs showing the bucket name
251
252In [Part 2](/aws/tutorial/part-2), you'll add a Lambda Function with
253a public URL that reads and writes objects in this bucket.