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-lmsimport { 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.
# 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
HTTP layer — Fastify
Domain core — framework-free
Adapters & persistence
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 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:sdkSpin up your own LMS in one command
Create a standalone installation that owns its config and plugins, and deploys anywhere Node and Postgres run.
npm create headless-lms