Application Modes

ubean’s mode config field declares the application shape and controls which build steps run. This is orthogonal to preset (deployment platform) and routing.mode (route data generation).

Mode Overview

ModeClient bundleSSR bundleServer bundlePrerenderTypical use case
fullstack (default, ssr: true)✅✅✅optionalVue pages + Hono API + SSR (default behavior)
fullstack + ssr: false✅❌✅❌Vue pages + Hono API, no SSR (admin dashboards)
spa✅❌❌❌Pure client-side render, static HTML + JS, no server
ssg✅✅ (static bundle)❌✅ (forced)Build-time prerender via direct render path — static HTML (marketing/blog/docs)
backend❌❌✅❌Pure Hono API service, no Vue pages, no SSR

Configuration

Set mode (and optionally ssr) in ubean.config.ts:

// ubean.config.ts
import { defineConfig } from 'ubean';

export default defineConfig({
  mode: 'fullstack', // 'fullstack' | 'spa' | 'ssg' | 'backend'
  ssr: true // only effective when mode === 'fullstack'
});

CLI flags override the config file:

ubean build --mode spa
ubean build --mode fullstack --no-ssr
ubean build --ssg          # shortcut for --mode ssg

The mode is also what a plain vite build produces — the plugin registers the client / ubean environments unconditionally, so vite build yields the same dist/{public,server} layout as ubean build (plus prerendered HTML for the routes that ask for it). vite build ignores --outDir and always writes build.outputDir.

Mode Details

fullstack (default)

The default mode — Vue pages + Hono API + SSR. Zero config needed.

  • Build output: dist/public/ (client) + dist/server/ (server)
  • Dev: Vite middleware mode + Hono app
  • Preview: Node server (server.mjs)
  • Prerender: optional (controlled by prerender.enabled)

fullstack + ssr: false

Full-stack without SSR. Suitable for apps with no SEO requirements (admin panels, internal tools).

  • Skips SSR bundle build (~40% build time saved)
  • Server bundle still built (Hono app handles API routes)
  • Pages render client-side; API routes respond normally
  • Preview still uses the Node server

fullstack + SSR exclude (ssr: { exclude: [...] })

Most pages SSR, but exclude specific routes (e.g. admin dashboards, highly interactive pages that don’t need SEO).

export default defineConfig({
  mode: 'fullstack',
  ssr: {
    exclude: ['/admin/**', '/dashboard/*', '/realtime']
  }
});
  • SSR bundle is still built (global ssr is true by default)
  • Matching pages return a client-only HTML shell (CSR) instead of SSR
  • Non-excluded pages render server-side normally
  • Glob patterns: * (single segment), ** (multi-segment recursive)
  • Use case: mix of content pages (SSR) and app-like pages (CSR) in the same project

Per-route SSR override via routeRules (P9-03)

For finer-grained control than ssr.exclude, use routeRules.ssr to override the global SSR setting per route. This takes precedence over ssr.exclude:

export default defineConfig({
  mode: 'fullstack',
  ssr: {
    exclude: ['/admin/**']           // admin pages → CSR by default
  },
  routeRules: {
    '/admin/share-screen': { ssr: true },        // ...except this one (force SSR)
    '/feed': { ssr: 'streaming' },                // force streaming SSR for /feed
    '/dashboard/realtime': { ssr: false }         // force CSR even if not in exclude list
  }
});
routeRules.ssr valueBehavior
trueForce SSR for matching routes (overrides ssr.exclude)
falseForce CSR for matching routes (treats them as if in ssr.exclude)
'streaming'Force streaming SSR for matching routes (overrides SsrOptions.streaming)
'data-only'Run loaders/data but return a CSR shell with dehydrated data

Combine with routeRules.isr for incremental static regeneration, or routeRules.prerender for build-time prerendering. See Route Rules for the full field reference.

spa

Pure client-side rendering, no server.

  • Build output: dist/public/ only (static index.html + assets)
  • No SSR bundle, no server entry, no prerender
  • Dev: Vite dev server, app.fetch() returns client HTML for all routes
  • Preview: static file server serving dist/public/

ssg

Static site generation — prerender at build time via a direct render path (no HTTP pipeline, see ADR-0011).

  • Builds client + a minimal static render bundle: no Hono app, API routes, middleware, crons, or IPX — lighter and faster than fullstack prerendering (~50% faster per-route render, 6–11% faster overall build)
  • Forces prerender.enabled = true
  • Output: static HTML files under dist/public/**/*.html
  • pages/404.vue (if present) renders to 404.html — picked up by GitHub Pages / Netlify / Cloudflare Pages as the custom 404 page
  • i18n routes are expanded per strategy: /about → /about + /zh/about under prefix_except_default; hreflang / canonical / og:locale tags are emitted automatically
  • Full-text search index is generated automatically when content: true (see Content & Search): dist/public/__search.json (section payload for useContentSearch()) plus a chunked Pagefind index under dist/public/pagefind/ when the optional pagefind dev dependency is installed — both CJK-aware
  • Page loader is not executed (one-time warning) — data comes from content collections, module constants, or client-side hydration fetch
  • Not available in static output: server actions, form POST, ISR / PPR / streaming, route-rule redirect/rewrite (no execution point in static files) — use fullstack with prerender when you need those
  • Security response headers (CSP/HSTS/…) are not part of the static output — configure them on your hosting platform (e.g. Netlify / Cloudflare Pages _headers). Dev disables them by default to mirror that; set security.headers in ubean.config.ts to re-enable them in dev as a CSP debugging console
  • Temporary dist/server/ is cleaned up after prerender (set UBEAN_KEEP_SSR=1 to keep it for debugging)
  • Preview: static file server serving dist/public/

backend

Pure API backend, no frontend.

  • Skips page-related virtual modules and Vue plugins
  • No client bundle, no SSR bundle
  • Builds server bundle only (Hono app + API routes)
  • Output: dist/server/ only
  • Preview: Node server (same as fullstack)

Relationship to Other Config

Config fieldRelationship to mode
build.presetOrthogonal — mode controls architecture, preset controls deployment platform (all 11: standard/node/cloudflare/cloudflare-dev/vercel/vercel-edge/netlify/bun/deno/aws/azure)
routing.modeOrthogonal — controls route file generation (virtual/file/both), independent of app mode
prerender.enabledssg forces it on; spa/backend/fullstack+ssr:false force it off
ssrSub-option of fullstack only; ignored by other modes
icon/pwa/auth/i18nOrthogonal — loaded on demand, unaffected by mode

Mode Selection Guide

ScenarioRecommended mode
Full-stack app (pages + API + SEO)fullstack (default)
Full-stack app (pages + API, no SEO)fullstack + ssr: false
Pure API service (no frontend)backend
Marketing site / blog (static)ssg
Pure frontend app (no API, no SEO)spa

Notes

  • mode defaults to fullstack and ssr defaults to true — existing projects need no changes (zero breaking change).
  • fullstack + ssr: true (default) build flow is identical to pre-mode behavior.
  • fullstack + ssr: false still generates a server bundle because API routes need it. If you need neither SSR nor API, use spa.