Getting started
npm create fougere shop --frond blog --app nuxt
cd shop && pnpm install && pnpm dev
Alpha. The
@fougere/*packages are on npm under thealphatag — the version is the whole promise, the surface can still move. This site (site/) anddemos/nuxt-blogare complete references. The structure below matches the current implementation. Already have a Nuxt app? Add Fougere to it.
Application structure
A Fougere app is a Nuxt app plus a fronds/ directory and one config file:
my-app/
fougere.config.ts ← persistence, auth, topology
nuxt.config.ts ← modules: ['@fougere/nuxt']
fronds/
blog/
entities/Post.ts
handlers/PostHandler.ts
collectors/CurrentUserCollector.ts
seeds/Post.seed.ts
user/ ← a second domain
entities/User.ts
app/
pages/ ← ordinary Nuxt pages, talking through the primitives
The scanner discovers entities, handlers, collectors, and seeds under fronds/. File
location and class name are used for registration; no additional wiring file is needed.
Each directory directly under fronds/ defines a Frond. A page imports an entity using
that directory name:
import Post from '@frond/blog/entities/Post';
@fougere/nuxt reads the scan and registers a @frond/<name> alias per Frond, so that
import works for blog and user alike — nothing to add, no package.json, no
pnpm-workspace.yaml entry. Renaming a Frond, or importing one from outside a Nuxt app,
is where a Frond's package.json earns its keep: see
Frond — naming and importing.
fougere new writes the same directories one level out — the app under apps/<name>/, the
Fronds shared at the workspace root, fougere: { root: '../..' } in nuxt.config.ts — so
that several apps consume the same domains. One app, one directory: the shape above.
One domain, no fronds/ at all
The project root can use the same convention as a directory under fronds/. A
single-domain app can therefore place its entities and handlers directly at the root:
my-shop/
fougere.config.ts
nuxt.config.ts
entities/Product.ts ← the root IS the Frond, named after the directory
handlers/ProductHandler.ts
app/pages/
fougere new my-shop --flat --frond blog writes exactly that. import Product from '@frond/my-shop/entities/Product' — same alias rule, no fronds/ segment, and the word
never comes up until there are two domains to tell apart. The root needs at least an
entities/ to count; a lone services/ is an ordinary directory name.
When the second domain arrives it goes to fronds/billing/ and the root Frond stays
where it is — nothing moves, no import is rewritten. fronds/ is not what defines a
Frond, it is where the others live.
fougere.config.ts — reference
import { defineFougere } from '@fougere/core';
import { betterAuth } from '@fougere/auth-better';
import User from './fronds/user/entities/User';
export default defineFougere({
// Persistence. Three forms:
// 'sqlite' → in-memory on the Nuxt side (reseeded each reload)
// { dialect: 'sqlite', path: '…' } → file-backed (survives reloads and deploys)
// false → no db
db: { dialect: 'sqlite', path: '.data/app.db' },
// Topology. A Frond listed here is STILL scanned (its entities keep feeding
// metadata to forms and validation) but is not hosted locally: calls travel
// as JSON-RPC to the process that hosts it. Comment the line → in-process.
// remotes: { blog: 'http://127.0.0.1:4100' },
// Auth (optional) — better-auth behind a thin translation layer.
auth: betterAuth({
user: User, // your entity extending AuthUser
secret: process.env.AUTH_SECRET!, // 32+ chars
baseUrl: process.env.SITE_URL ?? 'http://localhost:3000',
basePath: '/auth', // mounts /auth/** (sign-in, sign-up, sign-out…)
trustedOrigins: ['http://localhost:3000'],
sessionTtl: 30 * 24 * 60 * 60 * 1000,
providers: {
credential: { minPasswordLength: 8, autoSignIn: true },
// google: { clientId: …, clientSecret: … },
},
}),
});
Tables are derived from your entities. At boot, SQLite auto-DDL creates missing tables and adds missing columns. Renames, removals and type changes require an explicit migration. Seeds run after that schema sync and call operations with their usual validation.
Run
pnpm install
pnpm dev # scan → sync additive schema → seed → serve on :3000
Check the boot log for the number of discovered Fronds:
INF [boot:app] scanned 2 frond(s) in 467ms
INF [boot] ready in 483ms — 2 frond(s) + auth (/auth)
Next: Entities — the field vocabulary and the four axes.