Philosophy

Everything on this page comes from one rule: Fougere tells what your code is from how it runs. An entity says what your data is; the table, the protocol, the host and the address are how it runs. So everything else is either derived from your code (the type, the validation, the table, the form) or chosen apart from it, in the config (the database, the host, where each part runs). A detail of how it runs may sit next to your code when that is simpler — a column type for one field — and nothing derived reads it. You describe your data, what your app does and where one domain ends; Fougere then connects that to Nuxt, HTTP, SQL or another process.

One declaration, many uses

An entity describes your data without saying where it is stored. From that one class come the TypeScript type, the validation, the form, the database table and the GraphQL type. When you find the same rule written in two places, move it into the entity, and both places will read it from there.

Operations, not field writes

Your app changes things with commands, reads them with queries, and, when it helps, announces what happened with events. Crud(Post) gives you the five usual operations. A business step gets its own verb: publish checks its rules and then changes status, rather than letting the page write that field itself.

The Frond owns

A frond holds one domain: its entities, its operations and its rules. Another frond reaches it only through what it exposes, never through its files. Your app puts fronds together, and their logic stays inside them, not in your pages or your stores.

Topology is configuration

The same rule, applied to the clearest case of how it runs: where. The config says whether a frond runs in your process or on another host, and your code calls it the same way in both cases. Fougere does not hide the difference: your code simply never said which side it was on. A local call stays in memory; a remote one goes over the network.

The boundary also lets a Frond have its own repository and release cycle: only its contract must travel, never its source — fougere sync reads it off the running host, fougere build-frond turns it into an installable package (where the code lives).

HTTP is a projection, not a foundation

Many frameworks start from a route: everything hangs off a request, the model, the validation and the business code included. Here everything starts from the operation: a public method, called with its own arguments, that has never heard of HTTP.

This is not a matter of style; it is what makes the rest possible. An operation that ignores transport can be called in memory, put on a JSON-RPC wire, translated into a REST route, a GraphQL field or a shell command — with none of those forms privileged. @fougere/core depends on no server, and @fougere/http has no dependencies at all: you bring Hono, Fastify, Nitro — or nothing.

The corollary is that JavaScript takes you everywhere it goes. The declaration and its validator run in the browser as they do at the façade: the same object, not a faithful copy.

Transport is a leaf

A complete Fougere application may have no HTTP at all. Entities, operations, storage, validation, injection and seeds all work without a server ever starting. A shell command, a worker, a test, an in-memory call are not degraded versions of the application: they are whole uses of it.

That is why HTTP sits at the same rank as the other projections, not beneath them. One declaration yields the SQL table, the GraphQL type, the form contract and the route: four readings of a single statement, none of them the ground the others stand on.

Two consequences, and they are what makes the principle useful:

  • were transport the foundation, you could not remove it — so no in-memory call, so no gradient;
  • the surfaces could not return the same verdict, since one of them would be the floor beneath the rest.

So this is not a claim of independence from any server, nor an implementation choice. It is the rule stated at the top of this page — one declaration, many projections — applied where many frameworks put their foundation.

Ports, and a different arrow

SQLremotes:Mirrorcall envelopeRESTGraphQLthe Frondthe public surfacethe ports it traverses

The vocabulary is the ordinary one — Storage and HttpRouter are ports, the packages under adapter/ implement them — so a reader arriving from a ports-and-adapters architecture is on familiar ground. One thing differs. There, the arrow states a dependency: nothing in the core may point outward. Here it states a derivation: the table, the GraphQL type, the form contract and the route are read off the declaration. A dependency direction is a rule you have to keep; a derivation is a fact you cannot break.

State is losable or durable

To choose between a cache and durable storage, consider what losing the value changes. A value that can be recomputed from a query can remain in a cache. A value whose loss changes behavior should be stored as business data, even when it has a short lifetime. A one-time OAuth code can, for example, be represented as { code, userId, expiresAt } with a destructive read.

Embedded or externalized

Elements used in several contexts ship with the class; execution details are connected by the runtime.

  • Embedded — validation, input or output projections, and metadata. They can be used in the browser, at the façade, or in a remote Frond.
  • Externalized — storage, transport, and rendering. These adapters can vary with the application and the surface being used.

Validation is embedded so the same rules apply in each context. Storage remains external so the application can select an adapter. Metadata does not depend on topology; its use depends on the runtime that loads it.

Design order

When making a design decision, ask these questions in order:

  1. What is the application concept?
  2. What is its ownership boundary?
  3. Which contracts must it expose?
  4. Which operations change state?
  5. Which queries read it?
  6. What invalidates what?
  7. Which adapter executes or projects this model?

This order avoids spreading one rule across a route, page, table, and transport.

Why “Fougere”

A fern consists of fronds that repeat a structure similar to the whole plant. The name refers to the framework's composition: fields form an entity, entities and their operations form a Frond, and an application composes several Fronds.

Position

Fougere targets data-intensive applications that use one business model across several surfaces and execution modes. Nuxt, CRUD, and transports are integrations of that model, not its definition.

Next: The Frond.

Built with Fougere and Nuxt, hosted on GitHub Pages.