Skip to content

chore(deps): upgrade Next.js 15 → 16 + React 18 → 19 - #114

Merged
catomean merged 1 commit into
deps/next-15from
deps/next-16
Jul 26, 2026
Merged

chore(deps): upgrade Next.js 15 → 16 + React 18 → 19#114
catomean merged 1 commit into
deps/next-15from
deps/next-16

Conversation

@catomean

Copy link
Copy Markdown
Collaborator

Framework major upgrade. Stacks on #111 (Next 14 → 15) — base is deps/next-15 so this diff shows only the 15 → 16 delta and will auto-retarget to main when #111 merges. Merge order: #111 → this. (Security PRs #112/#113 are independent overrides that combine at merge.)

What changed

Dependencies

  • next 15.5.21 → 16.2.12
  • react / react-dom 18 → 19.2.8, @types/react(-dom) → 19
  • eslint 8 → 9 (flat config), eslint-config-next → 16, @typescript-eslint 6 → 8 — also clears the lingering ts-eslint Dependabot alert

Config migrations Next 16 requires

  • next lint was removed → lint scripts now run eslint .; .eslintrc.json migrated to eslint.config.mjs (flat config) composing eslint-config-next 16's native flat configs. (FlatCompat crashes with a circular-JSON error on the react plugin — same class as the sbb-lost-found lint crash.)
  • typedRoutes graduated from experimental → stable top-level option
  • tsconfig target es5 → ES2017 (Next 16 drops es5; noEmit, so this only affects type-checking, not SWC output)
  • next-env.d.ts regenerated to Next 16's import-based form

React 19 type-tightening (runtime behaviour unchanged)

  • ImgHTMLAttributes['src'] widened to string | Blob → narrow before string ops (MDXComponents, ServerMDXContent)
  • ReactElement['props'] is now unknown → annotate the read shape (guides pre block)
  • useRef<T>(null) returns RefObject<T | null> → widen the ChatMessageList prop

⚠️ Deferred (out of scope for a framework upgrade)

eslint-plugin-react-hooks v6 (bundled with Next 16) adds React-Compiler-era rules — set-state-in-effect (13), error-boundaries (12), immutability (5) — that flag 30 pre-existing intentional patterns (localStorage hydration, load-on-mount effects). Adopting them is a dedicated 30-site refactor with real behaviour risk, so they're disabled here and left as a tracked follow-up. rules-of-hooks and exhaustive-deps stay enabled. no-unused-vars caughtErrors pinned to 'none' to preserve the pre-upgrade contract (v8 flipped the default to 'all', which would newly flag every unused catch binding).

Verification

  • tsc --noEmit — clean
  • next build (Turbopack, all pages)
  • eslint . (flat config) — 0 problems
  • jest — 227 passed, 2 skipped

🤖 Generated with Claude Code

Framework major upgrade, stacked on #111 (Next 14 → 15).

Dependencies:
- next 15.5.21 → 16.2.12
- react / react-dom 18 → 19.2.8, @types/react(-dom) → 19
- eslint 8 → 9 (flat config), eslint-config-next → 16, @typescript-eslint 6 → 8
  (also clears the lingering ts-eslint Dependabot alert)

Config migrations required by Next 16:
- `next lint` removed → lint scripts use `eslint .`; migrated .eslintrc.json to
  eslint.config.mjs (flat) composing eslint-config-next 16's native flat configs
  (FlatCompat crashes on the react plugin's circular flat object)
- typedRoutes graduated from `experimental` to a stable top-level option
- tsconfig target es5 → ES2017 (Next 16 drops es5; noEmit, so type-check only)

React 19 type-tightening fixes (behaviour unchanged):
- ImgHTMLAttributes['src'] widened to string | Blob → narrow before string ops
  (MDXComponents, ServerMDXContent)
- ReactElement['props'] is now unknown → annotate read shape (guides pre block)
- useRef<T>(null) returns RefObject<T | null> → widen ChatMessageList prop

Deferred (out of scope for a framework upgrade, tracked as follow-up):
eslint-plugin-react-hooks v6 (bundled with Next 16) adds React-Compiler-era
rules (set-state-in-effect, error-boundaries, immutability) that flag 30
pre-existing intentional patterns; disabled here. no-unused-vars caughtErrors
pinned to 'none' to preserve the pre-upgrade contract (v8 flipped the default).

Verified: tsc --noEmit, next build (Turbopack, all pages), eslint ., jest 227 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@catomean
catomean merged commit 7cf0f61 into deps/next-15 Jul 26, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant