Headless LMS

Adapters

Adapters are what makes headless-lms incredibly extendable.

Adapters are implementations of the outbound ports declared in @headless-lms/core. These are the capabilities like email delivery, email templates, object storage, durable workflows etc.

For example, system emails are sent using Resend. If you want to use a different email provider, then implement your own Email adapter and pass it in to the server.

A running server wires these adapters together at startup:

main.ts
import { createContainer, buildServer } from "@headless-lms/server";
import { ResendEmailAdapter } from "@headless-lms/adapter-email-resend";
import { MinioStorageAdapter } from "@headless-lms/adapter-storage-minio";
import { ReactEmailTemplateRenderer } from "@headless-lms/adapter-email-templates";
import { HatchetAutomationEngine } from "@headless-lms/adapter-workflow-hatchet";

const container = await createContainer(config, {
  adapters: {
    email: new ResendEmailAdapter({ apiKey, from }),
    storage: new MinioStorageAdapter(storageConfig),
    templates: new ReactEmailTemplateRenderer(),
    workflows: new HatchetAutomationEngine(),
  },
});

Every slot is optional, with a sensible default, so you can start with nothing configured and add adapters as you need them.

Available adapters

SlotPortDefault adapterAbsent →
emailEmailSender@headless-lms/adapter-email-resendStub that fails loudly on send
templatesTemplateRenderer@headless-lms/adapter-email-templatesStub that fails loudly on render
storageObjectStorage@headless-lms/adapter-storage-minioStub that fails loudly on use
workflowsAutomationEngine@headless-lms/adapter-workflow-hatchetIn-process engine, one attempt per action

Because each slot is just an interface, you can replace any adapter with your own implementation — implement the port from @headless-lms/core/types and pass it in the same way.

An installation scaffolded with npm create headless-lms comes with one adapter wired: MinIO storage, and only when STORAGE_ENDPOINT is set. Every other slot sits on its default, so a fresh project boots against nothing but Postgres. Add the adapters above as you need them — apps/api in the repository is the fully wired reference (Resend, MinIO, React Email, Hatchet).

On this page