The API-first LMS for building learning systems
A headless, composable learning platform in modern TypeScript. Fastify, Drizzle, and Zod under the hood. Org-scoped multi-tenancy, a typed SDK, and swappable 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.
A backend that ships as a library
The backend ships as @headless-lms/server: a framework-free domain core behind a Fastify HTTP layer. Every client — including AI agents — talks to the same domain layer.
- Layered by design
- A framework-free domain core sits behind a Fastify HTTP layer, persisted with Drizzle and Postgres.
- Composable installations
- An installation composes what it wants with sane defaults. Swap storage and email 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
// 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:sdkOne 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
Reference apps and an AI-native surface
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.
- Student portal
- A Next.js app where students log in and take their courses, built on the typed SDK.
- MCP endpoint
- Agents authenticate over OAuth and operate the LMS through the exact same domain layer as the SDK and dashboards — no parallel code path.
# 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": "..." }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.
npm create headless-lms