ADR-0016: Quarterly stack-bump review cadence¶
- Status: Accepted
- Date: 2026-04-28
- Deciders: MASTER
- Related: #94, #160 Renovate, ADR-0009 frontend shadcn, ADR-0006 hosting Cloudflare, Reference → Tech stack
Context¶
961tech is built on the bleeding edge — Next.js 16 (released months ago), React 19, Prisma 7, Tailwind 4, Workers Paid. The bleeding-edge bet pays off (Server Actions, RSC, Suspense, Workers cost) but introduces a maintenance question: when do we bump?
Renovate (per #160) auto-merges minor + patch updates on green CI. Major bumps need human eyes. Without a cadence, two failure modes:
- Bump-when-you-think-of-it — we never think of it; the stack drifts; the next bump is a multi-major nightmare migration.
- Bump-immediately-on-release — every Friday becomes a migration day; productive feature work suffers.
A quarterly cadence threads the needle.
Decision¶
Bump major versions of the foundation stack on the first Monday of each quarter (January, April, July, October). The session is timeboxed: bumps that don't land cleanly within 1 day get reverted and queued for the next quarter (or a dedicated migration project if the gap is becoming costly).
Stack covered by the quarterly review: - Next.js, React, React DOM - Prisma, @prisma/client, @prisma/adapter-pg - TypeScript - Tailwind CSS, @tailwindcss/postcss - ESLint, eslint-config-next - Vitest - shadcn/ui (when introduced) - Auth.js (when introduced)
Renovate handles minor + patch automatically with auto-merge on green CI; the human-review surface is just majors. Renovate config is configured to surface major-bump PRs but not auto-merge them.
Workflow:
1. Quarterly Monday: pull main, branch chore/q<n>-stack-bump, run npm outdated --json to see major-version deltas.
2. For each major bump: read the migration guide, run the codemod (if available), bump the package, run npx tsc --noEmit && npm run lint && npm run format:check && npx vitest run && npx next build.
3. If anything breaks, fix it forward. If a fix is bigger than ~1 hour, revert that bump and file an issue for the next quarter.
4. Commit per-package: each PR title is chore(deps): bump <pkg> to <vX.Y>. PR body lists the migration guide link + breaking changes encountered.
5. Merge in dependency order (TS first, then build chain, then app frameworks last).
6. Open a quarterly review note at docs/plans/YYYY-Q<n>-stack-bump.md with the changelog summary.
Out-of-band bumps allowed when: - A security advisory drops on a dependency we use in prod (CVSS ≥ 7). - A bug we're hitting is fixed in a newer release. - The current version is end-of-life and the next stable is the only path forward.
Out-of-band bumps still go through the same workflow but in a smaller per-package PR rather than a quarterly batch.
Consequences¶
Positive¶
- Bounded migration cost. A major Next.js bump quarterly is cheap; once-a-year is expensive; never is catastrophic.
- Predictable maintenance. MASTER's calendar carries 4 days per year reserved for this.
- Continuous benefit. Bleeding-edge upside (Workers cost, Server Components) accrues without bleeding-edge downside (drift).
- Renovate handles the boring 80%. The human surface is just the majors that warrant review.
Negative¶
- A quarter can pass between a release and our adoption. A Next.js 17 release the week after our quarterly review waits 12 weeks. Mitigated by the out-of-band bump trigger when a new major is genuinely worth the early adoption.
- Dependency-version skew between quarters. If we ship a feature that depends on a Next.js 17.2 API, but our review cycle hasn't reached 17.2, we either backport or postpone the feature. Acceptable.
- Calendar drift. Quarterly reviews can slip. Mitigation: the project board carries a recurring "Q
stack bump" issue created at the start of each quarter.
Neutral¶
- This ADR doesn't pin specific majors — it sets the cadence. Specific version locks live in
package.jsonand are documented per-bump indocs/reference/tech-stack.md.
Alternatives considered¶
Bump-on-every-release (continuous adoption)¶
Rejected. Productive feature work suffers when every Friday is a migration day. Even with auto-codemods, the testing-and-verifying surface is real.
Bump-once-a-year (annual review)¶
Rejected. The migration debt accumulated over 12 months is materially harder than 4 quarterly migrations. A skipped Next.js 16 → 19 jump is a project; 16 → 17 → 18 → 19 in quarterly steps is four small reviews.
Pin-and-never-bump (LTS-only branches)¶
Rejected. Next.js doesn't ship LTS. React's LTS is implicit and slow. Prisma rolls forward fast. Pinning means we forfeit the bleeding-edge upside that motivated the stack choice.
Defer bumps to feature-driven need¶
Rejected. Means we bump only when forced — usually because a security advisory or an unfixable bug. The bump-in-crisis mode is the worst-time-to-bump mode.
Implementation plan¶
- This ADR (locked 2026-04-28)
- #160 Renovate config (shipped #167) — handles minor + patch with auto-merge on green CI; surfaces majors for review without auto-merging
- First quarterly review: 2026-07-06 (Q3 first Monday). Recurring issue auto-filed by GitHub Project workflow.
- Reference → Tech stack updated per quarter with current versions + last-bumped date.