Skip to content

Extensions

CairnCMS is built to be extended. The same APIs and components that power the platform are available to you, so a custom extension can add new capabilities without forking the codebase.

This page covers the extension types CairnCMS ships with, the three runtimes they run in, and how to choose between them. The next page, Creating extensions, covers the toolchain: scaffolding, building, installing, and publishing.

Before you pick a type, it helps to know where your code runs. CairnCMS has three runtimes, and the runtime decides what your code can reach.

  • In the browser. App extensions (interface, display, layout, module, panel, item view) are Vue components that run in the admin app, inside the logged-in user’s browser. They act through the API with that user’s own permissions, and can do whatever that user can do, no more and no less. The browser is not a security boundary. See App extensions.
  • In the API, with full authority. A server extension (hook, endpoint, operation) runs in the API’s Node process. By default it has full access to services, the database, and the environment. This is the home for code that needs native modules, raw services, or schema changes. It is the default when a server extension declares no runtime.
  • In the API, sandboxed. The same server types can opt into the confined runtime by declaring runtime: confined-server. The code then runs in a sandboxed child with no host imports and no raw Node. Every privileged effect goes through a brokered host.* call that the platform gates against the capabilities and settings the extension declares. See Sandbox.

A server extension is full-authority unless it opts into the sandbox. Prefer the sandbox for new server extensions when the brokered API covers what they need, and reach for full authority only for what the sandbox cannot host. Server extensions covers the choice in full.

CairnCMS supports ten extension types in three groups.

Vue components that run in the admin browser. See App extensions for the lane.

  • Interface is a custom field editing widget. Use this to add new ways to enter or edit data on the item form.
  • Display is a custom read-only renderer for a field. Use this when you need a different way to show a value in lists, tables, and detail views without changing how it is edited.
  • Layout is a custom collection page layout, alongside the built-in Table, Cards, Calendar, Map, and Kanban.
  • Module is a top-level area in the module bar. Use this when you need an entire workspace that does not fit into the existing modules.
  • Panel is a custom panel type for Insights dashboards.
  • Item View is a contextual split pane in the item editor, behind a platform-rendered toggle. Use this for previews, related information, or anything an editor wants beside the form.

Code that runs in the API in Node, either full-authority or sandboxed. See Server extensions for the lane.

  • Hook reacts to or modifies platform events. Full-authority hooks come in five types: filter (blocking, can transform or veto), action (non-blocking, runs after), init (runs once at startup), schedule (runs on a cron schedule), and embed (injects HTML into the admin app’s head or body). Sandboxed hooks support filters and actions.
  • Endpoint is a custom HTTP route mounted alongside the built-in API. Use this when you need to expose logic that does not map to a collection’s CRUD endpoints.
  • Operation is a custom flow operation. It is hybrid: the app side renders the operation’s configuration form in the flow editor, and the server side runs the logic when the flow executes. The server side is what chooses full authority or the sandbox.
  • Bundle is a wrapper that ships multiple, mixed extensions as a single package. Use this when several extensions share dependencies, are released together, or implement a single coherent feature across the app and server. A bundle spans both groups.

A short decision rubric:

  • The user needs a new way to edit a field’s value, use an Interface.
  • The user needs a new way to display a field’s value in non-edit contexts, use a Display.
  • The user needs a new way to browse a whole collection, use a Layout.
  • The user needs an entirely new workspace unrelated to existing modules, use a Module.
  • A dashboard needs a new visualization or interaction, use a Panel.
  • The user needs contextual information or an embedded view beside the item form, use an Item View.
  • The server needs to react to or modify a platform event, use a Hook.
  • The server needs to expose a custom HTTP route, use an Endpoint.
  • A flow needs a new step, use an Operation.
  • Several extensions ship together, use a Bundle.

If you find yourself wanting to ship app and server logic that should be released together, reach for a Bundle rather than separate top-level extensions.

Convention-based customization (not extensions)

Section titled “Convention-based customization (not extensions)”

A couple of developer-facing customization paths exist outside the extension system. They use simple file-folder conventions rather than the SDK’s define* API:

  • Custom migrations let you drop migration .js files into EXTENSIONS_PATH/migrations and they run alongside built-in migrations.
  • Email templates let you drop Liquid templates into EXTENSIONS_PATH/templates and reference them from the Send Email flow operation or by name from any code that sends mail.

These are not extension types and do not require the SDK or a build step. They are documented separately for that reason.

CairnCMS discovers extensions from three sources:

  • Package extensions are installed from npm into the project’s node_modules. Any package whose name matches cairncms-extension-<name>, @<scope>/cairncms-extension-<name>, or @cairncms/extension-<name> is auto-discovered.
  • Local package extensions are full package directories (each with its own package.json) placed inside EXTENSIONS_PATH. Bundles are installed this way.
  • Local file extensions are pre-built extension files placed in type subfolders inside EXTENSIONS_PATH (for example, EXTENSIONS_PATH/interfaces/<name>/index.js). Used for non-bundle extension types when you do not need a separate package.

The Creating extensions page walks through all three.

  • App extensions covers the browser lane and links to each app type.
  • Server extensions covers the Node lane and the full-authority versus sandboxed choice.
  • Sandbox is the reference for the confined runtime: the host API, capabilities, and diagnostics.
  • Extension settings covers declaring operator-managed settings and secrets, and how server and app extension code reads them.
  • Creating extensions covers the toolchain end to end: scaffold, build, install, hot reload, debug, publish.