Skip to content

Upgrade the whole stack to the latest stable versions (.NET 10.0.14, Aspire 13.6, Vite 8, ESLint 10, zod 4, Node 26) #1453

Closed

Description

@iammukeshm

Why

The kit has drifted behind on almost every layer. On 2026-11-03, dotnet list package --outdated reports 61 outdated NuGet packages, and both React apps are behind on most of their dependencies, including several majors. The 10.0.0 template on NuGet already fails to build for new users because of advisories published since its release (#1451). Falling behind like this is also how we got the restore break that #1447 fixed. This issue brings everything up to the latest stable versions in one tested pass, so that we can cut a 10.0.1 template release from a clean main.

Scope decisions

  • Stay on .NET 10 (LTS). .NET 11 is still at 11.0.0-rc.3 (go-live). It isn't GA, and it's an STS release. Moving the kit to .NET 11 is a separate issue, to be done after GA.
  • Stable versions only. No previews, RCs or betas, except where a package has only ever shipped prerelease builds. That applies to the OpenTelemetry EF Core and StackExchange.Redis instrumentation packages, which we already use as betas; move those to their latest beta.
  • TypeScript stays on the 6.0 line. TypeScript 7 is out, but typescript-eslint 8.72.1 declares typescript >=4.8.4 <6.1.0, so it can't lint TS 7. Take TS 6.0.3 now and follow up on 7 once typescript-eslint supports it.
  • Microsoft.OpenApi stays on 2.x. Microsoft.AspNetCore.OpenApi 10 is built against 2.x, and 3.x breaks the framework's transformers (see the comment in Directory.Packages.props). Bump it to the latest 2.x only.
  • Any major upgrade that can't be done cleanly gets reverted to the previous major, with the blocker written down here and a follow-up issue. A half-migrated major doesn't ship.

Inventory (2026-11-03)

.NET SDK and runtime

  • Runtime 10.0.13 → 10.0.14. SDK: latest is 10.0.403. global.json pins 10.0.100 with latestFeature; raise the floor to the current feature band.
  • System.Security.Cryptography.Xml / .Pkcs transitive pins → 10.0.14, in lockstep with the patch line.

NuGet (src/Directory.Packages.props)

  • ASP.NET Core / EF Core / Microsoft.Extensions.*: every 10.0.13 → 10.0.14. Microsoft.Extensions.Caching.Hybrid and Http.Resilience 10.10.0 → 10.11.0.
  • Aspire: Aspire.Hosting.* and the AppHost SDK 13.5.4 → 13.6.4. Check the default Postgres and Valkey images the new hosting packages pull; see the PG 18 volume note in the AppHost docs.
  • Finbuckle.MultiTenant.*: 10.1.0 → 10.1.6
  • FluentValidation: 12.1.1 → 12.2.0
  • OpenTelemetry: 1.19.x → 1.20.1, plus the beta instrumentation packages
  • StackExchange.Redis: 3.3.1 → 3.4.31
  • Scalar.AspNetCore: 2.17.10 → 2.18.7
  • MailKit / MimeKit: → 4.18.2
  • AWSSDK.S3: 4.0.103.4 → 4.0.104.8
  • QuestPDF: 2026.9.0 → 2026.9.1
  • Spectre.Console.Cli (CLI): 0.55.0 → 0.57.2. This is a pre-1.0 minor, so check for breaking API changes in the fsh commands.
  • Tooling: SonarAnalyzer 10.35.0.4138, SourceLink 10.0.403, Microsoft.NET.Test.Sdk 18.11.0, coverlet 10.1.0, xunit.runner.visualstudio 4.0.1, Testcontainers 4.16.0
  • xUnit v2 → v3: evaluate. The tests are on xunit 2.9.3, and v3 (xunit.v3) is the current line. If the migration is mechanical, do it here. If it touches the integration harness (collection fixtures, IAsyncLifetime), split it into its own issue and say so here.

React apps (clients/admin, clients/dashboard)

Minor/patch (take all): React 19.3.1, React Router 7.18.5, TanStack Query 5.105.3, TanStack Virtual 3.14.26, Radix (dialog 1.3.1, dropdown-menu 2.2.1, label 2.1.17, slot 1.5.0), Tailwind + @tailwindcss/vite 4.3.4, tailwind-merge 3.7.0, @microsoft/signalr 10.0.11, react-hook-form 7.91.0, sonner 2.0.8, Playwright 1.64.1, typescript-eslint 8.72.1, autoprefixer 10.6.2, @types/react* 19.3.0.

Majors (each one needs its migration guide read and applied):

Package From To What to watch
vite 7 8.3.5 Rolldown-based bundler. Check vite.config.ts, the dev proxy (including the admin ws proxy issue), manualChunks, and the runtime /config.json loading.
@vitejs/plugin-react 4 6.2.1 Needs Vite 8. Babel is now optional (@rolldown/plugin-babel).
typescript 5.x 6.0.3 New defaults and deprecations in tsconfig. Must stay <6.1 for typescript-eslint.
eslint 9 10.14.0 Flat config only. Check every plugin's peer range.
eslint-plugin-react-hooks 5 7.1.1 New React Compiler-aware rules. Fix real violations; don't blanket-disable them.
eslint-plugin-react-refresh 0.4 0.5.7
globals 15 17.14.0
lucide-react 0.475 1.67.0 Renamed or removed icons. Every import has to resolve, with no visual regressions.
zod (admin) 3 4.6.7 Error-map and message API changes, .email()/.url() moves, z.infer differences. Every admin form's validation messages must still render.
@hookform/resolvers (admin) 3 7.0.2 Needs RHF ≥ 7.55. Matches zod 4.
@types/node 22 latest matching the Node we run

Node, containers and CI

  • Node: the Dockerfiles use node:22-alpine and CI uses node-version: 22. The current LTS is Node 26 (v26.13.0). Move both to it, and set engines.node to what Vite 8 actually requires.
  • nginx:alpine: pin a version instead of floating, as the repo does for every other image.
  • Compose/Aspire images: Postgres is postgres:17-alpine in one compose file and postgres:18-alpine in another. Make it consistent. Also bump Valkey 9.1.0 → latest 9.x, RustFS 1.0.0 → latest stable, Mailpit v1.31.3 → latest, and amazon/aws-cli → latest. Testcontainers images must match what compose runs.
  • GitHub Actions: actions/setup-node@v4 → latest major, github/codeql-action@v3 → v4, dorny/paths-filter@v3 → latest, and check the rest are current. CodeQL has failed on main every week since 2026-10-19; fix it as part of this.
  • Terraform providers: check aws and the TF floor against the latest. Only bump these if terraform validate passes.

Acceptance criteria

  • dotnet list src/FSH.Starter.slnx package --outdated reports nothing except the exceptions listed under Scope decisions (OpenApi 3.x, any deferred majors), each with a comment in Directory.Packages.props explaining why.
  • dotnet list package --vulnerable --include-transitive reports no vulnerable packages, and restore passes with NuGet audit under TreatWarningsAsErrors.
  • dotnet build src/FSH.Starter.slnx: 0 errors, 0 warnings.
  • dotnet test src/FSH.Starter.slnx: unit, architecture and the full integration suite (Testcontainers) all pass, with the same or higher test count than before the upgrade.
  • Both React apps: npm ci is clean (no peer-dependency overrides or --legacy-peer-deps), npm outdated is empty apart from documented exceptions, npm audit --omit=dev shows no high or critical issues, npm run lint has 0 errors, tsc -b --noEmit is clean, and npm run build succeeds.
  • Both Playwright suites pass in full. Report bundle sizes before and after in the PR.
  • The full stack runs under Aspire (dotnet run --project src/Host/FSH.Starter.AppHost): migrator and seed succeed, the API is healthy, /scalar loads, and both apps sign in, navigate the main pages, and get realtime (SignalR) updates.
  • deploy/docker compose builds and starts. The frontend container smoke test and the DbMigrator container smoke test pass in CI.
  • The template smoke test (dotnet new fsh with and without Aspire/React) builds a fresh project with zero audit errors. This is the create new project build error #1451 regression check.
  • Backend CI, Frontend CI, Template Smoke Test and CodeQL are green on the PR and on main after merge.
  • The docs repo is updated (versions table, Node/Aspire requirements, any changed setup steps) with a changelog entry listing the notable upgrades.
  • Follow-up issues are filed for anything deferred (.NET 11, TypeScript 7, xUnit v3 if split).

Activity

  1. iammukeshm commented on Nov 3, 2026

    @iammukeshm
    MemberAuthor

    Done in three PRs: #1460 (backend, Aspire, images, Actions, Terraform), #1461 (both React apps, Node, nginx) and #1463 (the guides). The docs went in with fullstackhero/docs#279 and #280.

    Here's where each acceptance criterion landed:

    • Packages. dotnet list package --outdated and --vulnerable --include-transitive are both empty. npm outdated shows only TypeScript 7 in each app. npm audit --omit=dev reports no findings in either app (admin had one high, from zod 3, before).
    • Build and tests. The build has 0 warnings and 0 errors. Backend tests pass 2,222/2,222 across 16 assemblies, the same count as before. Playwright passes 183/183 (admin) and 251/251 (dashboard).
    • CI on main is green on the upgraded head: Backend CI (with the integration suite), Frontend CI (with both E2E suites and the container smoke tests), and the Template Smoke Test. CodeQL is green for the first time since 2026-10-19.
    • Aspire. The stack comes up on 13.6.4 with all /health/ready checks healthy, /scalar loads, and both React dev servers serve. Sign-in, refresh and 2FA are covered by 51/51 auth integration tests against a fresh database.
    • Template (create new project build error #1451). Packed and installed from the repo, the full and backend-only scaffolds both build with -warnaserror and zero audit errors. A 10.0.1 release on NuGet is the remaining step for create new project build error #1451.

    Deferred, with follow-ups:

    Worth knowing:

    • jsx-a11y fork. eslint-plugin-jsx-a11y has no ESLint 10 release, so the apps use the eslint-plugin-jsx-a11y-x fork under the same rule names. Switching back is a one-line import.
    • react-hooks 7 fixes. The 79 new findings were fixed, none disabled.
    • SignalR in dev. The admin dev proxy now forwards WebSocket upgrades.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions