giojs-server
The Rust server binary and its launcher bin: start the server with the caller's NODE_ENV, or validate the configuration with --check-config and print a JSON report.
npx giojs-server --check-configpnpm exec giojs-server --check-configyarn giojs-server --check-configbunx giojs-server --check-configgiojs-server # start the server; NODE_ENV is the caller's
giojs-server --check-config # validate .env files + gio.toml, print JSON, exitReference
Two programs share the name. @gio.js/server installs a giojs-server bin (bin/giojs-server.js), a launcher, and the platform package @gio.js/server-<platform> holds the Rust binary it runs.
| Parameter | Type | Default | Description |
|---|---|---|---|
--check-config | flag | - | Validate and exit instead of serving (see below). Recognized only on its own. |
other arguments | string | - | Passed through by the launcher and refused by the binary: it prints unexpected argument and exits with 2 (a usage error, as for gio) without starting. Everything else is configured with gio.toml and environment variables, and gio --version prints the versions. |
The launcher
giojs-server (the bin) starts the server with no command parsing, as projects scaffolded with create-giojs do from their scripts:
{
"scripts": {
"dev": "cross-env NODE_ENV=development giojs-server",
"start": "cross-env NODE_ENV=production giojs-server"
}
}- It finds the binary like
giodoes (GIO_SERVER_BIN, else the platform package) and exits with1and the package to install when there is none. - It keeps the caller's
NODE_ENV:developmentruns dev mode, anything else (or unset) production. - It tells the server where the Node worker's entry and
tsxare (GIO_NODE_SCRIPT,GIO_TSX_PKG), holds the server's stdin pipe so the server exits if the launcher dies (GIO_EXIT_ON_STDIN_EOF=1), forwardsSIGINT/SIGTERMon Unix, and exits with the server's exit code. - Unlike
gio dev/gio start, it prints no ready banner, takes no--port/--host(setGIO_PORT/GIO_HOST) and does not setNODE_ENV.
The binary
At startup the Rust binary, in order:
- loads the
.envfiles for its mode, unlessGIO_ENV_FILES=0or[env] files = false(variables already set win); - parses
gio.tomlstrictly (unknown keys are errors, with the line and the closest valid key; so is every invalid value, rule and[security]entry, all listed together) and appliesGIO_HOST/GIO_PORT/PORT; - runs the startup validation: the page cache directory's placement,
[security], the revalidation token, local[[fonts]]files and the TLS certificate and key - every problem is printed, not just the first; - logs one warning per protection
gio.tomlturns off or loosens; - spawns the Node worker(s), waits for the first to be ready, and only then binds the port.
$ npx giojs-server
giojs-server: configuration error: gio.toml:2: unknown key `server.prot` - did you mean `server.port`?
$ echo $?
1SIGINT and SIGTERM start a graceful shutdown: up to 8 seconds to drain in-flight requests, then up to 6 seconds for each worker to run its plugin onShutdown hooks (the workers stop in parallel). Give a process manager at least 14 seconds before it kills the server.
Environment variables
The binary reads these itself; app variables (GIO_SESSION_SECRET, GIO_PUBLIC_*, your own) also reach the Node worker. The full list is on Environment Variables.
| Variable | Effect |
|---|---|
NODE_ENV | development runs dev mode; anything else production. The worker runs in the same mode. |
GIO_HOST, GIO_PORT, PORT | The listen address, over [server] host / port (GIO_PORT before PORT). |
GIO_APP_DIR | The app/ directory (default app); gio.toml, public/ and the .env files are read from its parent. |
GIO_PUBLIC_DIR | The public/ directory, when it is not next to app/. |
GIO_ENV_FILES | 0 / false loads no .env files, 1 / true loads them whatever [env] files says. Any other value is a startup error. |
GIO_SESSION_SECRET | Signs sessions; required by require_session guards in production. |
GIO_REVALIDATE_TOKEN | The on-demand revalidation token, over [revalidate] token (at least 32 bytes). |
GIO_CACHE_DIR | The page cache directory, over [cache] disk_path. |
GIO_DEPLOYMENT_ID | Pins the deployment id (up to 64 characters) instead of deriving it from the code - for several instances of one release. |
GIO_LOG_FORMAT | json or text, over [logging] format. |
RUST_LOG | The log filter (default info). |
GIO_NODE_SCRIPT, GIO_TSX_PKG | The worker entry and the tsx package; the launchers set them. |
GIO_EXIT_ON_STDIN_EOF | 1: shut down when stdin reaches end of file (the launcher died). The launchers set it. |
giojs-server --check-config
Loads the .env files and gio.toml exactly as startup does, runs the same validation, prints one line of JSON on stdout and exits: 0 when the server would start, 1 when it would refuse. It never binds a port and never starts a worker, so it is safe in CI and on a production host next to a running server.
npx giojs-server --check-config
NODE_ENV=development npx giojs-server --check-config # the dev configuration
node standalone/run.mjs --check-config # a standalone buildReport
| Field | Type | Default | Description |
|---|---|---|---|
ok | boolean | - | Whether the server would start. |
errors | string[] | - | Every refusal, worded as startup prints it after configuration error:, in line order: every unknown key and section, every invalid value, rules that cannot be enforced, [i18n] mistakes, and the other checks startup makes. Rules (or [i18n] locales) holding a misspelled or invalid key are checked once it is fixed. A required key that is missing, or whose value is invalid (path = 3, or a [[rate_limits]] path that is not a valid pattern), ends the list there, and the last entry says which checks did not run. |
warnings | string[] | - | Protections the file turns off or loosens and ignored [dev] allowed_hosts entries - the same lines startup logs. |
mode | string | - | development or production, from NODE_ENV. |
envFiles | string[] | - | The .env files loaded, by name, highest precedence first. |
envFilesDisabledBy | string | null | - | What turned .env loading off: GIO_ENV_FILES or [env] files. |
configFile | string | null | - | The gio.toml read, or null when there is none (defaults apply). |
listen | object | - | { host, port, portSource, tls }. portSource is GIO_PORT, PORT, gio.toml or default. IPv6 hosts are bracketed. |
trustedProxies | number | - | Entries in [server] trusted_proxies. |
proxyHeaders | string | - | [server] proxy_headers: x-forwarded or forwarded. |
rateLimitRules | number | - | [[rate_limits]] entries. |
sessionGuards | number | - | [[guards]] in gio.toml with require_session = true (middleware.ts guards are not counted). |
sessionSecret | string | - | unset, valid or invalid for GIO_SESSION_SECRET - never its value. |
sessionSecretError | string | null | - | Why the secret is invalid. |
cacheDir | string | - | The page cache directory, absolute. |
When gio.toml cannot be parsed, the report holds only ok, errors, mode, envFiles, envFilesDisabledBy and configFile. When a .env file cannot be parsed, only ok, errors and configFile.
Worker boot errors
The Node worker loads gio.config.ts, discovers the routes and loads middleware.ts before it reports ready. When it cannot - an unknown key in gio.config.ts, two files that answer the same URL, a page whose export const revalidate is a literal the server cannot use, a middleware.ts that throws or holds a rule that cannot be enforced - it exits, and the server prints the worker's own error after the worker's log lines. A standalone build reports the same errors (its middleware.ts and gio.config are loaded at boot too, after the worker can report them):
giojs-server: the Node worker exited before it was ready (exit status: 1):
/srv/shop/middleware.ts failed to load: GIO_SESSION_SECRET is not set- Production exits
1at once, without a backtrace: the server never serves with the app's routes or rules half loaded. - Development prints the error and
waiting for a file change to start the worker again, binds no port, and starts the worker again on the next save ([dev] watch = falseexits instead). A worker that breaks after startup is respawned on the next save, and answers503meanwhile.
Examples
A valid configuration with warnings
[server]
port = 8080
max_connections = 0
[security.csrf]
enabled = false
[[guards]]
path = "/admin/*rest"
require_session = true
redirect_to = "/login"{
"cacheDir": "/srv/shop/.gio/cache/pages",
"configFile": "gio.toml",
"envFiles": [".env"],
"envFilesDisabledBy": null,
"errors": [],
"listen": { "host": "0.0.0.0", "port": 8080, "portSource": "gio.toml", "tls": false },
"mode": "production",
"ok": true,
"proxyHeaders": "x-forwarded",
"rateLimitRules": 0,
"sessionGuards": 1,
"sessionSecret": "invalid",
"sessionSecretError": "GIO_SESSION_SECRET secret #1 is 5 bytes; at least 32 are required",
"trustedProxies": 0,
"warnings": [
"[security.csrf] enabled = false: any website can send form posts and other unsafe requests to this server with your visitors' cookies - prefer listing origins in [security.csrf] trusted_origins, or public endpoints in [security.csrf] exempt",
"[server] max_connections = 0: concurrent connections are unlimited - a connection flood can exhaust file descriptors and memory"
]
}The output is one line; it is shown formatted here. ok is true although the session secret is invalid: the server starts and denies every require_session request instead. gio doctor turns that into an error.
A refused configuration
Every unknown key and section is reported in one run:
$ npx giojs-server --check-config
{"configFile":"gio.toml","envFiles":[],"envFilesDisabledBy":null,"errors":["gio.toml:2: unknown key `server.prot` - did you mean `server.port`?","gio.toml:7: unknown key [image] - did you mean [images]?"],"mode":"production","ok":false}
$ echo $?
1A syntax error is reported by line and column, without quoting the line (it may hold a token):
{"configFile":"gio.toml","envFiles":[".env"],"envFilesDisabledBy":null,"errors":["cannot parse gio.toml:1:8: invalid table header; expected `.`, `]`"],"mode":"production","ok":false}In CI
npx giojs-server --check-config > check.json || { cat check.json; exit 1; }
node -e 'const r = require("./check.json"); if (r.warnings.length) { console.log(r.warnings.join("\n")); process.exit(1); }'The second line also fails the job on any warning, for a pipeline that allows no loosened protections.
Good to know
- The report never carries a secret: not the session secret, not tokens, not
.envvalues. Errors name a key or a position, never a quoted line. gio dev,gio start,gio doctor,gio info,gio cache explainandgio benchrun--check-configto learn the listen address and validate the configuration, so no JavaScript re-implements thegio.tomlrules. An installed platform package of another version is not asked (it may predate the flag); aGIO_SERVER_BINor repository build always is. Without an answer, they readgio.tomlleniently and validate nothing.--check-configdoes not loadgio.config.ts,middleware.tsor your modules: the Node side is checked when the worker boots, and a worker that cannot boot stops startup with its own error (see Worker boot errors).- The binary has no
--helpor--version; usegio --helpandgio --version. Run it through a launcher (gio, thegiojs-serverbin, a standalonerun.mjs): started bare, it needsGIO_NODE_SCRIPTto find the worker. - Exit codes:
0after a graceful shutdown or a passing check,1for a configuration error, a failed check or a failed startup (a worker that cannot boot included), and2for any argument other than--check-config(a usage error; nothing starts).
Related
- gio.toml and its strict parsing
gio doctor- Turning Protections On and Off - the warnings explained
- When the server binary is missing
Version history
| Version | Changes |
|---|---|
v0.1.0-beta.8 | --check-config introduced. The server loads .env files, decides the worker's mode from NODE_ENV, rejects unknown gio.toml keys, reports every startup refusal at once (every unknown key in one run), and logs a warning per loosened protection. Any other argument (--version, --port) is a usage error, exit 2, where it used to be ignored and the server started. The bin became a separate launcher: gio got commands, giojs-server kept starting the server. |
v0.1.0-beta.1 | Introduced, as a second name for the gio bin. |