ci(renovate): let the Expo SDK lead, and the family follow via expo install --fix #16

Merged
ullrich merged 1 commit from ci/renovate-expo-sdk into main 2026-07-26 17:40:52 +00:00
Owner

Renovate's first dashboard (#12) proposed ~16 individual Expo bumpsexpo, 18 expo-* packages, and @expo/metro-runtime to v57. Every one is unmergeable on its own: the SDK pins the whole native family through bundledNativeModules.json, and CI never compiles native code, so nothing catches the breakage. That is exactly how the expo-modules-core macro mismatch got in in June 2026.

The community consensus is that Renovate and Expo genuinely fight — Expo wraps npm with expo install, and the family has to move together. So rather than fight it, this models the real workflow: expo leads, everything else follows via --fix.

Changes

The SDK-managed family is disabled for individual updates: /^expo-/, @expo/metro-runtime, /^react-native/, @sentry/react-native, jest-expo.

@expo/metro-runtime is new to this list — it was being proposed to v57 while the SDK is on 56, and the old Dependabot config never covered it either.

expo itself stays enabled, with a postUpgradeTask running pnpm --filter @trails-cool/mobile exec expo install --fix. That rewrites the whole family to the versions the new SDK pins, so a bump and its fallout land as one coherent PR instead of sixteen. Added to the global allowedCommands (anchored), since postUpgradeTasks silently no-op without it.

Expo majors get dependencyDashboardApproval. An SDK major is a project — upgrade guide, native rebuild, EAS credits — so it should open only when deliberately ticked, not appear unbidden on a Monday.

react remains deliberately excluded from the disable list: the web apps own its version through the workspace catalog.

Caveat, recorded in the config itself

A green PR here proves the JS side only. CI does not compile native code, so an SDK bump still needs an EAS build before merge — which lines up with the existing policy of only spending EAS credits when native deps actually change.

Validated with renovate-config-validator: Config validated successfully.

Renovate's first dashboard (#12) proposed **~16 individual Expo bumps** — `expo`, 18 `expo-*` packages, and `@expo/metro-runtime` to v57. Every one is unmergeable on its own: the SDK pins the whole native family through `bundledNativeModules.json`, and CI never compiles native code, so nothing catches the breakage. That is exactly how the `expo-modules-core` macro mismatch got in in June 2026. The community consensus is that [Renovate and Expo genuinely fight](https://github.com/renovatebot/renovate/discussions/24735) — Expo wraps npm with `expo install`, and the family has to move together. So rather than fight it, this models the real workflow: **expo leads, everything else follows via `--fix`**. ## Changes **The SDK-managed family is disabled for individual updates:** `/^expo-/`, `@expo/metro-runtime`, `/^react-native/`, `@sentry/react-native`, `jest-expo`. `@expo/metro-runtime` is new to this list — it was being proposed to **v57 while the SDK is on 56**, and the old Dependabot config never covered it either. **`expo` itself stays enabled**, with a postUpgradeTask running `pnpm --filter @trails-cool/mobile exec expo install --fix`. That rewrites the whole family to the versions the new SDK pins, so a bump and its fallout land as **one coherent PR** instead of sixteen. Added to the global `allowedCommands` (anchored), since postUpgradeTasks silently no-op without it. **Expo majors get `dependencyDashboardApproval`.** An SDK major is a project — upgrade guide, native rebuild, EAS credits — so it should open only when deliberately ticked, not appear unbidden on a Monday. `react` remains deliberately excluded from the disable list: the web apps own its version through the workspace catalog. ## Caveat, recorded in the config itself A green PR here proves **the JS side only**. CI does not compile native code, so an SDK bump still needs an EAS build before merge — which lines up with the existing policy of only spending EAS credits when native deps actually change. Validated with `renovate-config-validator`: *Config validated successfully*.
ci(renovate): let the Expo SDK lead, and the family follow via expo install --fix
All checks were successful
CI / Security Scan (pull_request) Successful in 42s
CI / Dockerfile Package Check (pull_request) Successful in 14s
CI / Checks (pull_request) Successful in 4m17s
CI / Visual Tests (pull_request) Successful in 2m11s
CI / Journal Image Smoke Test (pull_request) Successful in 3m10s
CI / E2E Tests (pull_request) Successful in 9m12s
e1da9e7536
Renovate's first dashboard proposed ~16 individual Expo bumps (expo, 18
expo-*, @expo/metro-runtime to v57). Every one of those is unmergeable on its
own: the SDK pins the whole native family via bundledNativeModules.json, and CI
never compiles native code, so nothing catches the breakage — that is how the
expo-modules-core macro mismatch got in in June 2026.

The community consensus is that Renovate and Expo genuinely fight, because Expo
wraps npm with `expo install` and the family must move together. So model the
real workflow instead of fighting it: expo leads, everything else follows.

- The whole SDK-managed family is disabled for individual updates:
  /^expo-/, @expo/metro-runtime, /^react-native/, @sentry/react-native,
  jest-expo. @expo/metro-runtime is new to this list and was being proposed to
  v57 while the SDK is on 56.
- `expo` itself stays enabled, with a postUpgradeTask running
  `expo install --fix` so the SDK bump and its fallout land as ONE coherent PR
  rather than sixteen. Added to the global allowedCommands, anchored.
- Expo majors get dependencyDashboardApproval: an SDK major is a project
  (upgrade guide, native rebuild, EAS credits), so it should open only when
  deliberately ticked rather than appearing unbidden.

`react` is still deliberately excluded from the disable list — the web apps own
its version through the workspace catalog.

Caveat recorded in the config: a green PR here proves the JS side only. An SDK
bump still needs an EAS build before merge.

Validated with renovate-config-validator.
ullrich deleted branch ci/renovate-expo-sdk 2026-07-26 17:40:53 +00:00
Author
Owner

Extended to the whole @expo/ scope after a good question — naming @expo/metro-runtime individually missed the rest of it.

The authoritative source is expo/bundledNativeModules.json in the installed SDK. For SDK 56 it pins 121 packages, four of them under @expo/:

Package SDK 56 pins Repo declares
@expo/fingerprint ~0.19.4 ^0.20.3 ← already off-pin
@expo/metro-runtime ~56.0.15 ^56.0.15
@expo/ui ~56.0.18 not used
@expo/vector-icons ^15.0.2 not used

The rule now matches /^@expo\// so a newly-added @expo/* is covered by default instead of drifting until someone notices — which is exactly what happened with fingerprint.

A decision for you: @expo/fingerprint

It is SDK-managed and already ahead of its pin, and Renovate had it queued in the development group, which would have pushed it further still.

How it got there: commit 3da7b8d"Fix lockfile sync: add @expo/fingerprint to root devDependencies" — and nothing in the codebase imports it. It is a phantom direct dependency added to satisfy lockfile resolution, which is why its version was never aligned to the SDK.

I have deliberately not touched it, because there are three defensible answers and the choice is yours:

  1. Align to ~0.19.4 — matches the SDK and keeps expo-doctor quiet, but may reintroduce whatever lockfile-sync problem 3da7b8d was fixing.
  2. Remove it entirely — if the original sync issue no longer reproduces, this is cleanest. Testable: drop the line and run pnpm install --frozen-lockfile.
  3. Leave it — nothing imports it, so it is inert; this PR at least stops Renovate pushing it further off-pin.

My inclination is (2) then (1) as fallback, but it wants verifying rather than guessing. Happy to test it if you want.

Extended to the whole `@expo/` scope after a good question — naming `@expo/metro-runtime` individually missed the rest of it. The authoritative source is `expo/bundledNativeModules.json` in the installed SDK. For SDK 56 it pins **121 packages**, four of them under `@expo/`: | Package | SDK 56 pins | Repo declares | |---|---|---| | `@expo/fingerprint` | `~0.19.4` | **`^0.20.3`** ← already off-pin | | `@expo/metro-runtime` | `~56.0.15` | `^56.0.15` ✓ | | `@expo/ui` | `~56.0.18` | not used | | `@expo/vector-icons` | `^15.0.2` | not used | The rule now matches `/^@expo\//` so a newly-added `@expo/*` is covered by default instead of drifting until someone notices — which is exactly what happened with fingerprint. ## A decision for you: `@expo/fingerprint` It is **SDK-managed and already ahead of its pin**, and Renovate had it queued in the `development` group, which would have pushed it further still. How it got there: commit `3da7b8d` — *"Fix lockfile sync: add @expo/fingerprint to root devDependencies"* — and **nothing in the codebase imports it**. It is a phantom direct dependency added to satisfy lockfile resolution, which is why its version was never aligned to the SDK. I have deliberately not touched it, because there are three defensible answers and the choice is yours: 1. **Align to `~0.19.4`** — matches the SDK and keeps `expo-doctor` quiet, but may reintroduce whatever lockfile-sync problem `3da7b8d` was fixing. 2. **Remove it entirely** — if the original sync issue no longer reproduces, this is cleanest. Testable: drop the line and run `pnpm install --frozen-lockfile`. 3. **Leave it** — nothing imports it, so it is inert; this PR at least stops Renovate pushing it further off-pin. My inclination is (2) then (1) as fallback, but it wants verifying rather than guessing. Happy to test it if you want.
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
trails-cool/trails!16
No description provided.