Frontend Configuration
Use this page to change an existing full-stack app. Complete Getting Started first, then merge only needed fields into src/config/default.ts while retaining server settings. Start with defaults and configure behaviors the product actually changes; see the VextFrontendConfig API reference for all type members.
Table of Contents
- Minimal Config
- Choose What to Configure
- Complete Example
- Production Delivery Profiles
- Core Fields
- Render Fields
- Style Fields
- Build Fields
- Deploy Fields
- SEO Fields
- I18n Fields
- Dev Fields
- SPA Fallback Fields
- Verify a Configuration Change
Minimal Config
Enable frontend in the default config; page files and routes still need to follow Getting Started:
frontend: true uses the src/frontend, pages, components, styles/index.css, and public conventions. When using an object, set enabled: true explicitly; the object alone does not enable frontend. Production output defaults to dist/client with browser minification on and source maps off; the separate Node SSR bundle is unminified by default.
To disable frontend entirely, use frontend: false and remove or adapt handlers that call res.render(). Disabling the setting does not automatically delete old generated directories.
Choose What to Configure
Avoid adding a field merely because it exists. Global defaults use React and esbuild, SSR on, buffered streaming, browser splitting and production minification on, and no CDN URL or upload. The full-stack starter separately configures streaming: "auto" and frontend i18n; inspect the app's actual configuration.
Complete Example
This same-origin object illustrates the field hierarchy for the default full-stack starter. Most values match defaults and do not all need to be written. Budget values are examples: gather a baseline with warnOnly: true. The starter has an en-US dictionary, so this example enables frontend i18n explicitly.
Production Delivery Profiles
Same-origin (default)
Do not configure a CDN for the first production deployment:
vext build writes the frontend closure to dist/client; vext start
validates it and serves assets plus SSR from the same Node service. This is
the baseline to keep when a separate static origin provides no material value.
CDN plus incremental upload
Add these optional delivery fields only when a working CDN is available. Replace the example domain with the real asset address before using it:
filesystem stages selected assets locally; it does not publish them to the example domain. Use a custom adapter or existing release process for a cloud provider. Keep the state file outside frontend.outDir, build, inspect vext deploy assets --dry-run, then deploy the Node output from the same build once assets are available. See Static Assets and CDN.
Core Fields
Relative directory bases and TypeScript paths are covered in Project Structure. Supported image/font imports share public URLs in browser and SSR builds; aliases only change path resolution.
Render Fields
See SSR and Rendering Modes. A synchronous SSR timeout is checked after rendering returns and cannot preempt synchronous JavaScript. Once a streamed response starts, a failure cannot be rewritten like a normal buffered response. Disabling SSR and disabling browser hydration are separate settings; see Hydration.
Style Fields
Build Fields
React-related browser externals must define externalRuntime mappings. Otherwise the build fails with a friendly diagnostic.
Browser output is directory-based and uses frontend.outDir; frontend.build.client.outFile is not supported. Vext always emits the frontend manifest family required by SSR, preload, deploy, and verification, so build.client.manifest / build.server.manifest are not configuration fields.
For a normal product, keep browser code splitting, hashed names, and the
Vext-managed vendor entry enabled. Start with budgets as warnings, inspect the
complete route closure in size-report.json, and only then turn the budget
into a release-blocking gate.
Deploy Fields
Glob configuration such as deploy include/exclude, media scans, and style includes is limited to 1024 patterns per group, 4096 characters per pattern, 100 nesting levels, and an estimated 4096 brace expansions per pattern. Excessive input fails before entering matchers. This input budget does not clear the upstream braces audit advisory.
assetBaseUrl must be an absolute URL. deploy-manifest.json describes deliverable JS, CSS, produced media, and selected public files; creating it does not upload anything. Source maps are excluded by default; SSR renderer and entry HTML are not CDN upload assets. Run npx vextjs deploy assets --dry-run before changing adapter, prefix, or include/exclude rules.
SEO Fields
frontend.seo is the global SEO entry. When the object is present, enabled defaults to true. Without that object, explicit route/render SEO can still work; sitemap and robots need their own configuration. Explicit enabled: false disables structured SEO while legacy head stays independent.
Replace publicOrigin with the real deployment origin. Without an explicit canonical override, Vext combines it with the request pathname. Use route-level frontend.seo for static metadata and res.render(..., { seo }) for metadata derived from page data. Sitemap and robots can use "build" or "runtime" mode; empty objects default to build. Named origins support a finite multi-domain deployment.
See SEO, Sitemap, and Robots for dynamic canonical, provider, host-selection, output, and no-hydration examples. The exact nested field list is in the API reference.
I18n Fields
See Frontend I18n for locale priority, complete examples, SSR/browser loading, caching, and the reserved inject/clientSwitch behavior.
Dev Fields
frontend.dev.overlay only controls frontend browser development UI. Backend exception HTML overlays are configured separately through top-level dev.errorOverlay.
SPA Fallback Fields
Declare individual scopes instead of a site-wide catch-all. API, OpenAPI, and documentation routes stay excluded by default so a client-router shell cannot hide an operational endpoint.
spaFallback: true creates a root / scope for page index; it differs from omission. A custom global exclude replaces defaults, so retain required exclusions. Method, Accept, and existing routes also constrain fallback; see CSR and SPA Fallback. Empty client shells use createRoot; completed SSR uses hydrateRoot.
Verify a Configuration Change
Stop a development server using the same port before this check, and skip dry run when upload is not configured. Same-origin output should retain page content and loadable resources from Getting Started. For build or budget changes, inspect size-report.json in the actual output directory; warnOnly: true permits budget warnings, while exceeding an enabled budget without it fails the build. For CDN changes, request an SSR page and the browser asset it actually references; real CDN reachability needs deployment-environment verification. For SPA fallback, request both an in-scope URL and an excluded API path. Stop the server with Ctrl+C. See the API reference for less common nested fields.