DEV Community

Cover image for I Migrated a 61,000+ Line TypeScript Monorepo to Next.js 16.3 & TypeScript 7 — The Results Surprised Me
Harsh Mangalam
Harsh Mangalam

Posted on

I Migrated a 61,000+ Line TypeScript Monorepo to Next.js 16.3 & TypeScript 7 — The Results Surprised Me

Performance improvements in release notes are always nice to read, but I've learned to take them with a grain of salt.

A benchmark on a small demo application rarely tells you how your production codebase will behave.

So I decided to benchmark one of my own projects after upgrading from Next.js 16.1 + TypeScript 5.8 to Next.js 16.3 + TypeScript 7.

The repository isn't enormous by enterprise standards, but it's large enough to expose real-world bottlenecks.

Project Overview

  • ~61,000 lines of TypeScript
  • Turborepo monorepo
  • Multiple applications and shared packages
  • Bun as the package manager/runtime
  • Next.js frontend
  • Shared internal packages

I measured:

  • Cold type checking
  • Cached type checking
  • Development startup
  • Production build
  • Static page generation
  • Build output size

The Upgrade Path

One thing worth mentioning is that I couldn't jump directly to TypeScript 7.

My starting point was:

  • Next.js 16.1
  • TypeScript 5.8

Since Next.js 16.1 doesn't support TypeScript 7, I first upgraded Next.js to 16.3.

That migration was surprisingly smooth and required almost no code changes.

Once that was complete, I upgraded the monorepo to TypeScript 7.


Current Ecosystem Caveat

At the time of writing, typescript-eslint still doesn't fully support TypeScript 7.

That means:

  • tsc uses TypeScript 7
  • ESLint still performs its analysis using TypeScript 5.9

It's not a blocker, but it's something to be aware of if you upgrade today.


Benchmark 1 — Type Checking

Cold run before upgrading:

bun run typecheck

Tasks:    6 successful, 6 total
Cached:   0 cached
Time:     29.805s
Enter fullscreen mode Exit fullscreen mode

After upgrading:

bun run typecheck

Tasks:    6 successful, 6 total
Cached:   0 cached
Time:     9.296s
Enter fullscreen mode Exit fullscreen mode

Result

Version Time
TS 5.8 29.8s
TS 7 9.3s

That's roughly a 3.2× improvement for a cold type check.

For a repository of this size, that's a significant reduction in feedback time.


Benchmark 2 — Turborepo Cache

Before:

259ms
Enter fullscreen mode Exit fullscreen mode

After:

114ms
Enter fullscreen mode Exit fullscreen mode

Already fast, but still noticeably quicker.


Benchmark 3 — Development Startup

Before:

bun run dev

Ready in 888ms
Enter fullscreen mode Exit fullscreen mode

After:

bun run dev

Ready in 600ms
Enter fullscreen mode Exit fullscreen mode

Not a massive difference, but enough to make restarting the dev server feel snappier.


Benchmark 4 — Production Build

Before:

time bun run build

real    0m52.044s
user    3m51.673s
sys     0m13.184s
Enter fullscreen mode Exit fullscreen mode

After:

time bun run build

real    0m22.752s
user    0m58.419s
sys     0m8.791s
Enter fullscreen mode Exit fullscreen mode

Result

Version Build Time
Before 52.0s
After 22.8s

That's approximately 56% faster.

One interesting observation is the CPU time.

The previous build consumed almost four minutes of user CPU time.

After upgrading, that dropped to under one minute, suggesting the build process itself became considerably more efficient.


Benchmark 5 — Static Generation

Before:

Generating static pages (17/17) in 3.3s
Enter fullscreen mode Exit fullscreen mode

After:

Generating static pages (17/17) in 3.2s
Enter fullscreen mode Exit fullscreen mode

Essentially unchanged.

This suggests that most of the improvements came earlier in the build pipeline rather than during static page generation.


Benchmark 6 — Output Size

Before:

du -sh .next

50M
Enter fullscreen mode Exit fullscreen mode

After:

du -sh .next

50M
Enter fullscreen mode Exit fullscreen mode

The build output remained identical.

No regressions in generated artifacts.


Summary

Metric Before After
Cold typecheck 29.8s 9.3s
Cached typecheck 259ms 114ms
Dev startup 888ms 600ms
Production build 52.0s 22.8s
Static generation 3.3s 3.2s
.next size 50 MB 50 MB

My Observations

A few things stood out during the migration:

  • The Next.js upgrade itself was uneventful.
  • TypeScript 7 delivered the largest measurable improvement in day-to-day workflows.
  • Production builds became dramatically faster.
  • Output size remained unchanged.
  • Turborepo caching continued to work flawlessly.
  • The only missing piece today is full TypeScript 7 support in typescript-eslint.

Final Thoughts

I wasn't expecting a dramatic improvement.

The biggest surprise was seeing a full monorepo type check drop from nearly 30 seconds to just over 9 seconds.

Combined with a production build that finished in less than half the previous time, the upgrade noticeably improved the development experience without requiring significant application changes.

If you're maintaining a medium or large TypeScript monorepo, it's worth running your own benchmarks after upgrading.

Your numbers will differ, but the improvements may surprise you as much as they surprised me.


Have you upgraded to TypeScript 7 yet? I'd be interested to hear how your build times compare.

Top comments (0)