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.
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.
The extension is your module. The host stays untouched, so you never inherit a maintenance fork.
Upgrade the base module and your extension keeps working — the platform re-joins your columns automatically.
An extension installs per tenant, on top of its host. A tenant that doesn't need it never sees it.
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.
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.
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.
Add a verb to someone else's entity — "Generate Swiss QR" on an invoice — with its own params, canExecute rule and audit trail.
Ship reports and views that read the host entity plus your added columns, surfaced under your own menu.
Declare configuration the host knows nothing about — a Swiss creditor IBAN, an industry code — owned and gated by your module.
Two jobs,
one mechanism.
Adapting a module and bridging two modules are both extensions under the hood — they differ in intent.
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.
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.
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.
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.
Extensions are how third parties build on the ecosystem — bridge, localize or specialize any module on the marketplace without forking it.
One tenant runs CRM + Finance + crm-fin; another adds your custom overlay. Every tenant assembles the stack it needs.
However many modules and extensions you combine, they run on the same metadata engine — one UI, one security model, one API.
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.
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.
An extension action carries its own permission. A Swiss admin can grant "Generate QR" to the AR lead alone — separate from generic invoice editing.
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.
Make it yours.
Without the fork.
See how modules compose, or browse the catalog for a base to build on.