| 1 | --- |
| 2 | title: Adopting Resources |
| 3 | description: How alchemy takes ownership of pre-existing cloud resources — recovery by default, --adopt for foreign resources, and the programmatic AdoptPolicy. |
| 4 | --- |
| 5 | |
| 6 | Two situations put alchemy in front of a cloud resource it has no state for: existing infrastructure you want alchemy to start managing, and a fresh (or wiped) state store sitting in front of resources alchemy already created. |
| 7 | |
| 8 | ```sh |
| 9 | bun alchemy deploy --adopt |
| 10 | ``` |
| 11 | |
| 12 | ## How the engine decides |
| 13 | |
| 14 | When a resource has no prior state, the engine calls the provider's |
| 15 | `read` to check whether the resource already exists in the cloud. The |
| 16 | return value drives one of three paths: |
| 17 | |
| 18 | | `read` returns | Without `--adopt` | With `--adopt` | |
| 19 | | ------------------- | ------------------------- | --------------------- | |
| 20 | | `undefined` | create | create | |
| 21 | | owned (plain attrs) | silent adopt | silent adopt | |
| 22 | | `Unowned(attrs)` | fail `OwnedBySomeoneElse` | take over (silently) | |
| 23 | |
| 24 | "Owned" means the provider can prove the resource was created by *this* stack/stage/logical-id — typically by inspecting tags or a naming convention. |
| 25 | |
| 26 | The same table drives the provider-side contract: see [Adoption in Resource Lifecycle](/infrastructure-as-code/resource-lifecycle#adoption) for the engine's routing and [the `read` operation](/infrastructure-as-code/provider#read) for how a provider returns `Unowned(attrs)`. |
| 27 | |
| 28 | ## Recovery is the default |
| 29 | |
| 30 | Re-importing owned resources into a fresh state store needs **no** flag — recovering a wiped state store for resources you already own is the default behavior. |
| 31 | |
| 32 | `--adopt` only matters when the provider reports a resource exists but isn't ours. That's the deliberately load-bearing case: by default alchemy refuses to silently overwrite tags/config of a resource it can't prove ownership of. `--adopt` says "yes, take it over." |
| 33 | |
| 34 | ```sh |
| 35 | # Re-import existing alchemy-tagged resources into a fresh state |
| 36 | # store — no flag needed for these. Ones with foreign ownership tags |
| 37 | # will surface as `OwnedBySomeoneElse` errors. |
| 38 | alchemy deploy |
| 39 | |
| 40 | # Preview the takeover without applying it. |
| 41 | alchemy plan --adopt |
| 42 | |
| 43 | # Force takeover of any conflicting resource regardless of tags. |
| 44 | alchemy deploy --adopt |
| 45 | ``` |
| 46 | |
| 47 | ## The `--adopt` flag |
| 48 | |
| 49 | `--adopt` opts the *entire* deploy in to adoption-on-conflict — it is provided as a single `AdoptPolicy` layer over the whole stack execution, not per resource. |
| 50 | |
| 51 | The default is `false` so an unintentional collision still surfaces loudly instead of silently overwriting someone else's resource. The option is part of the shared `ExecStackOptions` that every stack-executing command (including `dev`) runs through. |
| 52 | |
| 53 | ## When adoption is refused: `OwnedBySomeoneElse` |
| 54 | |
| 55 | When `read` reports an existing resource as `Unowned` and adoption is off, the deploy fails with the typed `OwnedBySomeoneElse` error, carrying `message`, `resourceType`, `logicalId`, and `physicalName`. |
| 56 | |
| 57 | You have three ways out: re-tag the cloud resource so the provider recognizes it as yours, pick a different physical name so there is no collision, or re-run with `--adopt` (or `adopt(true)`) to force a takeover. |
| 58 | |
| 59 | ## Programmatic adoption |
| 60 | |
| 61 | You can also enable adoption programmatically by piping the `adopt` combinator onto a deploy effect from `alchemy/AdoptPolicy`: |
| 62 | |
| 63 | ```typescript |
| 64 | import { adopt } from "alchemy/AdoptPolicy"; |
| 65 | |
| 66 | yield* deploy( |
| 67 | Effect.gen(function* () { |
| 68 | yield* Cloudflare.Worker("API", { /* ... */ }); |
| 69 | }), |
| 70 | ).pipe(adopt(true)); |
| 71 | ``` |
| 72 | |
| 73 | `AdoptPolicy` is consulted at plan time, so the combinator must wrap the *deploy* (or test runner's `stack.deploy(...)`) — not the inner resource-declaration effect. |
| 74 | |
| 75 | `adopt()` with no argument means `true`, and it also accepts an `Effect<boolean>` for dynamic policies: |
| 76 | |
| 77 | ```typescript |
| 78 | deployEffect.pipe(adopt()); // same as adopt(true) |
| 79 | deployEffect.pipe(adopt(decidePolicy)); // Effect<boolean>, resolved at plan time |
| 80 | ``` |
| 81 | |
| 82 | ## Resources without ownership semantics |
| 83 | |
| 84 | Providers with no tag concept (e.g. APIs that always return a singleton by name) always return plain attrs from `read`, so they silently adopt unconditionally — `--adopt` is a no-op for them. |
| 85 | |
| 86 | For the full lost-state-store recovery walkthrough (state explorer → state delete → deploy), see [Inspecting State](/cli/inspecting-state). |
| 87 | |
| 88 | ## Where next |
| 89 | |
| 90 | - [deploy](/cli/deploy) — the command that carries `--adopt` |
| 91 | - [Inspecting State](/cli/inspecting-state) — recover a lost or wiped state store |
| 92 | - [Resource Lifecycle](/infrastructure-as-code/resource-lifecycle) — where adoption sits in the engine |
| 93 | - [Providers](/infrastructure-as-code/provider) — implementing `read` and `Unowned` |