Skip to content

Commit b437778

Browse files
authored
Merge pull request #116 from design-sparx/claude/migrate-nextjs-14-to-16-018AEf4kj5QQZmkK3amqwrLm
Migrate Next.js from version 14 to 16
2 parents 2086291 + 0ca9f9a commit b437778

File tree

13 files changed

+23170
-5839
lines changed

13 files changed

+23170
-5839
lines changed

.changeset/tidy-news-push.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'mantine-analytics-dashboard': minor
3+
---
4+
5+
migrating from next 14 to next 16

MIGRATION_DISCUSSION.md

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# Discussion: Migration from Next.js 14 to Next.js 16
2+
3+
## Overview
4+
5+
This document outlines the proposed migration of our Mantine Analytics Dashboard from **Next.js 14.2.26** to **Next.js 16** (stable release, October 2025). This is a significant upgrade that requires careful planning and team discussion.
6+
7+
## Current Stack
8+
9+
| Package | Current Version |
10+
|---------|-----------------|
11+
| Next.js | 14.2.26 |
12+
| React | 18.2.0 |
13+
| React DOM | 18.2.0 |
14+
| TypeScript | 5.1.6 |
15+
| Node.js | 20.x |
16+
17+
## What's New in Next.js 16
18+
19+
### Performance Improvements
20+
21+
- **Turbopack (Stable & Default)** - 2-5x faster production builds, up to 10x faster Fast Refresh
22+
- **React Compiler (Stable)** - Automatic memoization of components, reducing unnecessary re-renders
23+
- **Layout Deduplication** - Shared layouts downloaded once instead of per-link (major prefetching optimization)
24+
25+
### New Features
26+
27+
- **React 19.2 Support** - View Transitions, `useEffectEvent`, Activity API
28+
- **Cache Components** - Stable `cacheLife` and `cacheTag` APIs (no more `unstable_` prefix)
29+
- **Next.js DevTools MCP** - AI-assisted debugging integration
30+
- **Partial Pre-Rendering (PPR)** - Enhanced with `use cache` for instant navigation
31+
32+
### Architecture Changes
33+
34+
- **Proxy replaces Middleware** - New `proxy.ts` file for network boundary operations
35+
- Edge runtime NOT supported in proxy
36+
- Runtime is Node.js only (not configurable)
37+
38+
## Breaking Changes & Migration Requirements
39+
40+
### 1. React 18 → React 19 Migration (High Impact)
41+
42+
This is the most significant change. React 19 introduces:
43+
- New hooks and APIs
44+
- Stricter hydration requirements
45+
- Changes to ref handling
46+
- Potential breaking changes in third-party libraries
47+
48+
**Action Required:** Update all React dependencies and audit component compatibility.
49+
50+
### 2. Middleware → Proxy Migration (High Impact)
51+
52+
Our current `middleware.ts` handles:
53+
- Route protection
54+
- Authentication redirects
55+
- Session validation
56+
57+
**Action Required:** Convert `middleware.ts` to `proxy.ts` with Node.js runtime constraints.
58+
59+
### 3. Dependency Compatibility Audit (Medium Impact)
60+
61+
Libraries requiring verification:
62+
63+
| Package | Concern |
64+
|---------|---------|
65+
| `@mantine/next` (6.0.16) | May need updates for Next.js 16 |
66+
| `next-auth` (4.24.12) | React 19 / Next.js 16 compatibility |
67+
| `@storybook/nextjs` (7.5.3) | React 19 compatibility |
68+
| `mantine-datatable` (7.1.7) | React 19 compatibility |
69+
| `react-apexcharts` (1.4.1) | React 19 compatibility |
70+
| `@tiptap/*` packages | React 19 compatibility |
71+
72+
### 4. TypeScript & Node.js Requirements
73+
74+
- **Node.js 20.9+** required (we currently meet this)
75+
- **TypeScript 5+** required (we currently meet this)
76+
77+
## Risk Assessment
78+
79+
### High Risk
80+
- React 19 migration may break third-party component libraries
81+
- Middleware to proxy conversion could affect authentication flow
82+
- Storybook may require significant updates for React 19
83+
84+
### Medium Risk
85+
- Mantine components may have undocumented React 19 issues
86+
- Build configuration changes with Turbopack default
87+
- NextAuth session handling changes
88+
89+
### Low Risk
90+
- TypeScript compatibility (already on 5.x)
91+
- Node.js compatibility (already on 20.x)
92+
- Basic routing (App Router unchanged)
93+
94+
## Proposed Migration Strategy
95+
96+
### Phase 1: Preparation
97+
1. Create feature branch for migration
98+
2. Audit all dependencies for React 19 / Next.js 16 compatibility
99+
3. Document current middleware functionality
100+
4. Set up comprehensive testing plan
101+
102+
### Phase 2: Core Migration
103+
1. Update React to 19.2
104+
2. Update Next.js to 16.x
105+
3. Convert `middleware.ts` to `proxy.ts`
106+
4. Fix TypeScript errors and breaking changes
107+
108+
### Phase 3: Dependency Updates
109+
1. Update Mantine packages (if new versions available)
110+
2. Update or replace incompatible libraries
111+
3. Update Storybook for React 19
112+
113+
### Phase 4: Testing & Validation
114+
1. Test all authentication flows
115+
2. Test all dashboard pages and components
116+
3. Verify Storybook builds
117+
4. Performance benchmarking
118+
119+
## Benefits of Migration
120+
121+
1. **Performance** - Significantly faster builds and development experience
122+
2. **Future-proofing** - Access to latest React features and optimizations
123+
3. **Developer Experience** - React Compiler eliminates manual memoization
124+
4. **AI Tooling** - DevTools MCP for enhanced debugging
125+
126+
## Questions for Discussion
127+
128+
1. **Timeline**: When should we target this migration? Is there urgency?
129+
2. **Testing**: Do we need to establish a test suite before migration?
130+
3. **Fallback Plan**: Should we maintain a Next.js 14 branch during transition?
131+
4. **Dependencies**: Are there alternative libraries we should consider for incompatible packages?
132+
5. **Incremental vs Big Bang**: Should we attempt Next.js 15 first, or jump directly to 16?
133+
134+
## Resources
135+
136+
- [Next.js 16 Release Blog](https://nextjs.org/blog/next-16)
137+
- [Next.js 16 Upgrade Guide](https://nextjs.org/docs/app/guides/upgrading/version-16)
138+
- [React 19 Migration Guide](https://react.dev/blog/2024/04/25/react-19-upgrade-guide)
139+
140+
## Next Steps
141+
142+
Please review this proposal and share your thoughts:
143+
144+
- [ ] Approve migration approach
145+
- [ ] Identify critical dependencies to audit first
146+
- [ ] Establish timeline
147+
- [ ] Assign migration tasks
148+
149+
---
150+
151+
**Created**: November 2025
152+
**Status**: Open for Discussion
153+
**Branch**: `claude/migrate-nextjs-14-to-16-018AEf4kj5QQZmkK3amqwrLm`
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
1-
import NextAuth from 'next-auth';
1+
import { handlers } from '@/auth';
22

3-
import { authOptions } from '@/app/lib/authOptions';
4-
5-
const handler = NextAuth(authOptions);
6-
7-
export { handler as GET, handler as POST };
3+
export const { GET, POST } = handlers;

app/auth/clerk/layout.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
import { ReactNode } from 'react';
44

55
import { ClerkProvider } from '@clerk/nextjs';
6+
import { Alert, Container, Stack, Text, Title } from '@mantine/core';
7+
import { IconAlertCircle } from '@tabler/icons-react';
68

79
import { MainLayout } from '@/layouts/Main';
810
import { Providers } from '@/providers/session';
@@ -14,6 +16,50 @@ type AuthProps = {
1416
};
1517

1618
function AuthLayout({ children }: AuthProps) {
19+
// Check if Clerk is configured
20+
const clerkPublishableKey = process.env.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY;
21+
22+
if (!clerkPublishableKey) {
23+
return (
24+
<MainLayout>
25+
<Providers>
26+
<Container size="sm" py="xl">
27+
<Stack>
28+
<Alert
29+
icon={<IconAlertCircle size={16} />}
30+
title="Clerk Not Configured"
31+
color="yellow"
32+
>
33+
<Text size="sm">
34+
Clerk authentication is not configured. Please set the{' '}
35+
<code>NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY</code> environment
36+
variable to enable Clerk features.
37+
</Text>
38+
</Alert>
39+
<Title order={4}>To configure Clerk:</Title>
40+
<Text size="sm">
41+
1. Create an account at{' '}
42+
<a
43+
href="https://dashboard.clerk.com"
44+
target="_blank"
45+
rel="noopener noreferrer"
46+
>
47+
dashboard.clerk.com
48+
</a>
49+
</Text>
50+
<Text size="sm">
51+
2. Get your publishable key from the API Keys section
52+
</Text>
53+
<Text size="sm">
54+
3. Add it to your <code>.env.local</code> file
55+
</Text>
56+
</Stack>
57+
</Container>
58+
</Providers>
59+
</MainLayout>
60+
);
61+
}
62+
1763
return (
1864
<MainLayout>
1965
<Providers>

app/lib/authOptions.ts renamed to auth.ts

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import NextAuth from 'next-auth';
2-
import { NextAuthOptions } from 'next-auth';
3-
import { JWT } from 'next-auth/jwt';
4-
import CredentialsProvider from 'next-auth/providers/credentials';
2+
import Credentials from 'next-auth/providers/credentials';
3+
4+
import type { JWT } from 'next-auth/jwt';
55

66
// Helper function to refresh the token
77
async function refreshAccessToken(token: JWT) {
@@ -76,7 +76,7 @@ async function refreshAccessToken(token: JWT) {
7676
const newToken = refreshedTokens.token || refreshedTokens.accessToken;
7777

7878
// Update permissions from the new token if needed
79-
let permissions = [];
79+
let permissions: string[] = [];
8080
if (newToken) {
8181
try {
8282
const payload = JSON.parse(
@@ -107,9 +107,9 @@ async function refreshAccessToken(token: JWT) {
107107
}
108108
}
109109

110-
export const authOptions: NextAuthOptions = {
110+
export const { handlers, signIn, signOut, auth } = NextAuth({
111111
providers: [
112-
CredentialsProvider({
112+
Credentials({
113113
name: 'Credentials',
114114
credentials: {
115115
email: { label: 'Email', type: 'email' },
@@ -154,7 +154,7 @@ export const authOptions: NextAuthOptions = {
154154
// You can extract the payload portion without validating the signature
155155
// (NextAuth will handle token validation)
156156
const token = response.token;
157-
let permissions = [];
157+
let permissions: string[] = [];
158158

159159
if (token) {
160160
try {
@@ -211,7 +211,7 @@ export const authOptions: NextAuthOptions = {
211211
}
212212

213213
// Return the previous token if the access token has not expired yet
214-
if (token.expiration && new Date(token.expiration) > new Date()) {
214+
if (token.expiration && new Date(token.expiration as string) > new Date()) {
215215
console.log('Token not expired, returning existing token');
216216
return token;
217217
}
@@ -235,24 +235,18 @@ export const authOptions: NextAuthOptions = {
235235
session.user.id = token.id as string;
236236

237237
// Add custom fields to session
238-
// @ts-ignore - Adding custom properties
239-
session.accessToken = token.accessToken;
240-
// @ts-ignore
241-
session.roles = token.roles;
242-
// @ts-ignore
243-
session.permissions = token.permissions;
244-
// @ts-ignore
245-
session.expiration = token.expiration;
238+
session.accessToken = token.accessToken as string;
239+
session.roles = token.roles as string[];
240+
session.permissions = token.permissions as string[];
241+
session.expiration = token.expiration as string;
246242

247243
// Add refresh token error to session if it exists
248244
if (token.error) {
249-
// @ts-ignore
250-
session.error = token.error;
245+
session.error = token.error as string;
251246
}
252247
}
253248

254249
return session;
255250
},
256251
},
257-
secret: process.env.NEXTAUTH_SECRET!,
258-
};
252+
});

next.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
const nextConfig = {
33
reactStrictMode: true,
44
trailingSlash: false,
5+
6+
// Enable React Compiler (stable in Next.js 16)
7+
reactCompiler: true,
58
};
69

710
module.exports = nextConfig;

0 commit comments

Comments
 (0)