The API-first LMS for building learning systems

A headless, composable learning platform in modern TypeScript. Use it out-of-the-box or swap with your own adapters. Build whatever frontend you want.

$ npm create headless-lms
app/lib/lms.ts
import { createClient } from "@headless-lms/sdk"

const lms = createClient({
  baseUrl: process.env.LMS_URL,
  token: process.env.LMS_TOKEN,
})

// Fully typed against the OpenAPI spec
const course = await lms.courses.create({
  orgId,
  title: "Intro to Distributed Systems",
})

await lms.entitlements.grant({
  studentId,
  courseId: course.id,
})

A complete learning platform, headless by design

The full domain of an LMS, exposed as a typed API. Compose the pieces you need and swap the ones you don't.

Course builder
Author structured course content; students work through it activity by activity.
Progress tracking
Per-student, per-activity completion, rolled up into course progress and reporting.
Entitlements
Grant and revoke student access to content with a first-class access model.
Multi-tenant
One deployment serves many orgs. Every student, course, and session is org-scoped.
Media & file assets
Object storage with presigned upload and download URLs, behind a swappable adapter.
Integrations
Drop a plugin folder into your installation and it's live at startup. Write your own.
MCP endpoint
AI agents connect over OAuth and operate the LMS through the same domain layer.
Typed SDK & OpenAPI
Routes validate against shared Zod schemas; the SDK is generated from the spec.
Transactional email
Invitation and auth mail, swappable behind an adapter you control.

Works out of the box

Ships with a Next.js admin back-office and student portal built on the public API, plus an MCP endpoint so AI agents are first-class clients.

Admin back-office
A Next.js dashboard for courses, students, entitlements, and reporting — built entirely on the public API.
Rich course content builder
Create engaging course content with our default content builder (powered by Plate.js).
Student portal
A Next.js app where students log in and take their courses, built on the typed SDK.
MCP endpoint
Agents authenticate and operate the LMS through the exact same domain layer as the SDK and dashboards.
mcp.http
# AI agents connect over OAuth and operate the LMS
# through the same domain layer as every other client.

POST /mcp
Authorization: Bearer <oauth-token>

> tools/call enroll_student
  { "orgId": "...", "studentId": "...", "courseId": "..." }

Bring your own adapters

The backend ships as @headless-lms/servera framework-free domain core which means you can bring your own adapters.

Layered by design
A framework-free domain core allows you to use any tech stack you want.
Composable installations
An installation composes what it wants with sane defaults. Swap for your own storage, email auth adapters freely.
Secure by default
Authentication, org-scoped multi-tenancy, encrypted credential storage, and validated I/O throughout.

Clients

Admin dashboard
Student portal
Your frontend
AI agents (MCP)

HTTP layer — Fastify

Zod-validated requests & responses
OpenAPI spec
Generated typed SDK

Domain core — framework-free

Courses
Progress
Entitlements
Orgs & sessions

Adapters & persistence

Drizzle / Postgres
Object storage
Email
Plugins

One source of truth, from schema to SDK

Define a route once with Zod schemas. Headless LMS validates every request and response, generates the OpenAPI spec, and produces a fully typed SDK you can build any frontend on.

  • Requests and responses validated against shared Zod schemas
  • OpenAPI spec generated from your routes
  • Typed SDK generated from the resulting spec
  • Interactive OpenAPI reference at /docs on a running API
routes/courses.ts
// Routes validate against shared Zod schemas
export const createCourse = defineRoute({
  method: "POST",
  path: "/orgs/:orgId/courses",
  input: CourseCreateSchema,   // validated request
  output: CourseSchema,        // validated response
  handler: async ({ input, ctx }) => {
    return ctx.courses.create(input)
  },
})

// The OpenAPI spec + SDK are generated from these.
// pnpm gen:sdk

Spin up your own LMS in one command

Create a standalone installation that owns its config and plugins, and deploys anywhere Node and Postgres run.

bash
npm create headless-lms