How to Scale LifterLMS to Tens of Thousands of Students

What it takes to scale LifterLMS to tens of thousands of students: hosting for concurrency, the database tables that grow fastest, running cron and Action Scheduler properly, and keeping reports fast.

  • Add as a preferred source on Google
Illustration for “How to Scale LifterLMS to Tens of Thousands of Students”

LifterLMS has no built-in student limit. The free core plugin places no cap on courses, memberships or enrollments, and sites with tens of thousands of students run on it. What changes at that scale is everything around the plugin: how many students are logged in at once, how big a handful of tables grow, how background jobs are run, and how heavy your reports are.

This guide is for owners and developers of LifterLMS sites that are already large, or are about to be: an academy with a big launch list, a corporate training rollout, an association moving thousands of members onto CE courses. It covers hosting, the database tables that grow fastest, cron and background processing, and reporting, with specific settings and hooks from LifterLMS 10.3.

If your site is slow today with modest traffic, start with our guide on how to speed up a LifterLMS site. This article assumes the basics are in place.

Where load comes from on a large LifterLMS site

SourceWhy it growsMain fix
Concurrent logged-in studentsLesson, quiz, dashboard and checkout pages are personal, so page caching does not serve themEnough PHP workers, fast PHP, persistent object cache
wp_lifterlms_user_postmetaSeveral rows per enrollment, plus one or more per completed lesson, section and courseGood indexes and efficient queries
wp_lifterlms_eventsPage load, exit, focus and blur events on course content, plus session eventsNarrow tracking, archive old rows
wp_lifterlms_notificationsOne row per notification per subscriberArchive old rows
Action Scheduler queueRecurring payments, delayed engagements, notifications, webhooks, expirationsReal cron and a dedicated queue runner
Reports and exportsAggregates over every enrolled studentCurrent 10.x, off-peak exports, reporting copies

Hosting and architecture

For a large course site, the number that matters most is concurrency: how many students are clicking at the same moment. A site with 50,000 students and a steady trickle of activity needs less than a site with 5,000 students who all start a live cohort at 9am.

  • PHP workers. Every uncached request occupies a PHP worker. When they run out, requests queue and students see slow pages or timeouts. Size workers for your peak, not your average, and use a current PHP version.
  • A separate, well-resourced database. At scale, MySQL or MariaDB on its own server or a managed database service, with enough memory for the InnoDB buffer pool to hold the busiest tables, is the single biggest upgrade.
  • A persistent object cache. Redis or Memcached removes repeated reads of options, post meta and user meta. Our guide to Redis object caching for LifterLMS covers setup and the 10.x fixes.
  • Page cache and CDN for public pages. Sales pages, the blog and course catalogue should be served from cache. LifterLMS already sends no-cache headers on checkout, the student dashboard and quizzes.
  • Offload heavy assets. Video belongs on a video host, and email on a transactional email service, not the web server.

The database: tables that grow and how to manage them

Enrollment and progress data

wp_lifterlms_user_postmeta holds enrollments, completions and award links. It is indexed on user_id and on post_id, and most queries also filter by meta_key. At hundreds of thousands or millions of rows, check your slowest queries with EXPLAIN on a production-sized copy. If a composite index (for example on post_id, meta_key) clearly helps, test it on staging first, document it, and recheck after LifterLMS updates, since the plugin manages this table's schema. Our article on how LifterLMS stores its data explains the table's structure.

Events

LifterLMS records client-side events (page load, exit, focus and blur) on its own public post types and on account and checkout pages, plus sign-on, sign-out and session events. On a busy site that is a lot of rows. They feed activity and session information in reporting, so do not switch them off blindly, but you can narrow them with the llms_tracking_post_types filter:

<?php
// Record client-side events (page load, exit, focus, blur) on lessons and quizzes only.
// Account and checkout pages are still tracked by core.
add_filter(
	'llms_tracking_post_types',
	function () {
		return array( 'lesson', 'llms_quiz' );
	}
);

For a finer rule, llms_tracking_should_track_client_events receives the final yes or no for the current page.

Old rows

We found no scheduled clean-up of the events or notifications tables in the LifterLMS 10.3 core. If they run into millions of rows, archive older records, for example events older than two years, to a separate table or export, in small batches during quiet hours and after a backup. Decide the retention period with whoever owns your reporting and privacy policy.

Cron and background processing

LifterLMS relies on background jobs more than most plugins. Recurring payments, access plan expirations, delayed engagements, notifications and webhook deliveries run through Action Scheduler, which LifterLMS bundles. Its own WP-Cron events include llms_end_idle_sessions every five minutes, llms_delete_expired_session_data hourly, and daily log backup, temporary file clean-up and tracking jobs.

By default, WP-Cron runs only when someone visits the site, and Action Scheduler is driven from it. On a large site that is unreliable in two directions: jobs run late when traffic is quiet, and big batches run during busy page loads. The fix is to run them from the server:

  1. Add define( 'DISABLE_WP_CRON', true ); to wp-config.php, as the WordPress handbook on system cron describes.
  2. Schedule WP-Cron and the Action Scheduler queue with the system scheduler, for example:
*/5 * * * * cd /var/www/example.com && wp cron event run --due-now --quiet
* * * * * cd /var/www/example.com && wp action-scheduler run --batch-size=50 --batches=4 --quiet

The wp action-scheduler run command and its --batch-size, --batches, --group and --hooks options are documented in the Action Scheduler WP-CLI guide. Tune batch sizes to your server.

Then watch the queue. LifterLMS > Status > Scheduled Actions lists pending, past-due and failed actions. A growing number of past-due llms_charge_recurring_payment actions means renewals are late, which is lost revenue. If background processors get stuck, the Tools & Utilities tab has Delete processor batches and Delete course data locks, and Reschedule Recurring Payments repairs active orders whose next payment is missing from the queue.

Reporting at scale

Reporting is where large sites feel pain first, because a single screen can aggregate every student in a course. LifterLMS 10.2 made several changes aimed at big sites:

  • The course students table sorts by student ID by default instead of by name, avoiding expensive joins and sorts.
  • Course and membership student exports count the result set once and honour a larger export page size, cutting the number of requests by up to ten times.
  • The Time in Course column is calculated with a single query, the lesson time sessions table gained a lesson index, and per-student queries are skipped when a course has no tracked time.
  • Reports and exports no longer create per-lesson time cache rows in user meta, and an update removed the empty rows created previously.

Average progress, average grade and enrolled student counts for each course are calculated by a background processor and stored on the course, so the course overview stays fast. Beyond that, run large exports outside peak hours, and for heavy analytics feed a separate reporting database from the REST API or a read replica rather than querying production directly. Our article on slow LifterLMS admin and reports covers specific screens.

Launches, bulk enrollment and email bursts

  • Bulk enrollment. Enrolling a large group fires engagements and notifications for each student. Run it from WP-CLI or the REST API in batches, not from a browser request, and stagger welcome emails if your email provider has rate limits.
  • Launch traffic. Load test a realistic journey (log in, open lesson, mark complete, take quiz) at expected peak concurrency on a staging copy with production-sized data.
  • Checkout peaks. Checkout cannot be page cached. Make sure your gateway webhooks and receipts work under load before a big promotion.

A scaling checklist

  1. LifterLMS and add-ons on the latest 10.x release.
  2. PHP workers sized for peak concurrency; current PHP.
  3. Dedicated database with enough memory; slow query log on.
  4. Redis or Memcached object cache with a unique prefix.
  5. Page cache and CDN for public pages only.
  6. System cron for WP-Cron and Action Scheduler; queue monitored.
  7. Event tracking scoped deliberately; retention policy for events and notifications.
  8. Exports off-peak; analytics on a reporting copy.
  9. Load test before every major launch.

Frequently asked questions

How many students can LifterLMS handle?

There is no limit in the software. The practical limit is your infrastructure and how many students are active at the same time. With the setup above, tens of thousands of students is a hosting and tuning question, not a platform one.

Do I need a separate database server?

Not at first. Once your database competes with PHP for memory and CPU, or slow queries appear during busy periods, a separate or managed database is usually the best next step.

Is WP-Cron really a problem?

On a large site, yes. Recurring payments, expirations and delayed emails all depend on it. Running it from the system scheduler makes them predictable.

Next steps

Measure before you buy hardware: enable the slow query log, look at PHP worker usage at peak, and check the Scheduled Actions queue. Those three numbers show where your site will break first.

If you are planning for significant growth or a large rollout, our LifterLMS optimization service audits hosting, database and background jobs and gives you a prioritised plan. Contact us with your student numbers and peak patterns.

Add LifterLMS Expert to your preferred sources

Add lifterlmsexpert as a preferred source on Google, or open this article in your AI assistant to use it as a source.

  • Add as a preferred source on Google
Free consultation

Prefer expert help over DIY?

Skip the trial and error. Get specialist LifterLMS help and ship faster.

Talk to a LifterLMS Expert Explore our services

Replies within one business day