| 1 | --- |
| 2 | title: Setup |
| 3 | description: Create a Fly org, generate an API token, and store it in a profile. |
| 4 | --- |
| 5 | |
| 6 | import { Code, Tabs, TabItem } from "@astrojs/starlight/components"; |
| 7 | import { effectVersion } from "../../../versions"; |
| 8 | |
| 9 | export const pkgs = `"alchemy@latest" "effect@${effectVersion}" "@effect/platform-bun@${effectVersion}" "@effect/platform-node@${effectVersion}"`; |
| 10 | |
| 11 | Everything you need before deploying to Fly.io: the alchemy package, |
| 12 | a Fly organization, and an API token stored in a profile. |
| 13 | |
| 14 | ## Prerequisites |
| 15 | |
| 16 | - [Bun](https://bun.sh) or Node.js 22+ |
| 17 | - A [Fly.io](https://fly.io) account |
| 18 | - [Docker](https://docs.docker.com/get-docker/) for |
| 19 | [Services](/fly/compute/services) (Alchemy builds and pushes an |
| 20 | image). Raw [Machines](/fly/compute/machines) with a public image |
| 21 | do not need it. Neither do |
| 22 | [Sprites](/fly/compute/sprites). |
| 23 | |
| 24 | ## Create a Fly organization |
| 25 | |
| 26 | Sign in at [fly.io/dashboard](https://fly.io/dashboard). A personal |
| 27 | org is created with the account. Tokens are scoped to an org — the |
| 28 | org slug is where Services create their Apps, and what `Fly.App` |
| 29 | uses when you omit `orgSlug` (Alchemy reads it from the current |
| 30 | token). |
| 31 | |
| 32 | ## Generate an API token |
| 33 | |
| 34 | In the dashboard: |
| 35 | |
| 36 | 1. Open **Account** → **Access Tokens** (or run `fly tokens create org` |
| 37 | if you have [flyctl](https://fly.io/docs/flyctl/install/)). |
| 38 | 2. Create an **organization** token with permission to manage Apps |
| 39 | and Machines. |
| 40 | 3. Copy the token — Fly shows it **only once**. |
| 41 | |
| 42 | The official environment variable is `FLY_API_TOKEN`. That token is |
| 43 | enough for Apps, Machines, Services, Sprites, Postgres, Redis, and |
| 44 | Tigris. Alchemy mints a Sprites bearer from it when you deploy a |
| 45 | Sprite. |
| 46 | |
| 47 | ## Create a project directory |
| 48 | |
| 49 | <Tabs syncKey="pkgManager"> |
| 50 | <TabItem label="bun" icon="bun"> |
| 51 | <Code code="mkdir my-app && cd my-app && bun init -y" lang="sh" /> |
| 52 | </TabItem> |
| 53 | <TabItem label="npm" icon="npm"> |
| 54 | <Code code="mkdir my-app && cd my-app && npm init -y" lang="sh" /> |
| 55 | </TabItem> |
| 56 | <TabItem label="pnpm" icon="pnpm"> |
| 57 | <Code code="mkdir my-app && cd my-app && pnpm init" lang="sh" /> |
| 58 | </TabItem> |
| 59 | <TabItem label="yarn" icon="seti:yarn"> |
| 60 | <Code code="mkdir my-app && cd my-app && yarn init -y" lang="sh" /> |
| 61 | </TabItem> |
| 62 | </Tabs> |
| 63 | |
| 64 | ## Install |
| 65 | |
| 66 | <Tabs syncKey="pkgManager"> |
| 67 | <TabItem label="bun" icon="bun"> |
| 68 | <Code code={`bun add ${pkgs}`} lang="sh" /> |
| 69 | </TabItem> |
| 70 | <TabItem label="npm" icon="npm"> |
| 71 | <Code code={`npm install ${pkgs}`} lang="sh" /> |
| 72 | </TabItem> |
| 73 | <TabItem label="pnpm" icon="pnpm"> |
| 74 | <Code code={`pnpm add ${pkgs}`} lang="sh" /> |
| 75 | </TabItem> |
| 76 | <TabItem label="yarn" icon="seti:yarn"> |
| 77 | <Code code={`yarn add ${pkgs}`} lang="sh" /> |
| 78 | </TabItem> |
| 79 | </Tabs> |
| 80 | |
| 81 | ## Connect alchemy to Fly |
| 82 | |
| 83 | There is no separate credentials step. The first time you run |
| 84 | `alchemy deploy` (or `plan`, `dev`, `destroy`) on a stack that uses |
| 85 | `Fly.providers()`, alchemy prompts for the token you generated above |
| 86 | (and, optionally, a Machines API hostname — default |
| 87 | `https://api.machines.dev/v1`). It is saved under |
| 88 | `~/.alchemy/credentials/<profile>/` in your **`default`** |
| 89 | [profile](/environments/profiles) and reused on every subsequent |
| 90 | command. |
| 91 | |
| 92 | In CI (`CI=true`) alchemy skips the prompt and reads `FLY_API_TOKEN` |
| 93 | (plus an optional `FLY_API_HOSTNAME`) from the environment instead. |
| 94 | |
| 95 | To re-run the setup later (e.g. to rotate the token, or configure a |
| 96 | separate `prod` profile): |
| 97 | |
| 98 | ```sh |
| 99 | # Re-run the interactive setup (e.g. to rotate the token) |
| 100 | alchemy profile edit --reconfigure Fly |
| 101 | |
| 102 | # Or connect Fly in a separate `prod` profile |
| 103 | alchemy profile create prod |
| 104 | alchemy profile edit --profile prod --add Fly |
| 105 | |
| 106 | # Non-interactive (scripts, agents) |
| 107 | alchemy profile edit --add Fly --method stored --set apiKey=env:FLY_API_TOKEN |
| 108 | ``` |
| 109 | |
| 110 | Inspect what's stored (secrets are redacted): |
| 111 | |
| 112 | ```sh |
| 113 | alchemy profile show |
| 114 | ``` |
| 115 | |
| 116 | :::note[Docker is required for Services] |
| 117 | [`Fly.Service`](/fly/compute/services) bundles your Effect program, |
| 118 | builds a `linux/amd64` image, and pushes it to `registry.fly.io`. |
| 119 | Have [Docker](https://docs.docker.com/get-docker/) running on the |
| 120 | machine that runs `alchemy deploy`. Raw |
| 121 | [`Fly.Machine`](/fly/compute/machines)s that use a public image |
| 122 | (`nginx:alpine`) do not need it. Neither do |
| 123 | [`Fly.Sprite`](/fly/compute/sprites)s — Alchemy writes the bundle |
| 124 | onto the Sprite. |
| 125 | ::: |
| 126 | |
| 127 | ## State storage |
| 128 | |
| 129 | Fly has no object-storage state backend of its own, so pick one of: |
| 130 | |
| 131 | - **`Alchemy.localState()`** — state on disk under `.alchemy/` next |
| 132 | to your code. Zero setup; right for solo projects and trying |
| 133 | things out. |
| 134 | - **A cloud state store** — if you also use Cloudflare or AWS, pass |
| 135 | `Cloudflare.state()` or `AWS.state()` so state is shared with |
| 136 | your team and CI. See [State Store](/state-store). |
| 137 | |
| 138 | ## Next steps |
| 139 | |
| 140 | - [Tutorial part 1](/fly/tutorial/part-1) — deploy your first Service. |
| 141 | - [Sprites](/fly/compute/sprites) — an Effect program that |
| 142 | hibernates. No Docker. |
| 143 | - [Fly overview](/fly) — the map of resources and guides. |