Self-hosting
Create a standalone installation, or run the full workspace locally for development.
Create an installation
The fastest path is the CLI. It creates a project that depends on @headless-lms/server, owns its config and plugins, and deploys anywhere Node and Postgres run.
npm create headless-lmsRun the repo locally
To develop against the source, you'll need Node ≥ 22, pnpm 10, and Docker. The following brings up Postgres, MinIO and Hatchet, applies migrations, and starts the api, admin and student apps.
pnpm install
docker compose -f docker/docker-compose.yml up -d # Postgres, MinIO, Hatchet
cp .env.example .env # set BETTER_AUTH_SECRET and CREDENTIAL_STORE_KEY
# (openssl rand -base64 32 for each)
pnpm db:generate && pnpm db:migrate
pnpm dev # api :8000 · admin :8001 · student :8002.env.example documents every variable and the command that mints a Hatchet token for the local hatchet container.
Files
| Variable | Required | Default | Notes |
|---|---|---|---|
DELIVERY_URL_EXPIRY | no | 86400 | How long the file URLs in API responses stay valid, in seconds. Every course, lesson, download, post, message, profile and library response signs its files with this lifetime. Must be a positive integer; the API does not start otherwise. |
MEMBER_IMAGE_MAX_BYTES | no | 10485760 | The largest image a member may upload (profile photo, post cover, message attachment), in bytes. Checked when the upload is finalized. Must be a positive integer; the API does not start otherwise. |
REQUEST_LOGGING | no | true | One log line per request with its id, status and duration. Set to false to turn the access log off. Refused requests and errors are logged either way. |
These commands run across all workspaces:
pnpm build·pnpm test·pnpm lint·pnpm typecheckpnpm gen:sdkregenerates the OpenAPI spec and SDK (the database must be running).
Default ports
:8000— API:8001— Admin dashboard:8002— Student portal:8005— Postgres ·:8006/:8007— MinIO (API / console):8008/:8009— Hatchet (gRPC / dashboard)