Inside Drupal LMS: Architecture, Entities and Developer Experience
A developer-level look at Drupal LMS — the entity model, the plugin architecture, Drupal 11 OOP hooks, Drush commands and the DDEV-based local development stack for building Hong Kong LMS deployments.
Key facts about the stack
- What is Drupal LMS built on?
- Drupal 10.3 or 11, PHP 8.1 or above (8.4 in the reference environment), MariaDB 11.4, nginx-fpm, Composer 2 and Drush 13.
- What is the current version?
- Drupal LMS 1.2.4, released 7 October 2026, covered by the Drupal security advisory policy. Declared compatibility is ^10.3 || ^11.
- How many core entities?
- Five: lms_activity, lms_answer, lms_lesson, lms_course_status and lms_lesson_status.
- How many activity types?
- Twelve, including four *_feedback variants that return per-response feedback to the learner.
- How do you develop locally?
- With DDEV. ddev composer si runs a standard install; ddev composer sid adds demo content and the developer console.
- Who is this page for?
- Technical buyers, IT teams and developers evaluating Drupal LMS for a Hong Kong deployment.
The stack a real deployment runs on
The reference development stack for Drupal LMS is deliberately boring, which is exactly why it is easy to hire for and cheap to host in Hong Kong:
| Layer | Component | Version |
|---|---|---|
| Application | Drupal Core | 11.x (LMS supports ^10.3 || ^11) |
| Language | PHP | 8.1+ (dev environment runs 8.4) |
| Database | MariaDB / MySQL | 11.4 in the reference environment |
| Web server | nginx + PHP-FPM | or Apache |
| CMS layer | Drupal LMS | 1.2.4 (stable, security-advisory covered) |
| CLI | Drush | 13.3+ |
| Dependency manager | Composer | 2.x with drupal.org repository |
| Local development | DDEV | Docker-based, with Tugboat preview for reviewers |
Drupal LMS 1.2.4 was released on 7 October 2026 and is covered by the Drupal security advisory policy, so stable releases receive coordinated security response. The project is maintained by Tag1 Consulting, with initial and ongoing development by the American Federation of Teachers, and reports 208 reporting sites.
The module declares compatibility with ^10.3 || ^11. If a supplier quotes you Drupal 9 or a patched 8.x core, ask why — it is well below the supported floor.
The entity model
Drupal LMS is built on Drupal's configuration-driven entity system, which is what makes it modular: everything is a bundle of a base entity type plus configuration.
| Entity | Machine name | Purpose |
|---|---|---|
| LMS Activity | lms_activity | A single thing a learner does inside a lesson |
| LMS Answer | lms_answer | Stores the learner's response to an activity |
| LMS Lesson | lms_lesson | An individual lesson within a course |
| LMS Course Status | lms_course_status | Tracks learner progress through a course |
| LMS Lesson Status | lms_lesson_status | Tracks completion status per lesson |
The status entities are the reason progress tracking in Drupal LMS is a first-class modelled concept. Progress is recorded as data, not inferred from reports — so a three-year student record is queryable without any vendor-specific export format.
Activity types and what they permit
Activity types are bundles of lms_activity. The published set covers a genuinely wide range of assessment:
select_single— single choice questionselect_multiple— multiple answer questiontrue_false— true/false questionfree_text— written responsefile_upload— file submissionwebform— a Webform form as an activityxapi_tincan— an xAPI/Tin Can activityno_answer— information-only block*_feedbackvariants —select_single_feedback,select_multiple_feedback,true_false_feedback,free_text_feedback— which return per-response feedback
The *_feedback variants matter more than they look. Immediate per-response feedback turns an activity from a grading event into a learning event, which matters for micro learning and for formative assessment inside a course.
Events, messages and notifications
LMS Messages integrates with Drupal's Message module to send notifications on LMS events. The published message types give a clear picture of the workflow the ecosystem expects:
lms_messages_new_request— a membership request was submittedlms_messages_approved_request— a request was approvedlms_messages_rejected_request— a request was rejectedlms_messages_answer_comment— a comment was added to a learner answerlms_messages_course_evaluation/lms_messages_course_evaluated— evaluation submitted / learner evaluated
For an enterprise approval workflow — the external-training scenario where an employee requests a course and a manager approves it — those first three message types are the whole cycle. An approval workflow with no notification is a workflow that stalls in an inbox.
Groups: courses, classes and cohorts
Drupal LMS uses Drupal's group module with two group types: lms_course for course groups and lms_class for class subgroups within a course. This is the mechanism behind both school class structures and enterprise cohort-based programme delivery — a Year 10 class, a management development cohort, a department-wide compliance group.
The DDEV development stack
For local development and new-project scaffolding, the ecosystem recommends a DDEV-based starter kit. DDEV gives a containerised, reproducible environment with no local PHP or database installation required.
git clone git@github.com:graber-1/drupal_lms_ddev.git
cd drupal_lms_ddev
ddev start
ddev composer install
ddev composer update drupal/lms
ddev composer si # standard install
ddev composer sid # install with demo content + developer consoleThe two install scripts are worth noting. si runs a minimal site install with existing config. sid additionally runs a Drush command called lms-ctt ("create test training" with simple passwords) and installs the developer console — producing a site with populated test content, which is exactly what you want when demonstrating to a client or onboarding a new developer.
The reference configuration is explicit: php_version: "8.4", database: mariadb 11.4, webserver_type: nginx-fpm, nodejs_version: "16", with a Selenium standalone Chrome container for browser testing and Tugboat configured for per-branch preview environments.
Drupal 11 OOP hooks and quality tooling
Drupal 11 moves hooks out of procedural files and into attributed OOP hooks. This is what a custom module hook declaration looks like:
[
'variables' => ['data' => NULL],
],
];
}The quality toolchain is part of the deal, not optional:
- PHPUnit (9, 10.5 or 11) — unit, kernel and functional tests
- PHPStan with deprecation rules and strict rules, plus a baseline for pre-existing issues
- PHPCS / PHPCBF with Drupal coding standards
- config_inspector for configuration change detection
And because Drupal LMS is itself a fork, contributing upstream is a normal workflow: clone into web/modules/contrib/lms, add your fork as a remote, work on an issue branch, and open a merge request. The module tree ships its own phpcs.xml, phpstan.neon and phpunit.xml.
Why this matters to an HK buyer
You are not buying a black box. You are buying GPL code on a mainstream CMS with a documented entity model, published contributed modules, a named maintainer, and a standard toolchain. Concretely, for a Hong Kong organisation:
- No seat licensing means a school with 1,200 students or an enterprise with 8,000 staff carries no per-user licence line.
- Published module list means you can see exactly what exists and what does not, instead of trusting a vendor feature matrix.
- Portable content — SCORM, xAPI, H5P and YAML packages all move out with you.
- Full database access and standard export, because it is your database.
- Hiring pool — Drupal and PHP skills are not niche, unlike some proprietary LMS skill sets.
All of this assumes someone competent operates it. A GPL platform with nobody to run it degrades faster than a licensed product with a support contract. That is the real trade, and it is a staffing question rather than a software question.
Questions about the platform architecture
Do we need a developer to run this?
Not to run it — administration is a normal back-office job. But somebody has to apply updates, and the more you extend the platform, the more that matters. If you have existing Drupal or PHP capability, that is a genuine advantage. If you do not, the realistic options are managed hosting or a support arrangement, and we will be direct about which fits.
What is the data model like?
Drupal LMS is built around five core entities — courses, users, content, quizzes and results — with two group types (courses and classes) and a set of message types for notifications. Progress is recorded as modelled data rather than inferred from reports, which is what makes a multi-year learner record queryable without any vendor-specific export format.
What is DDEV and why does it matter to us?
DDEV is a local development stack that lets developers bring up a working Drupal LMS environment on a laptop in minutes, using containers rather than a hand-built PHP and database environment. For you, it matters because it lowers the cost of any custom development we do for you, and it makes handover to your own team realistic.
Is Drupal 11 supported?
Yes. The rewrite targets Drupal 10.3 and above, including Drupal 11, using the object-oriented attribute-based hook system rather than the legacy procedural approach. The article covers the developer-experience differences that matter if your team will maintain custom code.
How much custom development will we need?
Usually configuration rather than code. The realistic sources of custom work are an integration that has no existing path, a report the standard views cannot produce, or content that behaves in a way the authoring tools do not support. We scope each of these explicitly and tell you when a requirement should be dropped rather than built.
Want to see Drupal LMS running with your own content?
Send us a few of your real course forms and one SCORM package. We will build a demo environment around them — not a generic sample — so you can judge the actual fit.