How modules work
// module extensions

Adapt any module.
Without forking it.

An extension adds to a module you didn't write — extra fields, actions, reports and settings on its entities — without touching the original. Stack as many as you need: country and industry variants, company-specific tweaks, bridges between modules. Your changes live in your own module, so the upstream one keeps updating underneath them.

fin.invoice · host entity
+2 extensions
fin.invoice host
+ ch_reference fin-ch
+ compute_qr() fin-ch
+ customer_id crm-fin
what an extension is

Augment.
Don't fork.

Forking a module means owning a copy forever — every upstream fix and feature stops reaching you. An extension is the opposite: it's an entity file in your own module that points at a host entity (it extends fin.invoice) and rides along as that module evolves.

[in your module]
Your changes, your package

The extension is your module. The host stays untouched, so you never inherit a maintenance fork.

[rides updates]
Survives upstream

Upgrade the base module and your extension keeps working — the platform re-joins your columns automatically.

[opt-in]
Installed only where wanted

An extension installs per tenant, on top of its host. A tenant that doesn't need it never sees it.

[clean uninstall]
Removable without a trace

Your physical columns live in a separate 1:1 table in your own schema. Uninstall drops it cleanly — the host is exactly as it was.

what you can add

Fields, actions,
reports, settings.

An extension can give a host entity the same building blocks a module ships for its own entities — and they surface as one record, one view.

[fields]
Fields

Physical columns (stored in a 1:1 table in your schema) or virtual ones — references, sets, formulas. They appear on the host's forms, grids and prints as if they'd always been there.

[actions]
Actions & triggers

Add a verb to someone else's entity — "Generate Swiss QR" on an invoice — with its own params, canExecute rule and audit trail.

[reports]
Reports & views

Ship reports and views that read the host entity plus your added columns, surfaced under your own menu.

[settings]
Settings

Declare configuration the host knows nothing about — a Swiss creditor IBAN, an industry code — owned and gated by your module.

adapt or bridge

Two jobs,
one mechanism.

Adapting a module and bridging two modules are both extensions under the hood — they differ in intent.

[adapt]
Adapt a module to your needs

Take a module you didn't write — a community CRM, the standard invoice — and add what your business or jurisdiction requires. fin-ch adds Swiss QR references to fin.invoice; your own overlay adds the fields your team needs. No fork, no waiting on the author.

[bridge]
Bridge two modules together

A small bridge module like crm-fin depends on both CRM and Finance and owns the integration — cross-module columns, actions and views — so quote-to-invoice just works. A bridge has no entities of its own. Anyone can bridge any two modules; install it only when both are present.

compose freely

Stack as many
as you want.

Extensions don't compete for the host. Several can layer on the same entity at once, each owning its own slice — and it's all still one app on one engine.

[stackable]
Many on one entity

crm-fin and hr-fin can both extend fin.invoice. Each gets its own table; the platform left-joins them all into a single record.

[third-party]
Anyone can extend

Extensions are how third parties build on the ecosystem — bridge, localize or specialize any module on the marketplace without forking it.

[per-tenant]
Per-tenant stacks

One tenant runs CRM + Finance + crm-fin; another adds your custom overlay. Every tenant assembles the stack it needs.

[one engine]
Still one app

However many modules and extensions you combine, they run on the same metadata engine — one UI, one security model, one API.

security across the seam

Extensions cross
a permission boundary.
It's enforced.

Adding to someone else's entity crosses a security boundary — dForge makes that explicit, so a third-party extension can't quietly widen access.

[columns]
Columns inherit the host

Extension fields are part of the record — if you can read the invoice, you read its Swiss reference. One invoice, one view, no piecewise holes.

[actions]
Actions own their rights

An extension action carries its own permission. A Swiss admin can grant "Generate QR" to the AR lead alone — separate from generic invoice editing.

[references]
References are checked

Reading across a reference needs rights on the target too. A finance-only role can't read the whole party book just because an invoice points at it.

build an extension

Make it yours.
Without the fork.

See how modules compose, or browse the catalog for a base to build on.