Choose how it runs

The code of the shop names no process, no provider, no database and no protocol. Those choices live in one file at the root of the project, fougere.config.ts, and none of them changes a line under fronds/.

// fougere.config.ts
import '@fougere/adapter-sql';
import '@fougere/adapter-rest';
import { defineFougere } from '@fougere/core';

export default defineFougere({
  fronds: { catalog: 'http://127.0.0.1:4620' },
  ports: { Payment: 'StripePayment' },
  sources: { main: { type: 'sqlite', path: '.data/shop.db' } },
  protocols: { rest: {} },
});

Each section below is one of these keys. Leave a key out and you get the default: every frond in the app's process, the only implementation of each port, rows kept in memory (a warning says so), and no REST or GraphQL. The imports at the top are what make a source type or a protocol available: nothing is imported for you, and naming one that is not imported refuses the boot, naming the import.

Where each frond runs

fronds: gives a frond an address. Start the catalog alone:

fougere dev catalog --port 4620       # in production: fougere build, then fougere serve

and name that address:

fronds: { catalog: 'http://127.0.0.1:4620' },

PriceHandler keeps calling this.catalog.list(); the call now crosses the network. Remove the line and the catalog runs in the app's process again.

→ Shape your topology · The gradient

What answers a port

When two classes extend Payment, the app stops at boot until ports: says which one answers:

ports: { Payment: process.env.NODE_ENV === 'production' ? 'StripePayment' : 'FakePayment' },

The same key stacks classes in front of it, from the outside in. RetryingPayment extends Payment and asks for one, so it wraps whatever comes after it in the list:

ports: { Payment: ['RetryingPayment', 'StripePayment'] },

CheckoutHandler still asks for Payment, and never learns which one it got.

→ Ports

Where rows live

sources: names each place rows live. The one entry that lists no entities holds every entity the others do not; an entry that lists some moves them elsewhere: another database, a directory of JSON files, or memory.

sources: {
  main: { type: 'sqlite', path: '.data/shop.db' },
  archive: { type: 'file', path: './archive', entities: ['Order'] },
},

Order is now read and written as files under archive/ (with import '@fougere/adapter-file' at the top); every other entity stays in main. The repository a handler asks for is the same either way.

→ Sources

What the app serves

protocols: says which APIs the app answers on, beside the calls its own pages make. The operations are served on each one:

import '@fougere/adapter-rest';
import '@fougere/adapter-graphql';

protocols: { rest: {}, graphql: {} },

Importing the adapter makes a protocol available; naming it here is what serves it — a helper imported from the package anywhere else opens nothing.

→ Surfaces

Built with Fougere and Nuxt, hosted on GitHub Pages.