CLI
The gio command runs, inspects and packages GioJS apps. It ships with @gio.js/server; create-giojs scaffolds new ones.
npx gio --helppnpm exec gio --helpyarn gio --helpbunx gio --helpCommands
| Command | What it does |
|---|---|
gio dev | Start the development server: file watcher, error overlay, live reload |
gio start | Start the production server |
gio build | Explain deploys: there is no build step |
gio build standalone | Package a self-contained deploy directory |
gio export | Render the app to static HTML in out/ |
gio routes | List every route the app serves |
gio typegen | Write .gio/routes.d.ts without starting the server |
gio doctor | Check the environment and project, with a fix for each problem |
gio info | Print versions and environment details for bug reports |
gio cache explain | Explain how the cache served a URL |
gio bench | Load-test a running server |
gio migrate | Migrate a Next.js app (runs create-giojs migrate) |
gio add | Add starter features to the app (runs create-giojs add) |
gio help | The command list, one command's options, --version |
giojs-server | Start the server with the caller's NODE_ENV; --check-config validates the configuration |
create-giojs | Scaffold a new app (npm create giojs@latest) |
gio --help # the command list
gio help dev # one command's options (same as: gio dev --help)
gio --version # CLI, server binary and @gio.js/core package versions (-v)In a project, run gio through your package manager (npx gio, pnpm gio) or from a package.json script. A mistyped command or option is an error with a suggestion (gio strat → did you mean gio start?), never a silently started server. gio with no command prints the help and exits with code 2.
Exit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | The command failed: the server exited with an error (its own exit code is passed through), gio doctor found an error, no server binary, a route conflict, an unreachable server |
2 | Usage error: unknown command or option, missing or malformed argument |
Every command keeps this contract, including the ones that parse their own options (gio build standalone, gio bench, gio migrate and gio add): a usage error exits with 2 before the command does anything. An argument a command does not take is one too, after --help or --version as well: gio --version --bogus and gio help dev extra exit with 2. --help wins only over arguments that parse (gio bench / --help prints the help).
gio --version prints package versions, read from the installed package.json files: gio is @gio.js/server's version, the server binary its platform package's (a binary from GIO_SERVER_BIN or a repository build prints its path instead), and @gio.js/core its own. It never runs the binary. See gio --version.
gio dev
gio dev [--port <port>] [--host <ip>] [--open]Starts the server with NODE_ENV=development and prints the local and network URLs once the worker is ready. The listen address comes from --port / --host (or GIO_PORT / GIO_HOST), then PORT - from the environment or the .env files - then gio.toml, then 0.0.0.0:3000. See gio dev.
Dev mode file watching
The whole project is watched: changes in app/, source files elsewhere and root config files restart the Node worker and reload open tabs, and edits under public/ only reload the browser. A gio.toml edit restarts the worker too, but its settings do not apply: the Rust server reads gio.toml (and the .env files) once, at startup, so stop and start gio dev after changing it. node_modules, hidden directories and build output are never watched. The rules, and the [dev] watch / watch_ignore keys, are on the gio dev page.
gio start
gio start [--port <port>] [--host <ip>] [--open]
PORT=8080 gio start # hosting platforms that assign the portThe same with NODE_ENV=production, whatever NODE_ENV the shell has. There is no build step before it. Both commands stay in the foreground and exit with the server's code. See gio start.
gio build
gio build # explains: normal deploys have no build step
gio build standalone [--out <dir>] [--target <platform>]gio build standalone packages the app into one directory - the Rust binary, the whole Node side bundled into worker.js, prebuilt chunks, public/ and gio.toml - that runs anywhere Node is installed with node run.mjs. See gio build and Standalone Deploys.
gio export
gio export # → out/Renders every page to static HTML with the client chunks that hydrate it, for static hosts, without the Rust server. GIO_APP_DIR and GIO_OUT_DIR override the input and output directories. See gio export and Static Export.
gio routes
gio routes [--json]Lists every URL the app serves - pages with their layouts and loading / error / not-found files, route handlers with their methods, WebSocket handlers and metadata routes - discovered exactly as the server discovers them, without starting it. See gio routes.
gio typegen
gio typegen && tsc --noEmitWrites .gio/routes.d.ts and .gio/css-modules.d.ts, the declarations behind typed href(), PageProps and CSS Module imports, for CI or a project with no server running. Your tsconfig.json must list ".gio/routes.d.ts" in include. See gio typegen.
gio doctor
gio doctor [--dev | --prod] [--json]Checks Node.js, the platform binary, package versions, gio.toml (with the server's own validation), tsconfig.json, the session secret, the port, trusted proxies and the cache directory, and prints a fix for every problem. Exits 1 when a check fails. See gio doctor.
gio info
gio info [--json]Prints the OS, Node.js and package manager versions, the server binary in use and the installed @gio.js/* versions. See gio info.
gio cache explain
gio cache explain <url-or-path> [--base <url>]Requests the URL and decodes its X-Gio-Cache header. A path goes to the local server at the address it listens on, or to --base. See gio cache explain.
gio bench
gio bench <url-or-path> [--connections 32] [--duration 10] [--warmup 2]
gio bench --suite /,/posts/1 [--base <url>]A zero-dependency load generator. See gio bench and Benchmarks.
gio migrate
gio migrate ./my-next-app [--dry-run] [-y] [--config <file>]Migrates a Next.js project in place and writes MIGRATION_REPORT.md, by running create-giojs migrate (the installed one, else the same version through npx / pnpm dlx / bunx). See gio migrate and the Migration Guide.
gio add
gio add tailwind auth [--dry-run] [--force]Adds starter features (tailwind, api, auth, db, docker, ci) by running create-giojs add. See gio add.
Environment variables
| Variable | Used by | Effect |
|---|---|---|
GIO_SERVER_BIN | dev, start, build standalone, doctor, info, cache explain, bench, --version, giojs-server | Use this giojs-server binary instead of the installed platform package (a source build, a custom target) |
GIO_APP_DIR | all | The app/ directory; the project root is its parent |
GIO_PORT / PORT / GIO_HOST | dev, start, cache explain, bench, doctor | The listen address (--port / --host set the GIO_* ones) |
NODE_ENV | export, routes, typegen, doctor, giojs-server | development selects development mode and the .env.development* files; gio dev / gio start set it themselves |
GIO_ENV_FILES | all that read .env files | 0 loads no .env files, 1 loads them whatever [env] files says; any other value is the error the server refuses to start with (gio doctor reports it) |
GIO_OUT_DIR, GIO_SITE_URL | export | The output directory; the site origin for sitemap.xml |
GIO_STANDALONE_SERVER_BIN | build standalone | The binary to package, over --target |
Every variable the server itself reads is listed under Environment Variables.
When the server binary is missing
The Rust server ships as an optional dependency picked by OS and CPU (@gio.js/server-linux-x64, -linux-x64-musl, -darwin-arm64, -darwin-x64, -win32-x64). When it is missing, every command that needs it says which package to install, for your package manager:
gio: the GioJS server binary for linux-x64 is not installed.
Install it: npm install --save-optional @gio.js/server-linux-x64@0.1.0-beta.8
@gio.js/server ships its Rust binary in @gio.js/server-linux-x64, an optional
dependency picked by OS and CPU. It is usually missing because:
- optional dependencies were skipped (--no-optional, --omit=optional,
or omit=optional in .npmrc)
- the lockfile was written on another OS and left this platform out:
delete node_modules and the lockfile, then install again
- node_modules was copied from another machine or OS
Or point GIO_SERVER_BIN at a giojs-server binary you built.Linux on ARM64 has no prebuilt binary yet: build one with cargo build --release -p giojs-server (Rust 1.89 or newer) and point GIO_SERVER_BIN at it, or run the app in a linux-x64 container. A GIO_SERVER_BIN that points at a missing file is reported as such. gio export, gio routes, gio typegen, gio migrate and gio add do not need the binary.
giojs-server
The giojs-server bin starts the server with no command parsing: it keeps the caller's NODE_ENV and passes its arguments to the binary (which takes only --check-config: any other argument exits with 2), as the scripts of scaffolded projects use it (cross-env NODE_ENV=development giojs-server). See giojs-server.
giojs-server --check-config
giojs-server --check-config
{"cacheDir":"/srv/app/.gio/cache/pages","configFile":"gio.toml","envFiles":[".env"],"envFilesDisabledBy":null,
"errors":[],"listen":{"host":"0.0.0.0","port":3000,"portSource":"default","tls":false},"mode":"production",
"ok":true,"proxyHeaders":"x-forwarded","rateLimitRules":0,"sessionGuards":1,"sessionSecret":"valid",...}Loads the .env files and gio.toml exactly as startup does, runs the same validation, prints a JSON report and exits - 0 when the server would start, 1 with the reasons in errors - without binding a port or starting a worker. The fields are described on the giojs-server page.
create-giojs
npm create giojs@latest [directory] -- [options]Scaffolds a new project, asking on a terminal for whatever the flags leave open: language (--ts / --js), server app or static site (--server / --static), starter features (--tailwind, --api, --auth, --db, --docker, --ci), and whether to install. Every flag, prompt and exit code is on create-giojs.
Adding features to an existing app
Adds starter features to an existing project without overwriting files you changed; gio add runs it. See create-giojs add.