How to code around limitations imposed by the Lucee Loader Architecture

Firstly, what is the Lucee Loader?


I’m not a hardcore java dev, so excuse me, if I get any of the terminology wrong.

The Loader in Lucee is the reason why you can easily upgrade and downgrade between Lucee versions, unlike with ACF which can be a complete pain to upgrade / update.

The Lucee Loader defines a stable interface which the updates (.lco files) plug into / run on top of (i.e. the flat bed truck). It’s a bit like the HAL in Windows or Project Treble in Android. We call it the fat jar, as it bundles all the extensions and is about 6x larger than the .lco core update files (i.e. the earth mover which does the actual work).

The Loader is found under a normal Lucee install, under /lib, i.e. /lucee/lib/lucee-

You cannot downgrade below the version of your Lucee loader.

Updating the loader is a manual process and requires stopping tomcat first, replacing the .jar file and then restarting tomcat.

You can download a loader from , it’s labelled lucee.jar.

Living with the Loader as a java developer

For those of us working on Lucee java code, this is often a bit of a pain, as you can’t change anything in the Loader interface as it’s stable and hasn’t changed since before I got involved with Lucee.

When developing (coughs hacking) on the Lucee java code, you should never change anything under /loader, you can only make changes under the /core as that’s what goes into the core updates, aka the .lco files.

If you do make changes the loader, sure, the build tests will pass but when you try and deploy, Lucee with throw an confusing error message saying method not found. Sure it’s there in your source code, but remember, you are deploying against the stable loader interface.

Quick Case Study

I’ve been working on adding support for specifying a custom user agent for Scheduled Tasks, which sounds easy enough, but the ScheduledTask interface is defined in the loader, so when I tried to deploy, I got the above error message, hmmmmf.

Add custom userAgent to cfschedule - LDEV-2999

Talking with @micstriit, he explained to me about the use of * interfaces in Lucee, which just extend a Loader interface, allowing us to extended Lucee whilst keeping the Loader stable, thus keeping everything nice and simple for Lucee users.

Note the // FUTURE comment, you will see them scattered across the Lucee code base, next time we decided to update the Loader, those files will be removed and the extra methods merged back into the Lucee Loader interfaces.

Hope that helps someone, feel free to ask questions!


The loader only has 2 jobs to fulfill and SHOULD do nothing else.

  • Provide interface that allows the outside world do communicate with the core (for example extensions)
  • loading/unloading the core

Of course there are exceptions to the rule, but the oyder keeps working code to a absolute minimum. So for example if you wanna create an array from outside the core, you do


This code loads the CreationUtil from the core and then that object from the core, creates the array.

The biggest benefit is that any code that communicate with the Lucee core (for example all extensions) not get impacted by any change made in the core, because the interface they use to communicate always stays the same. When we update the loader (for major version changes) we also follow some rules, that never takes away existinginterface methods unless they was deprecated since before the last major update.

BTW Lucee 6 will not get a change in the loader

1 Like