# Apply modes
Source: https://docs.formae.io/documentation/concepts/apply-modes
What reconcile and patch modes each let formae do, and what they refuse to do.
Every `formae apply` requires a mode. The mode determines what formae is allowed to do, and more importantly, what it won't do.
## Reconcile
```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
formae apply --mode reconcile main.pkl
```
Reconcile is the [GitOps](/documentation/concepts/ways-to-work) mode: your codebase declares the desired state of your infrastructure, and reconcile makes reality match it. Resources in your forma are created or updated, and resources that exist in the cloud but **not** in your forma are destroyed. After a reconcile, your infrastructure is exactly what your code says it should be.
This is the everyday mode whenever your code is the source of truth and you want your infrastructure brought back in line with it, from a first deployment to routine changes.
## Patch
```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
formae apply --mode patch change.pkl
```
Patch is **append-only**. It only creates or updates the resources named in your forma, and never destroys anything. Resources you don't mention are left untouched, and within a resource, collection properties (tags, security groups, and the like) are only added to, never trimmed. Reconcile can destroy; patch cannot.
Patch exists for two situations:
* **Working without a declared codebase.** When you don't have code that describes the desired state of your infrastructure, or don't have it to hand, you work by extract-and-patch: extract the resource or two you want to change, edit them, and apply them back with patch.
* **Emergency fixes.** When you're firefighting an incident and want the smallest possible blast radius, patch one or two resources to resolve it rather than reconciling a whole stack.
### A patch is an out-of-band change
A patch changes your infrastructure without going through a full reconcile, so formae treats it exactly like a change made outside formae, the same way it treats an [out-of-band change](/documentation/concepts/synchronization) that sync pulls in. After a patch, your codebase no longer describes reality.
The next [soft reconcile](#hard-vs-soft-reconcile) on that stack detects the drift the patch introduced and **fails**, forcing you to deal with it: absorb the change back into your code, or undo it. This is deliberate. A 2am patch fixes the incident now; the drift it created surfaces the next morning, so someone reconciles the code back to reality instead of silently losing the change.
## Collection handling
When a resource has a collection property (tags, security groups, or any list of values), the apply mode determines how that collection is updated.
**Reconcile mode** treats your forma as the complete truth: the collection after apply matches exactly what you specified, and elements not in your forma are removed.
**Patch mode** is append-only: elements in your forma are guaranteed to exist after apply, but existing elements are never removed.
**Example:** a resource has tags `[A, B, C]` and your forma specifies `[B, D]`.
| Mode | Result | What happened |
| --------- | -------------- | ------------------------------- |
| Reconcile | `[B, D]` | Tags A and C are removed |
| Patch | `[A, B, C, D]` | Tag D is added, nothing removed |
This makes patch mode safer for shared resources where multiple teams manage different parts of the same collection.
## Hard vs soft reconcile
When someone changes a resource outside of formae (through the cloud console, another tool, or a script), that's an out-of-band change. Reconcile mode handles them in two ways.
### Soft reconcile (default)
If formae detects out-of-band changes, it rejects the apply to protect you:
```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
formae apply --mode reconcile main.pkl
# Fails: external changes detected
```
This gives you a chance to review what changed: extract the current state, compare it with your code, and decide what to keep.
### Hard reconcile
If you've reviewed the changes and want to overwrite them, add `--force`:
```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
formae apply --mode reconcile --force main.pkl
```
Hard reconcile overwrites all out-of-band changes and brings the infrastructure exactly in line with your forma. Use it when your code is the authority and external changes should be discarded.
unmanaged stack: legacy-igw-inline, legacy-igw-standalone, igw-0a1b2c3d4e5f6a7b8, igw-0f9e8d7c6b5a4f3e2, webapp-1558-igw-1, and webapp-abc1-igw. Want me to bring them under management?imported-networking stack and simulate first. The simulation creates the stack and moves 6 resources from unmanaged to imported-networking, putting them under management with nothing recreated. Apply it?imported-networking, and nothing was recreated.prod-us-west-2 for AWS us-west-2 and simulate first: it creates one target, discoverable, and no cloud resources. Because it's discoverable, formae will then scan us-west-2 for existing resources. Apply it?prod-us-west-2 is registered and discoverable, and discovery is scanning it now. Once it finishes I can show you what's there to bring under management.lifeline stack changed outside formae: the internet gateway lifeline-igw was updated. Something added a tag to it in the console. Do you want to absorb that change into your forma, or discard it?Owner = platform-team tag to the gateway definition in network\_resources.pkl. Reconciling now reports no changes, so your forma and the running stack agree again and the tag is under management. Want me to commit the change?spec.replicas on the chat-ui deployment in vllm-chat from 1 to 2, with nothing else affected. Apply it?chat-ui is now running 2 replicas.prod-us-east-1, prod-eu-west-1, and prod-us-east-2.unmanaged stack: legacy-igw-inline, legacy-igw-standalone, igw-0a1b2c3d4e5f6a7b8, igw-0f9e8d7c6b5a4f3e2, webapp-1558-igw-1, and webapp-abc1-igw. Nothing has been changed. Want to bring any under management?incident-logs in production, and changes nothing else. Apply it?incident-logs is live in production, and the rest of the stack is untouched. This is drift now, so fold it into your forma once the incident is over.incident-logs from the production stack and added it to your forma. Reconciling now shows no changes for it, so your code and the live stack agree again. Want me to reconcile to confirm?incident-logs is now part of your committed infrastructure, not drift.production removes incident-logs, the one resource not in your code, and leaves everything else as is. This discards the patch. Go ahead?incident-logs is gone and production matches your code exactly.ttl policy, ephemeral-24h (24 hours, onDependents = abort), then attaches it to dev-sandbox-1 and dev-sandbox-2. Each stack is destroyed 24 hours after the policy attaches, and editing the one policy updates both. Apply it?ephemeral-24h now covers both sandboxes. Attach it to another stack any time by pointing that stack at the same policy.artifacts-bucket-cdk to lambda-artifacts on the S3 bucket in web-backend, with no change to the bucket itself. Apply it?lambda-artifacts, and the bucket itself was untouched.