gio.config.ts
The optional project-root file for what only JavaScript can express: Node plugins that run around every request the worker handles.
gio.config.ts
import { defineConfig } from '@gio.js/core';
import { requestTimer } from './lib/request-timer';
export default defineConfig({
plugins: [requestTimer],
});Reference
File name and location
gio.config.ts or gio.config.js (.ts first) in the project root, next to app/. Without one, GioJS runs with no plugins.
Its default export is a GioConfig; plugins is currently its only key. Every key, the plugin interface and its hooks are documented on gio.config.ts reference.
gio.config.ts or gio.toml?
| Setting | File |
|---|---|
Node plugins (onRequest, onResponse, onStartup, onShutdown) | gio.config.ts |
| Server, cache, security, images, fonts, rate limits, rules and every other setting | gio.toml |
| Redirects, rewrites, headers and guards computed in code | middleware.ts |
Behavior
- Loaded by the Node worker when it starts, by every worker of a pool, and again whenever a worker restarts. In development, saving the file restarts the worker.
- Strict. The default export is checked when the worker starts. A mistake makes the worker exit with one of these errors in the log, and the server does not start (it reports that it could not connect to the worker):
text
gio.config.ts: unknown key "plugin" - did you mean "plugins"? (gio.config takes plugins; server settings belong in gio.toml)
gio.config.ts: plugins must be an array of plugins
gio.config.ts: plugins[0] must be a plugin object with a name
gio.config.ts: the default export must be an object - export default defineConfig({ ... })- Server-only. The file never reaches a browser bundle, so plugins may use secrets and Node APIs.
Examples
A plugin that times renders
lib/request-timer.ts
import type { GioNodePlugin } from '@gio.js/core';
const started = new Map<string, number>();
export const requestTimer: GioNodePlugin = {
name: 'request-timer',
version: '1.0.0',
async onRequest(req) {
started.set(req.id, performance.now());
return req;
},
async onResponse(req, res) {
const start = started.get(req.id);
started.delete(req.id);
if (start === undefined) return res;
return { ...res, headers: { ...res.headers, 'server-timing': `render;dur=${(performance.now() - start).toFixed(1)}` } };
},
};An onResponse hook needs the whole body, so while one is registered pages are rendered completely instead of streamed.
Good to know
- Unlike
next.config.js, this file holds no server settings: ports, caching, headers, images and the rest are ingio.toml, which the Rust server reads. An unknown key here is an error, not a no-op. - Plugins run in the order of the array. An
onRequestthat returns a response answers the request without rendering. - An
onRequesthook that throws answers that request with500and the bodyInternal Server Error (plugin: <name>). AnonResponsehook that throws is logged and skipped: the response goes out as it was before that hook. Neither takes the worker down.
Related
- gio.config.ts reference - every key and hook.
defineConfig- Configuration: gio.config.ts
- gio.toml, middleware.ts
Version history
| Version | Changes |
|---|---|
v0.1.0-beta.8 | Validated at startup: unknown keys and plugins without a name are errors. defineConfig and the GioConfig type. |
v0.1.0-beta.1 | Introduced, as gio.config.ts or gio.config.js, with Node plugins. |