@aphrody/m3-next-migrate
v3.3.11
Published
Migration analysis, codemods and runtime shims for Next.js 16 components and private-owner native Bun web apps; Tauri 3 source planning requires a registered native host adapter for activation
Maintainers
Readme
@aphrody/m3-next-migrate
High-performance migration engine, AST codemod and runtime shims to migrate Next.js 16 UI and React components to Tauri v2 desktop applications or Bun / Vite web SPAs.
Codemods: to the Next 16 + M3 stack
Two directions. The codemods below take an existing Next 14/15, MUI or Tailwind v3 app to Next.js 16, Base UI with M3 and
Tailwind v4 (the stack of @aphrody/m3-next, @aphrody/m3-baseui and @aphrody/m3-tailwind); the rest of this README takes a Next 16
app out to Tauri or Vite. Without --apply nothing is written: you get a report of what would change and what needs a human.
next-migrate codemod --list
next-migrate codemod next16 ./my-app # report
next-migrate codemod all ./my-app --apply # write
next-migrate pages-hints ./my-app # Pages Router -> App Router plan, nothing rewrittenInside the Aphrody checkout, yolo m3 next-migrate takes the same arguments.
| Group | Codemod | Does |
| --------- | ------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| next16 | next-config | experimental.dynamicIO, ppr -> cacheComponents; experimental.turbo -> turbopack; typedRoutes, reactCompiler, serverComponentsExternalPackages -> serverExternalPackages; drops eslint and removed flags; images.domains -> remotePatterns |
| next16 | middleware-to-proxy | middleware.ts -> proxy.ts, export function middleware -> proxy, drops runtime = "edge" |
| next16 | async-request-apis | awaits cookies(), headers(), draftMode() and makes the enclosing top-level function async |
| next16 | async-route-props | params and searchParams are Promises in page, layout, route and metadata files: types, destructuring and uses |
| next16 | revalidate-tag | revalidateTag(tag) -> revalidateTag(tag, "max") |
| next16 | legacy-image, next-package-json | next/legacy/image -> next/image; versions, next lint, --turbo |
| mui | mui-to-m3 | Button, Switch, Checkbox, Divider -> @aphrody/m3-baseui; Typography, Stack, Box, Paper -> elements with M3 Tailwind classes; the rest is reported |
| tailwind4 | tailwind-css-v4 | @tailwind directives -> @import "tailwindcss"; @layer utilities -> @utility; theme() |
| tailwind4 | tailwind-classes-v4 | shadow-sm, rounded, ring, outline-none, ... renamed; bg-opacity-50 -> /50; !p-4 -> p-4!; bg-[--x] -> bg-(--x); runs once (a project already on v4 is skipped) |
| tailwind4 | tailwind-config-v4, postcss-config-v4, tailwind-package-json | tailwind.config.js -> tailwind-theme.css (@theme, @plugin, dark variant); PostCSS plugin; dependencies |
The codemods are pure functions on source text (import { codemods } from "@aphrody/m3-next-migrate", or the subpath
@aphrody/m3-next-migrate/codemods): a small scanner finds strings, comments and matching brackets, so edits never land inside a
string. A shape a codemod recognises but cannot rewrite safely (a named props type, a callback that needs await, a MUI Select) becomes
a warning, never a guess. pages-hints covers getServerSideProps, getStaticProps, getStaticPaths, next/router, next/head,
(req, res) API handlers, _app and _document.
Moved to aphrody-labs/bun
The next16 and tailwind4 codemods, the source scanner (lex), pages-hints and the codemod CLI now live in @aphrody/next-bun
(packages/bun-next/codemods/ of aphrody-labs/bun, tested in test/integration/next-bun/codemods.test.ts there, also
next-bun codemod). This package keeps mui-to-m3 (and its JSX scanner), composes [...NEXT16_CODEMODS, mui, ...TAILWIND4_CODEMODS],
passes the M3 preset header to tailwind-config-v4 and re-exports the rest from @aphrody/m3-next-migrate/codemods. The dependency is
the published @aphrody/next-bun (npm, exact pin 0.2.0-aphrody.1).
Why Migrate from Next.js 16 to Tauri v2 or Vite?
Next.js 16 introduces React 19, Server Actions, Async Request APIs (await params, await cookies()), and deep coupling to Vercel/Node edge runtimes. Migrating UI components to a desktop application (Tauri v2) or client SPA (Bun/Vite) traditionally requires manually rewriting dozens of Next.js imports and routing mechanisms.
@aphrody/m3-next-migrate automates this transition end-to-end:
AST & Import Codemod:
- Strips
"use client"and adapts"use server"boundaries. - Rewrites
next/navigationhooks (useRouter,usePathname,useSearchParams,useParams,redirect,notFound). - Rewrites
next/linkwith automatic desktop shell delegation (external links open in OS browser via@aphrody/plugin-opener, internal links route via client router). - Rewrites
next/imagewith responsive<img>andfillmode support. - Rewrites
next/font/googleandnext/font/localto standard CSS variables and fonts. - Rewrites
next/dynamictoReact.lazy+Suspense. - Normalizes Next 16 async page props (
await params->params). - Rewrites
process.env.NEXT_PUBLIC_*toimport.meta.env.*.
- Strips
Production-Ready Runtime Shims:
@aphrody/m3-next-migrate/shims/navigation@aphrody/m3-next-migrate/shims/link@aphrody/m3-next-migrate/shims/image@aphrody/m3-next-migrate/shims/font@aphrody/m3-next-migrate/shims/dynamic@aphrody/m3-next-migrate/shims/headers@aphrody/m3-next-migrate/shims/form@aphrody/m3-next-migrate/shims/tauri-ipc@aphrody/m3-next-migrate/shims/provider(<NextMigrateProvider>)
Complete Scaffolding:
- Generates
tauri.conf.json,Cargo.toml,vite.config.ts,index.html, andmain.tsx.
- Generates
CLI Usage
# Scan a Next.js 16 codebase and audit used features
next-migrate ./my-next-app --scan-only
# Migrate an entire Next.js 16 project to Tauri v2
next-migrate ./my-next-app ./desktop-app --target tauri
# Migrate to a Bun / Vite web SPA
next-migrate ./my-next-app ./web-app --target vite
# Migrate a single component file
next-migrate ./components/Hero.tsx ./dist/Hero.tsxProgrammatic API
import { transformComponent, scanNextDirectory, migrateProject } from "@aphrody/m3-next-migrate";
// Transform component code
const result = transformComponent(nextSourceCode, {
target: "tauri",
rewriteEnv: true,
stripDirectives: true,
});
// Full project migration
const report = await migrateProject({
sourceDir: "./next-site",
targetDir: "./tauri-desktop",
target: "tauri",
projectName: "my-desktop-app",
scaffold: true,
});The generated project is written by @aphrody/scaffold (the app template), the single scaffolder of the
UI stack; TAURI_3 is re-exported from there. See docs/guides/ui/SCAFFOLD.md.
Testing & Verification
bun test packages/m3-next-migrate
bun run --filter @aphrody/m3-next-migrate typecheck
bun run --filter @aphrody/m3-next-migrate build