Additives

Base Additives

Some features are really a foundation that several variants build on: a shared layout, a set of common routes, a battery of models. WebFluid models that with base Additives — Additives that aren't meant to run on their own, but to be extended.

What makes an Additive a base

A base Additive is declared with "type": "base" and, because it is a foundation rather than a finished feature, it may not declare a frontend. It is never enabled directly in your app config either; instead, a regular (default) Additive picks it up and extends it.

additives/core/manifest.json json
{
  "id": "core",
  "version": "1.0.0",
  "type": "base",
  "frontend": { "type": "none" },
  "name": "Core"
}

A base looks like any other Additive otherwise — it has routers, templates and hooks. Here it contributes a shared route that every extending Additive will inherit:

additives/core/__init__.py python
from webfluid import Additive

additive = Additive(__name__)


@additive.before_enable
def before_enable(_):
    from .app import about
    additive.app.get("/about")(about)

Extending a base

A default Additive becomes a child of a base by passing it into the constructor. You don't import the base package directly — you resolve it through import_base, which finds the installed base by its id:

additives/portal/__init__.py python
from webfluid import Additive
from webfluid.additives.core import import_base

additive = Additive(
    __name__,
    import_base("core")
)


@additive.before_enable
def before_enable(_):
    from .app import index
    additive.app.get("/")(index)

What extension actually does

When the child is enabled, the framework folds the base into it:

  • The base's api, app and ws routers are included into the child, so the /about route above now answers under the child's prefix (e.g. /portal/about).
  • The base's templates join the child's namespace, so the child can extend layouts and partials the base ships — under the child's id.
  • The base's required extensions are merged into the child's requirements.
  • The base inherits the child's url prefix and id, so reverse-url lookups line up.
 

Only the child is switched on in your app config. The base rides along with it. You never put a base id into the [additives] section — bases are loaded on demand when something extends them.

 

A given base can be extended by exactly one default Additive at a time. If two of your enabled Additives try to extend the same base, enabling will fail. Bases are foundations for a single feature, not a shared singleton service — reach for an extension if you need the latter.

Why bother

Base Additives shine for distribution. You can publish a polished foundation — an admin shell, an auth flow, a billing skeleton — and let each project extend it with its own routes and frontend without forking. That packaging story is exactly what the next chapter is about.

Continue reading

From here you can continue straight with Interaction between.