gio migrate
Migrate a Next.js project (pages or app router) to GioJS in place, by running create-giojs migrate, and write MIGRATION_REPORT.md.
npx gio migrate ./my-next-app --dry-runpnpm exec gio migrate ./my-next-app --dry-runyarn gio migrate ./my-next-app --dry-runbunx gio migrate ./my-next-app --dry-rungio migrate [dir] [--dry-run] [-y] [--config <file>]
# the same command, without @gio.js/server installed:
npm create giojs@latest -- migrate [dir]
npx create-giojs migrate [dir]
npx -p create-giojs gio-migrate [dir]Reference
| Option | Type | Default | Description |
|---|---|---|---|
[dir] | path | . | The Next.js project root. |
--dry-run, -n | boolean | false | Print the plan and a unified diff of every change; write nothing. |
-y, --yes | boolean | false | Apply without asking. Without a terminal (CI, piped input) a real run needs it. |
--config <file> | path | - | Only convert this next.config file to gio.toml (written next to it). Takes --dry-run too. |
-h, --help | boolean | - | Print create-giojs migrate's help and exit with 0. |
Behavior
gio migrate passes its arguments to create-giojs migrate, which owns the transforms. It runs:
- the
create-giojsinstalled in the project or next to@gio.js/server; - otherwise
create-giojs@<your gio version>through your package manager (npx,pnpm dlxorbunx), so the CLI and the migration are the same release. It printsgio migrate: create-giojs is not installed, running npx create-giojs@...first.
gio never runs a create-giojs to find out whether it knows migrate: releases from before the subcommand treat any unknown argument as the name of a new project and scaffold it. It reads the subcommand from create-giojs's package.json exports (create-giojs/migrate) instead - from disk for an installed copy, from the registry with npm view (which downloads and runs nothing) otherwise. A release without it is reported, with the install command, and not run.
The migration itself:
- Plans every change first and prints a summary. A real run then warns when the directory is not a git repository or has uncommitted changes, and asks before writing (or needs
--yes). - Moves
pages/toapp/(pages/about.tsx→app/about/page.tsx,pages/api/x.ts→app/api/x/route.ts,_app/_documentintoapp/layout.tsx), andsrc/apptoapp/. - Rewrites
next/link,next/image,next/router,next/navigation,next/head,next/script,next/dynamic,next/fontandnext/cachecode, and turnsgetStaticPropsintogetServerSidePropsplusexport const revalidate. Anything it cannot convert gets a// TODO(gio-migrate):comment. - Converts
next.configredirects, rewrites, headers, images and i18n togio.toml, merged into an existing one only when that is safe (otherwisegio.migrated.toml). - Swaps
nextfor the@gio.js/*packages inpackage.jsonand sets"type": "module". - Writes
MIGRATION_REPORT.mdwith every move, change and TODO, by file and line.
Examples
Preview the migration
$ npx gio migrate ./next-app --dry-run
Next.js project (pages router) at /home/me/next-app
→ pages/api/hello.ts → app/api/hello/route.ts (2 TODOs)
→ pages/index.tsx → app/page.tsx (2 changes)
→ pages/posts/[id].tsx → app/posts/[id]/page.tsx (2 changes, 1 TODO)
+ gio.toml
~ package.json (11 changes)
+ MIGRATION_REPORT.md
4 TODOs for you - see MIGRATION_REPORT.md
--- pages/api/hello.ts
+++ app/api/hello/route.ts
...
Dry run - nothing was written.→ is a move, + a new file, ~ an edit in place.
Apply without a prompt
git switch -c migrate-to-giojs
npx gio migrate . --yes
npm install && npx tsc --noEmit && npm run devWithout --yes and without a terminal, nothing is written:
Refusing to modify files without confirmation: re-run with --yes to apply, or --dry-run to preview.Convert only next.config
$ npx gio migrate --config next.config.js --dry-run
✔ redirect /old/:path* → /new/:path* → [[redirects]] /old/*path → /new/*path (308)
--- gio.toml
+++ gio.toml
@@ -0,0 +1,16 @@
+# gio.toml - generated by create-giojs migrate from next.config.
+# Reference: https://giojs.com/docs/configuration
+
+[app]
+name = "next-app"
...
+[[redirects]]
+from = "/old/*path"
+to = "/new/*path"
+status = 308
Dry run - nothing was written.Good to know
- Commit first. The migration edits files in place and is meant to be reviewed as a diff; a file is never moved onto an existing one.
- Exit codes come from
create-giojs migrate:0when it applied, previewed, or you answered no;1for an error or a refused run without--yes;2for a usage error (an unknown option, a second directory,--configwithout a file), as everygiousage error.gio migrateexits1itself when no suitablecreate-giojscan be found or run. - A new
gio.tomlnames the app after thenameinpackage.json(with--config, the one next to the config file), ormy-appwhen there is none.--configrefuses to overwrite an existinggio.migrated.toml. gio help migrateprintsgio's summary;gio migrate --helpprints the full help ofcreate-giojs migrate.
Related
- Migration from Next.js - what is converted and what needs a human
create-giojs migrategio add
Version history
| Version | Changes |
|---|---|
v0.1.0-beta.8 | Introduced. The migration (also create-giojs migrate and the gio-migrate bin) parses code with the TypeScript compiler, replacing the regex codemod. Usage errors exit with 2, and --config names the app after package.json like the full migration. |