Run Learnio locally
Get your package running on your computer, with Docker.
For the Full Stack package
Before you start: install and open Docker Desktop, or Docker Engine with Compose.
View requirementsDownload your template
Open My templates and download the Learnio ZIP for your package.
Expected result: A file named like
learnio-lms-main-….zipis in your downloads.Unzip and open the folder
Extract the ZIP and open a terminal in the
learnio-lmsfolder. On Windows, extract it in File Explorer, then open a terminal in the folder.Terminalunzip learnio-lms-*.zip cd learnio-lmsExpected result: The folder lists
Having trouble?admin-dashboard,back-end,frontendanddocker-compose.yml.Start the apps
Build and start the API, the student site and the admin dashboard. The first start builds three images and fills the database with the demo data, which takes a few minutes; later starts take seconds.
Terminalinlearnio-lmsdocker compose up --buildA port is already in use?
If the start stops with
A port is already in useports are not available ... address already in use, another program uses 3030, 3031 or 8000. Either stop it, or create a file named.envin thelearnio-lmsfolder with the port you need, such asADMIN_PORT=3041(SITE_PORTfor the student site,API_PORTfor the API). Rundocker compose up --buildagain and open the app on its new port.Expected result: The three services keep running and the log stops scrolling. Leave this terminal open.
Having trouble?Open the student site
Open localhost:3030Local and sign in as the demo student:
demo@learnio.comwith the passwordDemo@123.Expected result: The catalogue loads, and signing in opens the learner dashboard.
Having trouble?Sign in to the admin
Open localhost:3031Local. The super admin is
admin@learnio.comwith the passwordAdmin@123. Change it after your first sign-in.Expected result: The admin dashboard opens on its overview.
Having trouble?
Take a tour
What the demo data looks like once everything runs: the student site with its catalogue, opened on a course.

| Account | Password | |
|---|---|---|
| Super admin | admin@learnio.com | Admin@123 |
| Instructor | emily-davis@learnio.com | Teach@123 |
| Student | demo@learnio.com | Demo@123 |
Eleven more staff accounts exist at *@learnio.com with the password admin123, each on a different role, so you can see the permissions from the inside. These are local demo accounts only.
Stop and start again
Press Ctrl+C in the terminal to stop the apps, or run this from the learnio-lms folder. Your data is kept in the learnio-data volume.
learnio-lmsdocker compose downStart again with the same command as step 3. Without --build it reuses the images you already built.
learnio-lmsdocker compose upKeep your data
docker compose down -v also deletes the database volume. The next start seeds a fresh copy of the demo data, and everything you created is gone.
Run the student site
This package is the student site on its own. It runs on its bundled sample data until you point it at a Learnio API. The API is a separate package and is not in this download.
Unzip and open the folder
Terminalunzip frontend-*.zip cd frontendExpected result: The folder has a
Dockerfileand apackage.json.Build the image
The
NEXT_PUBLIC_*values are compiled into the JavaScript the browser loads, so they are build arguments. Leave them out to run on the sample data; to use your own API, pass its address.Terminalinfrontenddocker build -t learnio-site .With your own API:
Terminalinfrontenddocker build -t learnio-site --build-arg NEXT_PUBLIC_API_BASE_URL=https://api.your-domain.com/api --build-arg NEXT_PUBLIC_SITE_URL=https://your-domain.com .Start it
If port
3030is taken, change the number on the left of-p, for example-p 3041:3030, and open that port instead.Terminalinfrontenddocker run -p 3030:3030 learnio-siteExpected result: localhost:3030Local opens the site. Without an API, a "Sample data" notice at the bottom of the page says so.
Having trouble?
Run the admin dashboard
This package is the admin dashboard on its own. Without an API it runs on an in-browser mock: you can sign in and look around, but most screens stay empty until you connect a Learnio API. The API is a separate package and is not in this download.
Unzip and open the folder
Terminalunzip admin-dashboard-*.zip cd admin-dashboardExpected result: The folder has a
Dockerfileand apackage.json.Build the image
Without build arguments the dashboard uses its mock. To use your own API, pass its address, its WebSocket address (the same server without
/api) and the student site's address.Terminalinadmin-dashboarddocker build -t learnio-admin .With your own API:
Terminalinadmin-dashboarddocker build -t learnio-admin --build-arg NEXT_PUBLIC_API_BASE_URL=https://api.your-domain.com/api --build-arg NEXT_PUBLIC_WEBSOCKET_BASE_URL=https://api.your-domain.com --build-arg NEXT_PUBLIC_SITE_URL=https://your-domain.com .Start it and sign in
If port
3031is taken, change the number on the left of-p, for example-p 3041:3031, and open that port instead.Terminalinadmin-dashboarddocker run -p 3031:3031 learnio-adminExpected result: localhost:3031Local opens the sign-in form, prefilled with
Having trouble?admin@learnio.comandAdmin@123. On the mock, any email and password sign you in as the super admin.
Run the API
This package is the NestJS API on its own, on a SQLite file kept in a Docker volume. The student site and the admin dashboard are separate packages and are not in this download.
Unzip and create the environment file
.env.exampleworks as it is for a local run.Terminalunzip back-end-*.zip cd back-end cp .env.example .envBuild the image
Terminalinback-enddocker build -t learnio-api .Start it with the demo data
A fresh database gets empty tables unless you ask for the demo data. The volume keeps the database between runs. If port
8000is taken, change the number on the left of-p, for example-p 8010:8000, and use that address: your frontends must then point athttp://localhost:8010/api.Terminalinback-enddocker run -p 8000:8000 -v learnio-data:/data -e SEED_DEMO_DATA=true --env-file .env learnio-apiExpected result: localhost:8000/api/healthLocal answers with a status of
Having trouble?ok.
Without a JWT_SECRET of your own, or with the example one, the container generates a secret and keeps it in the volume.