$npx -y skills add pulumi/agent-skills --skill provider-upgradeUpgrade any Pulumi provider to a newer version and reconcile the resulting diff. Use when users want to upgrade or update a provider (including editing package.json, requirements.txt, pyproject.toml, go.mod, or Pulumi.yaml to bump a provider SDK), check for breaking changes befor
| 1 | # Upgrading Pulumi Providers |
| 2 | |
| 3 | ## The Principle |
| 4 | |
| 5 | A provider upgrade is a translation, not a change request. |
| 6 | |
| 7 | The user's infrastructure intent hasn't changed - they still want the same bucket, the |
| 8 | same function, the same cluster. What changed is how the provider's API expresses that |
| 9 | intent. Your job is to translate their existing code into the new API so that Pulumi sees |
| 10 | no difference between what the code says and what already exists. |
| 11 | |
| 12 | There are four layers to keep in mind: |
| 13 | |
| 14 | 1. **User intent** - what the user wants in the cloud (unchanged during an upgrade) |
| 15 | 2. **Code** - how the program expresses that intent using the provider API (may need updating) |
| 16 | 3. **Pulumi state** - Pulumi's stored representation of what exists (may need reconciliation) |
| 17 | 4. **Real cloud** - the actual infrastructure (should not change during an upgrade) |
| 18 | |
| 19 | During an upgrade, layers 2 and 3 may need to change so that they continue to correctly |
| 20 | represent the unchanged layers 1 and 4. |
| 21 | |
| 22 | A correct translation produces zero diff. The Pulumi engine doesn't have a concept of |
| 23 | "upgrade" - it just compares goal state (your code) against actual state (the state file) |
| 24 | and reconciles. If the translation is correct, those two states match and nothing happens. |
| 25 | If you see a diff, either your translation is wrong, or something beyond a code change is |
| 26 | needed (import, alias, manual step). In all cases, the diff is a problem to solve, not a |
| 27 | consequence to accept. |
| 28 | |
| 29 | ## The Core Loop |
| 30 | |
| 31 | ```mermaid |
| 32 | flowchart TD |
| 33 | A[Bump version] --> B[Run preview with env vars] |
| 34 | B --> C{Clean?} |
| 35 | C -->|Yes| D[Create PR] |
| 36 | C -->|No| E[Diff Checkpoint: categorize every diff] |
| 37 | E --> F{Any Category A?} |
| 38 | F -->|Yes| G[Fix wrong translations] |
| 39 | G --> B |
| 40 | F -->|No| H{Any Category B?} |
| 41 | H -->|Yes| I[Investigate with toolbox] |
| 42 | I --> J[Fix or document] |
| 43 | J --> B |
| 44 | H -->|No| D |
| 45 | ``` |
| 46 | |
| 47 | 1. **Bump** the provider dependency |
| 48 | 2. **Preview** with required CLI flags |
| 49 | 3. **Diff Checkpoint** - categorize every non-`same` resource (see next section) |
| 50 | 4. **Fix Category A** - code changes that didn't produce `same` |
| 51 | 5. **Investigate Category B** - diffs on resources you didn't change |
| 52 | 6. **Repeat** until clean or remaining diffs are fully investigated |
| 53 | 7. **Create PR** with upgrade summary |
| 54 | |
| 55 | --- |
| 56 | |
| 57 | ## The Diff Checkpoint |
| 58 | |
| 59 | This is the most important section. Run this after EVERY preview. |
| 60 | |
| 61 | For each non-`same` resource, answer one question: |
| 62 | **"Did any of my code changes affect this resource - directly or indirectly?"** |
| 63 | |
| 64 | "Directly" means you edited the resource block itself. "Indirectly" means you changed |
| 65 | something that feeds into this resource - a shared variable, an output from another |
| 66 | resource, a helper function, a default value, or a resource that this one depends on. |
| 67 | If your changes could have altered what Pulumi computes for this resource, it's Category A. |
| 68 | |
| 69 | Then follow the category that applies. |
| 70 | |
| 71 | ### Category A: I changed code for this resource |
| 72 | |
| 73 | Your code change was supposed to translate the same intent into the new API. If the |
| 74 | resource shows `same`, your translation is correct. If it shows anything else, your |
| 75 | translation is wrong. Not "the diff is expected because I changed the code" - if the |
| 76 | change were semantically equivalent, there would be no diff. |
| 77 | |
| 78 | **I modified an existing resource and it shows `update`:** |
| 79 | |
| 80 | Your rename, restructure, or value adjustment changed the meaning, not just the syntax. |
| 81 | The resource would show `same` if the old and new code compiled to the same goal state. |
| 82 | The `update` means they don't. |
| 83 | |
| 84 | Ask yourself: *"If this rename were truly equivalent, the resource would show `same`. |
| 85 | It doesn't. What is semantically different between my old code and my new code?"* |
| 86 | |
| 87 | Common causes: the new property name maps to a different underlying field; the value |
| 88 | shape changed and your conversion lost or added information; a default value changed |
| 89 | in the new version and you need to explicitly set the old value; additional properties |
| 90 | now appear in the diff because the new provider version tracks fields it didn't before |
| 91 | (these need to be set explicitly to match the current state). |
| 92 | |
| 93 | If the update includes properties you didn't change - new fields appearing, type |
| 94 | normalizations (string->number), additional defaults - that's |