1---
2title: Setup
3description: Install Alchemy and connect it to Hetzner Cloud — create a project, generate an API token, and store it in a profile.
4---
5
6import { Code, Tabs, TabItem } from "@astrojs/starlight/components";
7import { effectVersion } from "../../../versions";
8
9export const pkgs = `"alchemy@latest" "effect@${effectVersion}" "@effect/platform-bun@${effectVersion}" "@effect/platform-node@${effectVersion}"`;
10
11Everything you need before deploying to Hetzner Cloud: the alchemy
12package, a Hetzner project, and an API token stored in a profile.
13
14## Prerequisites
15
16- [Bun](https://bun.sh) or Node.js 22+
17- A [Hetzner Cloud](https://console.hetzner.com) account
18
19## Create a Hetzner project
20
21Everything in Hetzner Cloud — servers, volumes, networks, tokens —
22lives inside a **project**. In the
23[Hetzner Cloud Console](https://console.hetzner.com):
24
251. Click **+ New project**.
262. Give it a name (e.g. `my-app`) and open it.
27
28One project per app (or per environment) is a good default: API
29tokens are scoped to a single project, so separate projects give you
30hard isolation between apps.
31
32## Generate an API token
33
34Inside the project:
35
361. Go to **Security** → **API tokens**.
372. Click **Generate API token**.
383. Give it a description (e.g. `alchemy`) and select
39 **Read & Write** — Alchemy needs write access to create resources.
404. Copy the token — Hetzner shows it **only once**.
41
42## Create a project directory
43
44<Tabs syncKey="pkgManager">
45 <TabItem label="bun" icon="bun">
46 <Code code="mkdir my-app && cd my-app && bun init -y" lang="sh" />
47 </TabItem>
48 <TabItem label="npm" icon="npm">
49 <Code code="mkdir my-app && cd my-app && npm init -y" lang="sh" />
50 </TabItem>
51 <TabItem label="pnpm" icon="pnpm">
52 <Code code="mkdir my-app && cd my-app && pnpm init" lang="sh" />
53 </TabItem>
54 <TabItem label="yarn" icon="seti:yarn">
55 <Code code="mkdir my-app && cd my-app && yarn init -y" lang="sh" />
56 </TabItem>
57</Tabs>
58
59## Install
60
61<Tabs syncKey="pkgManager">
62 <TabItem label="bun" icon="bun">
63 <Code code={`bun add ${pkgs}`} lang="sh" />
64 </TabItem>
65 <TabItem label="npm" icon="npm">
66 <Code code={`npm install ${pkgs}`} lang="sh" />
67 </TabItem>
68 <TabItem label="pnpm" icon="pnpm">
69 <Code code={`pnpm add ${pkgs}`} lang="sh" />
70 </TabItem>
71 <TabItem label="yarn" icon="seti:yarn">
72 <Code code={`yarn add ${pkgs}`} lang="sh" />
73 </TabItem>
74</Tabs>
75
76## Connect alchemy to Hetzner
77
78There is no separate credentials step. The first time you run
79`alchemy deploy` (or `plan`, `dev`, `destroy`) on a stack that uses
80`Hetzner.providers()`, alchemy prompts for the token you generated
81above (and, optionally, an API endpoint override). It is saved under
82`~/.alchemy/credentials/<profile>/` in the selected
83[profile](/environments/profiles) and reused on subsequent commands.
84
85In CI (`CI=true`) alchemy skips the prompt and reads `HCLOUD_TOKEN`
86(plus an optional `HCLOUD_ENDPOINT`) from the environment instead.
87
88To re-run the setup later (e.g. to rotate the token, or configure a
89separate `prod` profile):
90
91```sh
92# Re-run the interactive setup (e.g. to rotate the token)
93alchemy profile edit --reconfigure Hetzner
94
95# Or connect Hetzner in a separate `prod` profile
96alchemy profile create prod
97alchemy profile edit --profile prod --add Hetzner
98
99# Non-interactive (scripts, agents)
100alchemy profile edit --add Hetzner --method stored --set token=env:HCLOUD_TOKEN
101```
102
103Inspect what's stored (secrets are redacted):
104
105```sh
106alchemy profile show
107```
108
109:::note[No SSH key setup required]
110`Hetzner.Service` deploys your code to a Server over SSH, but you
111don't need to create or upload an SSH key for that — alchemy
112generates a dedicated deploy key for each Server it creates and
113injects it at boot. Adding your own `Hetzner.SshKey` is only for
114*your* interactive `ssh` access.
115:::
116
117## State storage
118
119Hetzner has no object-storage state backend of its own, so pick one
120of:
121
122- **`Alchemy.localState()`** — state on disk under `.alchemy/` next
123 to your code. Zero setup; right for solo projects and trying
124 things out.
125- **A cloud state store** — if you also use Cloudflare or AWS, pass
126 `Cloudflare.state()` or `AWS.state()` so state is shared with
127 your team and CI. See [State Store](/state-store).
128
129State for a Hetzner stack includes each Server's deploy SSH key
130(stored redacted), so for shared or production stacks prefer a
131remote state store over files on one laptop.
132
133## Next steps
134
135- [Tutorial part 1](/hetzner/tutorial/part-1) — deploy your first
136 Server.
137- [Hetzner overview](/hetzner) — the map of resources and guides.