Application configuration
Understand what belongs in tavo.config.ts, what belongs in vite.config.ts, and how to extend either file without discarding existing behavior.
Start from the generated configuration
Use Node.js 20.19+ or 22.12+ and run commands from the project root. A generated project already contains both configuration files. Edit those files in place instead of replacing them with an example from another project.
| File | Read by | Responsibility |
|---|---|---|
tavo.config.ts | Tavo.js | Routes, CSS entries, plugins, diagnostics, build policy, and SSR behavior. |
vite.config.ts | Vite through Tavo.js | Vite server, resolve, dependency, and bundler settings while preserving Tavo.js's TSX and build plugins. |
tsconfig.json | TypeScript | Typechecking and Tavo.js's automatic TSX runtime configuration. |
Configure framework behavior in tavo.config.ts
defineConfig preserves literal types and catches unsupported top-level fields. Paths are relative to the project root. Keep every existing plugin and CSS entry when adding another integration. Tavo.js has one framework configuration file at the project root; imported and computed values are evaluated consistently by development, build, inspection, and production.
tsimport { defineConfig } from "@tavojs/core/config";
import { tavoUi } from "@tavojs/ui/plugin";
export default defineConfig({
pagesDir: "src/pages",
cssEntries: ["src/styles.css"],
diagnostics: {
devOverlay: true,
traces: false
},
build: {
prerenderStyles: "inline",
budgets: {
firstLoadJs: "150kb",
routeJs: "40kb"
}
},
ssr: {
trustedHosts: ["example.com"],
canonicalOrigin: "https://example.com"
},
plugins: [tavoUi()]
});Top-level TavoConfig reference
These are all accepted top-level TavoConfig properties in tavo.config.ts. defineConfig rejects any other top-level key at typecheck time. Every property is optional, but the file and its default defineConfig export are required.
tsimport { defineConfig } from "@tavojs/core/config";
export default defineConfig({
pagesDir: "src/pages",
cssEntries: ["src/styles/app.scss"],
diagnostics: {
devOverlay: true,
traces: false
},
ssr: {
canonicalOrigin: "https://example.com"
}
});| Property | Accepted value | Default | What it changes |
|---|---|---|---|
pagesDir | string | src/pages | Sets the project-root-relative directory scanned for pages, layouts, route groups, and special route modules. |
cssEntries | string[] | Existing files among src/styles.css, src/styles.scss, src/app.css, and src/app.scss | Sets project-root-relative global CSS or Sass entries loaded by development, client build, and SSR. |
plugins | PluginUse[] | { use: PluginUse[]; overrides?: PluginOverride[] } | No app plugins | Installs Plugin API v1 integrations. Use the array form for normal installs and the object form only when public overrides are needed. |
diagnostics | { devOverlay?: boolean; traces?: boolean } | Omitted; generated apps set { devOverlay: true, traces: false } | Sets development error-overlay and framework trace preferences. |
build | { prerenderStyles?: "inline" | "external"; budgets?: { … } } | { prerenderStyles: "inline", budgets: {} } | Controls prerendered CSS delivery and JavaScript budget enforcement. |
ssr | Tavo.js SSR options | Runtime defaults shown below | Configures page-runtime behavior, Node requests, response caching, the HTML document, and image optimization. |
Diagnostics and build properties
| Property | Accepted value | Default | What it changes |
|---|---|---|---|
diagnostics.devOverlay | boolean | Generated apps: true | Enables or disables the development error-overlay preference. |
diagnostics.traces | boolean | Generated apps: false | Enables or disables detailed framework diagnostic traces. |
build.prerenderStyles | "inline" | "external" | inline | Inlines collected route styles into prerendered HTML or writes references to external build assets. |
build.budgets.firstLoadJs | number | byte-size string | No limit | Fails the production build when JavaScript needed for a route's first load exceeds this number of bytes. |
build.budgets.routeJs | number | byte-size string | No limit | Fails the production build when JavaScript attributed to one route exceeds this number of bytes. |
Budget strings accept bytes or the case-insensitive units b, kb, kib, mb, and mib; decimal strings such as 1.5mb are valid. Numeric values are bytes. CLI flags override the file for one build.
bashnpx tavo build --max-first-load-js 150kb --max-route-js 40kb
npx tavo build --prerender-styles externalSSR and page-runtime properties
The ssr object accepts the following properties. The CLI supplies discovered route modules and compiles top-level plugins, so most applications configure only origin security, rendering, caches, or images here.
| Property | Accepted value | Default | What it changes |
|---|---|---|---|
ssr.canonicalOrigin | absolute HTTP(S) origin string | Origin derived from the request Host over HTTP | Sets the public origin behind TLS termination. Credentials, paths, queries, and fragments are rejected; its host is also trusted for actions. |
ssr.trustedHosts | string[] | Localhost variants, plus canonicalOrigin when configured | Allows Host values used to validate Node action and plugin mutation requests. Entries may include a hostname or host with port. |
ssr.allowExternalRedirects | boolean | false | Allows route and middleware redirects to absolute HTTP(S) URLs. Relative same-origin paths remain allowed without it. |
ssr.stream | boolean | false | Streams the SSR response instead of buffering the completed document. |
ssr.maxRequestBodyBytes | number | 10 MiB | Limits buffered non-GET request bodies in the Node handler. Requests above the limit receive 413. |
ssr.maxResolvedCacheEntries | finite non-negative number | 1,024 | Limits the process-local route-resolution data cache. Values are floored; 0 disables reuse. |
ssr.staticCache | SsrStaticCache | Process-local memory cache with 1,024 entries | Stores rendered responses for static and revalidated routes. Supply an adapter for shared or durable caching. |
ssr.document | RenderDocumentOptions | Document defaults shown below | Sets the shared HTML shell, attributes, serialized initial state, CSP nonce, and style registry. |
ssr.images | ImageOptimizerOptions | Optimizer defaults shown below | Configures /_tavo/image, local and remote sources, transform limits, formats, and memory caching. |
ssr.getPageProps | () => Record<string, unknown> | No extra props | Adds application-owned props to page components on each runtime render. |
ssr.notFound | Component<{ pathname: string }> | Discovered src/pages/404 module | Overrides the application-wide not-found component supplied by file routing. |
ssr.csrFallback | Child | ({ pathname, params }) => Child | null | Renders fallback content when a CSR route is resolved by the browser before its route module is ready. |
ssr.csrActions | CsrActionsOptions | Disabled | Maps browser form submissions for static CSR delivery to an action backend. Nested properties are listed below. |
ssr.middleware | PageMiddleware[] | [] | Runs application-wide middleware around every route in addition to discovered layout and page middleware. |
ssr.i18n | I18nService | Registered default i18n service, otherwise none | Supplies locale detection, localized path resolution, and locale state to the pages runtime. |
ssr.instrumentation | { emit(event: TavoInstrumentationEvent): void } | None | Receives route resolve, middleware, loader, action, and cache lifecycle events. Listener failures do not interrupt framework work. |
ssr.modules | PageModules | Generated route-module map | Overrides file-discovered modules. This is an advanced manual-runtime hook; normal applications leave it unset. |
CSR action properties
Configure ssr.csrActions when a statically hosted CSR application should submit Tavo.js forms to a separate action server. resolveUrl takes precedence over baseUrl.
| Property | Accepted value | Default | What it changes |
|---|---|---|---|
ssr.csrActions.enabled | boolean | false | Intercepts eligible non-GET forms and enables action URL mapping. |
ssr.csrActions.baseUrl | string | Current origin and route path | Resolves the route pathname and query against a separate action-server base URL. |
ssr.csrActions.resolveUrl | ({ pathname, search, form? }) => string | Uses baseUrl, then the route path | Computes the complete action request URL for each route or form. |
ssr.csrActions.credentials | RequestCredentials | include | Sets the Fetch credentials mode used for intercepted form submissions. |
ssr.csrActions.headers | HeadersInit | ({ pathname, form }) => HeadersInit | No additional headers | Adds fixed or per-form request headers to the action fetch. |
tsimport { defineConfig } from "@tavojs/core/config";
export default defineConfig({
ssr: {
csrActions: {
enabled: true,
baseUrl: "https://actions.example.com",
credentials: "include",
headers: ({ pathname }) => ({
"X-Tavo.js-Route": pathname
})
}
}
});HTML document properties
ssr.document sets defaults for the server-rendered document shell. Route head exports and Tavo.js SEO components can refine metadata per route.
| Property | Accepted value | Default | What it changes |
|---|---|---|---|
ssr.document.lang | string | en | Sets the escaped html lang attribute. |
ssr.document.title | string | No title | Sets the escaped fallback document title. Route SEO metadata takes precedence. |
ssr.document.unsafeHeadHtml | string | Empty | Appends trusted raw HTML to head. It is not escaped; prefer TSX metadata for all structured head content. |
ssr.document.htmlAttributes | Record<string, string | number | boolean> | {} | Adds escaped safe-name attributes to html. false omits an attribute and true renders a boolean attribute. |
ssr.document.bodyAttributes | Record<string, string | number | boolean> | {} | Adds escaped attributes to body. |
ssr.document.appAttributes | Record<string, string | number | boolean> | {} | Adds escaped attributes to the application container. |
ssr.document.doctype | string | <!doctype html> | Sets the exact doctype prefix written before the html element. |
ssr.document.appContainerId | string | app | Sets the escaped id of the application container used by hydration. |
ssr.document.initialState | unknown | Omitted | Serializes JSON into a protected application/json script after the app container. |
ssr.document.stateScriptId | string | __TAVO_STATE__ | Sets the escaped id of the serialized initial-state script. |
ssr.document.nonce | string | None | Adds a CSP nonce to generated state and style elements. |
ssr.document.beforeRender | () => void | None | Runs immediately before server rendering. Use only for request-safe setup. |
ssr.document.styleRegistry | StyleRegistry | A new registry for each render | Supplies a custom style collector with add, has, and entries methods. |
Image optimizer properties
| Property | Accepted value | Default | What it changes |
|---|---|---|---|
ssr.images.enabled | boolean | true | Enables the /_tavo/image optimization endpoint. |
ssr.images.allowRemote | boolean | false | Allows remote HTTP(S) image sources, still subject to remotePatterns and network safety checks. |
ssr.images.remotePatterns | Array<string | { protocol?, hostname, port?, pathname? }> | [] | Allowlists remote origins or host/path patterns. A hostname beginning with *. matches subdomains only. |
ssr.images.publicDir | string | public | Sets the project-root-relative source directory for local images. |
ssr.images.quality | number | 75 | Sets fallback output quality; request values are clamped from 1 through 100. |
ssr.images.cacheMaxAge | number | 31,536,000 seconds | Sets the Cache-Control max-age of transformed image responses. |
ssr.images.defaultFormat | "webp" | "avif" | "jpeg" | "png" | "original" | webp | Sets the output format when the optimization URL does not request one. |
ssr.images.sizes | number[] | [320, 640, 960, 1280, 1600] | Sets the candidate widths and supplies the fallback width for an optimization request. |
ssr.images.timeoutMs | number | 5,000 | Limits remote fetch duration. |
ssr.images.maxBytes | number | 10 MiB | Rejects local or remote source images larger than this byte limit. |
ssr.images.memoryCacheMaxEntries | number | 128 | Limits transformed images stored in process memory. Values are floored; 0 disables storage. |
ssr.images.maxConcurrentTransforms | number | 4 | Limits simultaneous Sharp transforms; values are floored with a minimum of 1. |
ssr.images.maxPendingTransforms | number | 64 | Limits queued transforms before the optimizer returns a busy error. |
ssr.images.allowInsecureRemote | boolean | false | Allows HTTP remote image URLs. Keep disabled unless the transport risk is explicitly accepted. |
ssr.images.resolveHostname | (hostname: string) => Promise<Array<{ address: string }>> | Node DNS lookup | Overrides DNS resolution used by private-network protection. Intended for adapters and controlled tests. |
tsimport { defineConfig } from "@tavojs/core/config";
export default defineConfig({
ssr: {
images: {
allowRemote: true,
remotePatterns: [
{
protocol: "https:",
hostname: "images.example.com",
pathname: "/products"
}
],
defaultFormat: "avif",
quality: 80
}
}
});Server image transforms require the optional sharp dependency in the application that runs SSR. Remote requests are checked against the allowlist, redirects, DNS results, private-network addresses, timeout, and byte limit.
SsrStaticCache adapter
Use the public SsrStaticCache interface from @tavojs/core/server when rendered static and revalidated responses must be shared across processes or persisted outside Node memory. Methods may return values directly or through promises.
tsimport type {
SsrStaticCache,
SsrStaticCacheEntry
} from "@tavojs/core/server";
const entries = new Map<string, SsrStaticCacheEntry>();
export const staticCache: SsrStaticCache = {
get(key) {
return entries.get(key) ?? null;
},
set(key, entry) {
entries.set(key, entry);
},
delete(key) {
entries.delete(key);
},
invalidateTags(tags) {
const requested = new Set(tags);
let deleted = 0;
for (const [key, entry] of entries) {
if (entry.tags.some((tag) => requested.has(tag))) {
entries.delete(key);
deleted += 1;
}
}
return deleted;
},
clear() {
entries.clear();
}
};SsrStaticCacheEntry contains the rendered response, an absolute expiresAt timestamp or null, and its cache tags. The built-in createMemoryStaticCache is available from @tavojs/core/server. The Map above illustrates the contract; use a shared cache implementation for multi-process production deployments.
Configuration loading behavior
tsimport { loadTavoConfig } from "@tavojs/core/dev";
const config = await loadTavoConfig(process.cwd(), {
mode: "development"
});
console.log(config.pagesDir);| Concern | Contract |
|---|---|
| Location | Exactly one tavo.config.ts at the project root. |
| Export | A default export returned by defineConfig({ … }). A plain object is rejected. |
| Evaluation | Imported and computed values are supported. The file is evaluated once per project root and process. |
| Environment | .env files are loaded before evaluation. The explicit mode wins, then NODE_ENV, then production. |
| Mode safety | One project root cannot be reevaluated in a different mode in the same process. |
| Failure | A failed load is not cached, so the next command or retry can load a corrected file. |
Keep Tavo.js's Vite wrapper
defineTavoViteConfig installs Tavo.js's TSX transform, file-route build guards, SVG support, localization splitting, and plugin build contributions. Pass your Vite settings into the wrapper rather than replacing it with Vite's defineConfig.
tsimport { defineTavoViteConfig } from "@tavojs/core/config";
export default defineTavoViteConfig(({ mode }) => ({
server: {
port: mode === "development" ? 4174 : undefined
},
build: {
sourcemap: mode !== "production"
}
}));Verify the result
bashnpx tavo info
npx tavo check
npm run buildinfo shows the resolved pages and CSS configuration, check reports route and project-shape problems, and the production build exercises both client and server configuration. If a plugin was added, run npx tavo inspect plugins as well.
Look up exact public types
Follow linked API names to their canonical TypeScript declarations and package boundaries.