Moodle Database and Data APIs: Developer Reference Guide
Formswrite Team
•
February 15, 2026

Moodle Database and Data APIs: Developer Reference Guide
If you're building Moodle plugins or customizing your Moodle installation, you'll need to work with Moodle's internal APIs. This guide covers the key data-related APIs that every Moodle developer should know.
Moodle Core API Overview
Moodle's architecture is built on a set of core APIs that provide standardized ways to interact with the system. These are PHP-based APIs used within Moodle's codebase (not to be confused with the external Web Services REST API).
| API | Purpose |
|---|---|
| Database API (DML) | Read and write to the database |
| Data Definition API (DDL) | Create and modify database tables |
| Cache API (MUC) | Cache data for performance |
| Calendar API | Manage calendar events |
| Course API | Work with courses and modules |
| Analytics API | Build predictive models |
| xAPI | Learning experience tracking |
Moodle Database API (DML)
The Data Manipulation Language (DML) API is how all Moodle code reads from and writes to the database. You never write raw SQL in Moodle — instead, you use the global
$DB object.Getting Started
phpglobal $DB;
The
$DB object is an instance of moodle_database and provides all database operations.Read Operations
Get a Single Record
php// Get user by ID
$user = $DB->get_record('user', ['id' => 5]);
echo $user->firstname; // "Alice"
// Get with specific fields only
$user = $DB->get_record('user', ['id' => 5], 'id, firstname, email');
// Throw exception if not found
$user = $DB->get_record('user', ['id' => 999], '*', MUST_EXIST);
Get Multiple Records
php// Get all users with a specific email domain
$users = $DB->get_records_select('user', "email LIKE ?", ['%@school.edu']);
// Get records with SQL
$users = $DB->get_records_sql(
"SELECT * FROM {user} WHERE confirmed = ? AND deleted = ?",
[1, 0]
);
// Get as menu (id => fullname) for dropdowns
$courses = $DB->get_records_menu('course', null, '', 'id, fullname');
Count Records
php$count = $DB->count_records('user', ['confirmed' => 1]);
$count = $DB->count_records_select('user', "email LIKE ?", ['%@school.edu']);
Check if Record Exists
phpif ($DB->record_exists('user', ['username' => 'jdoe'])) {
// User exists
}
Write Operations
Insert a Record
php$record = new stdClass();
$record->username = 'jdoe';
$record->firstname = 'John';
$record->lastname = 'Doe';
$record->email = '[email protected]';
$id = $DB->insert_record('user', $record);
Update a Record
php$record = $DB->get_record('user', ['id' => 5]);
$record->firstname = 'Jane';
$DB->update_record('user', $record);
Delete Records
php// Delete by conditions
$DB->delete_records('user', ['id' => 5]);
// Delete with SQL
$DB->delete_records_select('log', "timecreated < ?", [strtotime('-1 year')]);
Transactions
php$transaction = $DB->start_delegated_transaction();
try {
$DB->insert_record('course', $course1);
$DB->insert_record('course', $course2);
$transaction->allow_commit();
} catch (Exception $e) {
$transaction->rollback($e);
}
Important Rules
- Always use placeholders (
?or named:param) — never concatenate SQL - Use
{tablename}syntax in raw SQL — Moodle adds the table prefix automatically - Never use
mysql_*orPDOdirectly — always use$DB
Moodle Data Definition API (DDL)
The DDL API is used in plugin install/upgrade scripts to create and modify database tables.
Define Tables in db/install.xml
xml<TABLE NAME="local_myplugin" COMMENT="My plugin data">
<FIELDS>
<FIELD NAME="id" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="true"/>
<FIELD NAME="userid" TYPE="int" LENGTH="10" NOTNULL="true"/>
<FIELD NAME="data" TYPE="text" NOTNULL="false"/>
<FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true"/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id"/>
<KEY NAME="userid" TYPE="foreign" FIELDS="userid" REFTABLE="user" REFFIELDS="id"/>
</KEYS>
</TABLE>
Upgrade in db/upgrade.php
phpfunction xmldb_local_myplugin_upgrade($oldversion) {
global $DB;
$dbman = $DB->get_manager();
if ($oldversion < 2026021500) {
$table = new xmldb_table('local_myplugin');
$field = new xmldb_field('status', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '0');
if (!$dbman->field_exists($table, $field)) {
$dbman->add_field($table, $field);
}
upgrade_plugin_savepoint(true, 2026021500, 'local', 'myplugin');
}
}
Moodle Cache API (MUC)
The Moodle Universal Cache (MUC) provides a standardized caching layer for performance optimization.
Cache Types
| Type | Persistence | Shared | Use Case |
|---|---|---|---|
| Application | Persistent | Yes (all users) | Config, computed data |
| Session | Per session | No (per user) | User preferences, temp data |
| Request | Per request | No | Computed data within one page load |
Define a Cache in db/caches.php
php$definitions = [
'mycache' => [
'mode' => cache_store::MODE_APPLICATION,
'simplekeys' => true,
'simpledata' => true,
],
];
Use the Cache
php$cache = cache::make('local_myplugin', 'mycache');
// Set
$cache->set('key1', 'value1');
// Get
$value = $cache->get('key1');
// Delete
$cache->delete('key1');
// Purge all
$cache->purge();
Moodle Calendar API
The Calendar API manages events displayed in Moodle's calendar.
Create a Calendar Event
php$event = new stdClass();
$event->name = 'Quiz Due Date';
$event->description = 'Biology Quiz Chapter 5 is due';
$event->courseid = 5;
$event->userid = 0; // 0 = course event
$event->eventtype = 'course';
$event->timestart = strtotime('2026-03-01 23:59');
$event->timeduration = 0;
$event->visible = 1;
calendar_event::create($event);
Event Types
| Type | Scope |
|---|---|
site | Visible to all users |
course | Visible to course participants |
user | Visible only to the user |
group | Visible to group members |
Moodle Course API
The Course API provides functions for working with courses and activities.
Get Course Information
php$course = get_course($courseid);
echo $course->fullname;
Get Course Modules
php$modinfo = get_fast_modinfo($courseid);
foreach ($modinfo->get_cms() as $cm) {
echo $cm->name . ' (' . $cm->modname . ')';
}
Create a Course Module
php$moduleinfo = new stdClass();
$moduleinfo->modulename = 'quiz';
$moduleinfo->course = $courseid;
$moduleinfo->section = 1;
$moduleinfo->name = 'Chapter 5 Quiz';
$moduleinfo->intro = 'Test your knowledge of Chapter 5';
$moduleinfo->introformat = FORMAT_HTML;
$module = create_module($moduleinfo);
Moodle Analytics API
Moodle's Analytics API enables predictive analytics using machine learning models.
Built-in Models
- Students at risk of dropping out — predicts dropout based on engagement
- No teaching — detects courses with no teacher activity
- No recent access — flags inactive students
Creating Custom Analytics
phpclass target_low_quiz_score extends \core_analytics\local\target\binary {
public static function get_name(): \lang_string {
return new \lang_string('targetlowquizscore', 'local_myplugin');
}
protected function calculate_sample($sampleid, $sampleorigin, $starttime, $endtime) {
// Return 1 if student scored below 60%, 0 otherwise
}
}
Analytics are processed by a scheduled task and results are shown to teachers as notifications.
Does Moodle Support xAPI?
Yes. Moodle supports xAPI (Experience API, also known as Tin Can API) through plugins:
- Logstore xAPI — sends Moodle events as xAPI statements to a Learning Record Store (LRS)
- H5P — H5P content generates xAPI statements natively
- SCORM — SCORM content can emit xAPI through conversion
What is xAPI?
xAPI is a specification for tracking learning experiences. It records statements in the format:
"Actor" + "Verb" + "Object"
Example: "Alice completed Quiz 5"
These statements are sent to a Learning Record Store (LRS) like Learning Locker, Watershed, or SCORM Cloud.
Setting Up xAPI in Moodle
- Install the Logstore xAPI plugin from moodle.org/plugins
- Configure your LRS endpoint, username, and password
- Select which events to track (course views, quiz attempts, assignment submissions)
- xAPI statements are sent automatically as students interact with Moodle
Getting Content into Moodle
While these APIs handle Moodle's internal data and logic, getting quiz content into Moodle is a separate challenge. Creating quiz questions through code requires working with Moodle's complex question bank API.
A faster approach: use Formswrite to convert Google Docs into Moodle-compatible files (XML, GIFT, Aiken, H5P) and import them through Moodle's built-in import feature. This works alongside any API-based automation you build.
FAQ
What database does Moodle use?
Moodle supports MySQL/MariaDB, PostgreSQL, Microsoft SQL Server, and Oracle. MySQL and PostgreSQL are the most common.
Can I write raw SQL in Moodle?
You should use
$DB->get_records_sql() and similar methods with the {tablename} syntax. Never write raw SQL with direct database connections.What is MUC in Moodle?
MUC stands for Moodle Universal Cache. It's the caching framework that supports application, session, and request-level caching with pluggable backends (file, memcached, Redis).
Does Moodle support Redis?
Yes. Redis can be used as a cache backend for the MUC system and for session storage.
Summary
Moodle's internal APIs give developers powerful tools for building plugins and integrations. For content creation — especially quizzes and assessments — pair these APIs with Formswrite to convert documents into Moodle-ready files automatically.