GioJSdocs
On this page

gio doctor

Check the environment and the project for what most often breaks a GioJS app, with a fix for every problem. Exits 1 when a check fails.

npx gio doctor
bash
gio doctor [--dev | --prod] [--json]

Reference

OptionTypeDefaultDescription
--devboolean-Check the development configuration: what gio dev runs (.env.development*, the ephemeral session secret).
--prodboolean-Check the production configuration: what gio start runs. A production-only problem is an error, even when NODE_ENV is unset.
--jsonbooleanfalsePrint { ok, mode, environment, checks } instead of the report (see JSON output).
-h, --helpboolean-Print the help and exit with 0.

--dev and --prod together are a usage error. Without either, NODE_ENV decides, as it does for the server: development when it is development, production otherwise. When production is only assumed because NODE_ENV is unset (or something else), problems that gio dev would not have are warnings, not errors.

Checks

IdChecksFails (error) when
nodeThe Node.js versionOlder than GioJS needs (>=20). Outside your package.json engines is a warning.
binaryThe server binary in useNone is found; the detail names the package for this platform and how to install it.
versions@gio.js/server, its platform binary, @gio.js/core, @gio.js/react@gio.js/core is missing, or the server, binary and core are not one version. A different @gio.js/react is a warning.
appThe app/ directoryIt does not exist (run from the project root or set GIO_APP_DIR).
configgio.toml, validated by the server binary itself through --check-configThe server would refuse to start. Protections the file turns off are warnings, with the server's own text.
tsconfigtsconfig.json or jsconfig.jsonNever: missing .gio/routes.d.ts in include is a warning.
sessionGIO_SESSION_SECRET for require_session guards (in gio.toml or middleware.ts)The secret is invalid (each comma-separated secret needs 32 bytes), or guards exist and it is unset in production. Development uses an ephemeral secret (info).
portWhether the listen address can be boundNever: in use, a privileged port or no IPv6 are warnings.
proxy[server] trusted_proxiesNever: deploy files (Dockerfile, fly.toml, Procfile, nginx.conf, ...) or rate limits with no trusted proxy give a hint.
cacheThe page cache directoryIt (or its nearest existing parent) is not writable.

Each check has a status: ✓ ok, i info (a hint), ! warn, ✗ error, - skipped. A skipped check says why in its title. The config check is skipped when no binary of the CLI's own version is available (a different version may not know the flag); the other checks then read gio.toml leniently. That reader follows dotted keys and inline tables as the server does (env.files = false and env = { files = false } turn the .env files off just like [env] files = false), and still fails the config check on an invalid GIO_ENV_FILES, with the server's own error. When it cannot read gio.toml either (a line that is not TOML, such as an unclosed [server header), the config check warns with the line numbers, and the session, port, proxy and cache checks are skipped with gio.toml could not be read (see above) instead of running on defaults.

When the server cannot read the configuration at all (gio.toml does not parse, or a .env file or GIO_ENV_FILES is invalid), the config check fails with the error, and the session, port, proxy and cache checks are skipped: - Session guards not checked: the server could not read the configuration (error above). They never pass on settings nobody could read. A configuration that parses but fails a later check (a missing TLS certificate) still gets them.

Output

text
$ npx gio doctor --prod
GioJS doctor

  gio              0.1.0-beta.8
  Node.js          22.22.0
  Platform         linux-x64 (glibc), 6.8.0-45-generic
  Package manager  npm
  Server binary    0.1.0-beta.8 (/home/me/shop/node_modules/@gio.js/server-linux-x64/bin/giojs-server)
  @gio.js/server   0.1.0-beta.8
  @gio.js/core     0.1.0-beta.8
  @gio.js/react    0.1.0-beta.8
  create-giojs     not installed
  Project          /home/me/shop
  gio.toml         gio.toml
  NODE_ENV         (unset)

Checking the production configuration (what `gio start` runs), as --prod asked.

  ✓ Node.js 22.22.0 (GioJS needs >=20)
  ✓ Server binary: @gio.js/server-linux-x64 0.1.0-beta.8
  ✓ @gio.js packages in lockstep (0.1.0-beta.8)
  ✓ App directory: /home/me/shop/app
  ✓ gio.toml is valid
  ✓ tsconfig.json includes .gio/routes.d.ts (typed routes)
  ✗ require_session guards exist but GIO_SESSION_SECRET is not set
      In production every guarded request is denied until a secret is configured.
      fix: Set GIO_SESSION_SECRET in the deploy environment. Generate one: node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
  ✓ Port 3000 is free (0.0.0.0:3000, from gio.toml)
  i Behind a reverse proxy or load balancer? Set [server] trusted_proxies
      deploy files found (Dockerfile); 1 rate limit rule(s) key on the client IP. Without it X-Forwarded-For/-Proto are ignored, so every request appears to come from the proxy: rate limits share one bucket and logs show the proxy address.
      fix: In gio.toml: [server] trusted_proxies = ["10.0.0.0/8"]  (your proxy's address or CIDR block)
  ✓ Cache directory is writable (/home/me/shop/.gio/cache/pages)

1 error, 0 warnings.

The environment half is the same report as gio info.

JSON output

FieldTypeDefaultDescription
okboolean-false when any check has status error.
modeobject-The configuration checked: name is development or production, explicit is false when production was assumed, source is --dev, --prod, NODE_ENV or null.
environmentobject-The gio info --json report.
checksobject[]-One { id, status, title, detail?, fix? } per check, in the order above. status is ok, info, warn, error or skip.
json
{
  "ok": false,
  "mode": { "name": "production", "explicit": true, "source": "--prod" },
  "environment": { "gio": "0.1.0-beta.8", "node": "22.22.0", "...": "..." },
  "checks": [
    {
      "id": "session",
      "status": "error",
      "title": "require_session guards exist but GIO_SESSION_SECRET is not set",
      "detail": "In production every guarded request is denied until a secret is configured.",
      "fix": "Set GIO_SESSION_SECRET in the deploy environment. ..."
    }
  ]
}

Examples

Gate a deploy

bash
npx gio doctor --prod || exit 1

Run it in the deploy environment, with its variables set: it fails on a missing session secret, an invalid gio.toml, mismatched package versions or a missing binary.

Check what gio dev will see

bash
npx gio doctor --dev

Attach to a bug report

bash
npx gio doctor --json > doctor.json

Secrets never appear: the session secret is reported only as set, unset or invalid.

Good to know

  • Exit codes: 0 when no check has status error (warnings and hints do not fail), 1 when one does, 2 for a usage error.
  • The listen address is the one the server would use: GIO_PORT / PORT / GIO_HOST, the .env files, then gio.toml. A port in use is only a warning, because it is often your own running server.
  • The package manager is the one running gio (from npm_config_user_agent), else the one whose lockfile the project has; the fixes use its commands.
  • gio doctor does not load gio.config.ts or import your modules. A broken plugin or a route.ts that throws shows up in gio routes and at startup.

Version history

VersionChanges
v0.1.0-beta.8Introduced, with --dev, --prod and --json. The config check reports the warnings for protections gio.toml turns off. Checks that need a configuration the server could not read are skipped with the reason, instead of passing.