Configuration

Keep deployment identity and supported resources in one Node-loadable config file.

On this page

goribu.config.js

Default-export the result of defineConfig() from goribu/server:

goribu.config.js
import { defineConfig } from "goribu/server";

export default defineConfig({
  name: "my-app",
  compatibilityDate: "2026-09-01",
  database: { type: "d1", name: "my-app-db" },
  kv: { name: "my-app-kv" },
});
  • Optional resources: D1 and KV declarations are optional.
  • Node-loadable config: Keep goribu.config.js plain JavaScript, including in TypeScript apps. Node loads it directly; do not import JSX, a Document, or application components.

Options and defaults

OptionMeaning and default
nameRequired Worker name. Lowercase letters, digits, and hyphens; no leading or trailing hyphen; at most 63 characters.
domainOptional application hostname connected during deployment. Omitted means no domain management. Available since 0.9.0.
workersDevOptional boolean. false turns off the workers.dev address and requires domain. Defaults to true. Available since 0.9.2.
compatibilityDateRequired real date in YYYY-MM-DD format.
compatibilityFlagsOptional array of Workers compatibility flags. Defaults to an empty array.
databaseOptional single D1 declaration. Omitted means no D1 binding.
kvOptional single KV namespace. Omitted means no KV binding.
responseHeadersOptional synchronous callback for Worker response defaults.
  • Unknown fields: Goribu rejects unknown configuration fields.
  • Generated configuration: Edit goribu.config.js rather than generated goribu.wrangler.jsonc or production output.

Custom domain

Available in Goribu 0.9.0. The top-level domain option connects an application hostname during deployment.

Add one line to connect your application to a custom hostname:

goribu.config.js
import { defineConfig } from "goribu/server";

export default defineConfig({
  name: "my-app",
  compatibilityDate: "2026-10-02",
  domain: "app.example.com",
});
  • Hostname format: Use one bare hostname: a zone apex such as example.com or subdomain such as app.example.com. Goribu normalizes it to lowercase.
  • Rejected hostnames: Schemes, paths, ports, IP addresses, wildcards, and Cloudflare-managed workers.dev or r2.dev addresses are rejected.
  • Zone ownership: The hostname must belong to an active Cloudflare zone in the deployment account. Goribu finds the zone automatically.
  • Browser login: Normal goribu cloudflare-login works for custom domains. No separate DNS Read permission is required.
  • API tokens: Include Workers Scripts Write and Zone Read for the target zone alongside the app's other deployment permissions.
  • Connection preview: pnpm check previews a domain connection without changing resources.
  • Attachment order: pnpm run deploy checks ownership before provisioning, uploads the Worker, then checks again and attaches the hostname. For a new Worker, the domain conflict preview runs after its first upload.
  • Existing assignments: A connection to this Worker is reused. Conflicting assignments block the operation; Cloudflare's replacement overrides remain disabled.
  • Activation: Cloudflare creates DNS records and a TLS certificate. Activation may still be pending after attachment.
  • Attachment failure: If connection fails after upload, the Worker remains deployed and the command reports an error. Resolve the problem and retry deployment.
  • Other addresses: The workers.dev address remains available unless you turn it off. Other attached domains also remain available.
  • Old hostnames: Changing or removing domain never disconnects an old hostname. Other attachments are listed as information.
  • Alias management: Manage aliases such as www, redirects, and unwanted connections separately in Cloudflare.
  • Media hostname: Use a different hostname for r2.domain, which serves bucket files.
  • Upload CORS: The planned application origin is included in R2 direct-upload CORS before domain attachment.
  • Local validation: Development and standalone builds validate the hostname without contacting Cloudflare.

workers.dev address

Available in Goribu 0.9.2. Every app is also served at https://<name>.<account-subdomain>.workers.dev. Once the app has its own domain, that second address may be unwanted: OAuth callbacks, cookies, and CORS are tied to one host. Turn it off with workersDev: false:

goribu.config.js
import { defineConfig } from "goribu/server";

export default defineConfig({
  name: "my-app",
  compatibilityDate: "2026-10-02",
  domain: "app.example.com",
  workersDev: false,
});
  • Required domain: workersDev: false requires domain; otherwise the app would have no address.
  • Setting ownership: Each deploy applies workersDev. Remove the field to restore workers.dev rather than changing the dashboard setting.
  • Activation timing: Keep the default until the custom domain is connected and serving. DNS and TLS may need a few minutes; workers.dev works immediately.
  • Upload origin: R2 direct-upload CORS drops the workers.dev origin when that address is disabled.
  • Preview URLs: Deploys always turn off Cloudflare's per-version preview URLs. Goribu deploys production only; previews would be additional public app addresses.
  • One-time warning: The first deploy disabling preview URLs on an existing Worker may print a Wrangler warning. No action is needed.

Resources

  • D1 fields: A D1 declaration accepts type: "d1", name, and optional replication.
  • KV fields: A KV declaration accepts only name.
  • Resource names: D1 and KV names may contain lowercase letters, digits, hyphens, and underscores. Start with a letter or digit and use at most 63 characters.

Goribu owns the DB and KV bindings. You do not supply resource IDs or duplicate them in a Wrangler file.

  • Replication default: Omitted replication enables it on new D1 databases and leaves existing settings untouched.
  • Replication reconciliation: Explicit true or false reconciles replication during deployment. See D1 and KV.
  • Resource selection: Changing a resource name selects a different resource. It does not rename or delete the previous resource.
  • Declaration removal: Removing a declaration leaves the production resource intact.

Environment variables

Use .env for local values and .env.local for local overrides:

.env
CATALOG_API_TOKEN=local-placeholder
PUBLIC_API_ORIGIN=https://api.example.com
  • Server values: Read server values through req.env in handlers or middleware.
  • Browser values: Only PUBLIC_* variables are available to browser code through import.meta.env. Values are embedded at build time and must not contain secrets.
Server code
import type { Handler } from "goribu/server";

type Env = { CATALOG_API_TOKEN: string };

// Keep this value on the server; never return it in page props.
export const GET: Handler<Record<string, unknown>, Env> = (req, res) => {
  const token = req.env.CATALOG_API_TOKEN;
  return res.json({ configured: Boolean(token) });
};
Server code
// Keep this value on the server; never return it in page props.
export const GET = (req, res) => {
  const token = req.env.CATALOG_API_TOKEN;
  return res.json({ configured: Boolean(token) });
};
Browser code
// In browser-reachable application code; this value is public.
const apiOrigin = import.meta.env.PUBLIC_API_ORIGIN;
Browser code
// In browser-reachable application code; this value is public.
const apiOrigin = import.meta.env.PUBLIC_API_ORIGIN;
  • Worker-specific file: Cloudflare supports .dev.vars for local Worker bindings.
  • File precedence: If .dev.vars exists, even empty, it replaces loading of both .env and .env.local for the server. Choose one workflow; these files do not merge.
  • Local secrets exclusion: Build output never contains local server values.
  • Build log wording: Cloudflare's Vite plugin still prints "Using secrets defined in .env" during a build. Since 0.9.2, Goribu removes that local copy before output is written, so nothing local is uploaded.
  • Server build constants: import.meta.env.DEV, PROD, and MODE work in handlers and server modules.
  • Development guards: Vite replaces these values with constants. Production builds drop code that runs only when DEV is true; use this for development-only routes:
src/routes/dev-login.ts
import type { Handler } from "goribu/server";

// src/routes/dev-login.ts
export const POST: Handler = async (req, res) => {
  if (import.meta.env.DEV) {
    req.cookies.set("session", await createDevSession(req), { path: "/", httpOnly: true });
    return res.redirect("/");
  }
  return res.notFound();
};
src/routes/dev-login.js
// src/routes/dev-login.js
export const POST = async (req, res) => {
  if (import.meta.env.DEV) {
    req.cookies.set("session", await createDevSession(req), { path: "/", httpOnly: true });
    return res.redirect("/");
  }
  return res.notFound();
};
  • Browser mode files: Browser values follow Vite's .env, .env.local, .env.development, .env.production, and mode-specific local overrides.
  • Server mode distinction: A value in .env.development does not become a server binding just because Vite can see it.

Production secrets

  • Production source: Put production values in .env.production. Deployment validates it with Wrangler and uploads its keys as Worker secrets.
  • Existing secrets: Existing secrets omitted from .env.production remain on the Worker.
  • Missing file: Without .env.production, Goribu uses existing platform secrets. Local .env is never an upload fallback.
  • Public prefix: A PUBLIC_* value stays public even when the same key is uploaded as a Worker secret.
  • Shared placeholders: Keep real environment files out of Git. Share placeholder names in .env.example.

Config evaluation does not load dotenv files into process.env. If the config reads an environment variable, supply it in the shell running the command.

Response headers

Use a callback for defaults on Worker-served responses:

goribu.config.js
import { defineConfig } from "goribu/server";

export default defineConfig({
  name: "my-app",
  compatibilityDate: "2026-09-01",
  // Return ordinary header values synchronously.
  responseHeaders({ request, env, mode, nonce }) {
    return { "X-Content-Type-Options": "nosniff" };
  },
});
  • Callback arguments: responseHeaders receives the original Request, Worker environment, development/production mode, and request nonce.
  • Return contract: Return a plain object of strings or arrays of strings synchronously.
  • Header precedence: Route and framework headers take precedence over callback defaults. Vary tokens merge.
  • Worker-rendered static pages: A static page rendered by the Worker, in development or after a pre-render fallback, receives these headers and keeps its nonce. Prerendered HTML has neither.
  • Disallowed defaults: Body, redirect, cookie, and transport headers cannot be blanket defaults: Content-Type, Content-Length, Content-Range, Content-Encoding, Location, Set-Cookie, Trailer, and Transfer-Encoding.
  • Response ownership: Set those headers through the API that owns the response.
  • Static Assets: responseHeaders does not run for Static Assets. App-authored public/_headers is rejected, so this API cannot establish a custom static-page header policy.
  • Security policy defaults: Goribu does not set a default CSP or CORS policy.

Development and build settings

  • Vite configuration: Put Vite options in vite.config.js, not the Goribu app config. Keep goribu() in the plugins list.
  • CSS tooling: Tailwind is an app plugin. Ordinary CSS works too.
  • Config reloads: Changes to goribu.config.js or vite.config.js restart the development session.
  • Invalid replacements: Invalid replacement config is reported while the existing session continues. Fix it before relying on new settings.
  • Undiscovered routes: Restart pnpm dev if a newly added route is not recognized.

Import aliases

Add import aliases through Vite's resolve.alias option in vite.config.js. This example maps @ to your src directory using an absolute path. Merge it into your existing config, keeping any other plugins and settings:

vite.config.js
import { fileURLToPath } from "node:url";
import { goribu } from "goribu/vite";

export default {
  plugins: [goribu()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
};
  • Alias usage: Application code can use import Button from "@/components/button" for src/components/button.tsxsrc/components/button.jsx.
  • Alias scope: Vite aliases apply during development and production builds.
  • Config imports: Keep goribu.config.js imports Node-compatible. Node loads that file directly without Vite aliases.