Blog

Brad Wood

January 24, 2017

Spread the word


Share your thoughts

ColdBox modules have revolutionized the way that CFML developers can reuse and organize code.  Modules follow an HMVC, or Hierarchical MVC pattern that allows you to not only break apart your CFML app into smaller chunks, but to stack those pieces into a hierarchy that really makes sense of your code.  We also call this module inceptions-- the act of nesting modules inside of each other.  

So, a question came across the ColdBox Google group today asking about how to access events from within nested modules and how that manifests itself in the URL.  Before I responded, I spun up a quick site in CommandBox to test and I found to my dismay that the answer was very difficult to find in our docs.  As such, I figured a quick blog post was in order since it's fairly easy to set up if you know what to do.

Module Routing

First, a quick review of how module routes work.  Let's create a quick site in CommandBox to test with (feel free to follow along locally).

CommandBox> mkdir moduleRouting --cd
CommandBox> coldbox create app
CommandBox> coldbox create module admin
CommandBox> server start --rewritesEnable

Ok, in a few seconds a browser should pop up with your fresh ColdBox site.  We've created a simple module called "admin".  There's two ways you can hit the admin module (Add in the port for your server):

  • http://localhost/index.cfm?event=admin:home.index
  • http://localhost/admin/home/index

The latter is what we're going to focus on.  It uses SES URLs and the URL rewriting inherent in CommandBox to produce a nice, clean URL.  In fact, you can shorten that last URL down to http://localhost/admin which uses the conventions and defaults inside the framework to default the home an index part.  That default route of "/admin" comes from the admin module's ModuleConfig.cfc where it says 

this.entryPoint = "admin";

This can really be anything, but it default to the name of the module.

Nested Modules

Ok, let's throw an "orders" module inside of our "admin" module.  We'll assume the administrator portion of your site has a subsection to handle orders.

CommandBox> cd modules_app/admin
CommandBox> coldbox create module name=orders directory=modules
CommandBox> cd ../../
CommandBox> coldbox reinit

Ok, so now we have this setup:

Your ColdBox:
 +- Admin module
    +- Orders module

So, how do we access the default event from our nested "orders" module in the url?  Well, by default the nested module's entry point is simply going to be "orders" which means the default URLs look like this:

http://localhost/orders

But what if we want to clean that up and show the same nesting in the URL that matches our module hierarchy?  There's two ways to approach this.

Override the entry point for the nested module

Ok, so let's open up the ModuleConfig.cfc from our nested orders module in your default editor:

CommandBox> edit modules_app/admin/modules/orders/ModuleConfig.cfc

Find the entry point defined before the configure method and change it like so:

// Module Entry Point
this.entryPoint = "admin/orders";

Now, issue another ColdBox reinit, and the following URL should take you to your orders module homepage:

http://localhost/admin/orders

Add module routing in the parent

Ok, the above method works great if you have control over all the code.  What if the "orders" module was something installed by CommandBox as a 3rd party dependency and you don't want to or simply cannot edit the code. No worries, our "admin" module can declare a passthrough route that tells ColdBox that we want to point to the nested module under a certain routing namespace.  Let's open up the parent admin module's config:

CommandBox> edit modules_app/admin/ModuleConfig.cfc

Find the array of routing info and add a new line to it:

// SES Routes
routes = [
    // Module Entry Point
    { pattern="/", handler="home", action="index" },
    // Passthrough route for nested module
    { pattern="/orders, moduleRouting="orders" },
    // Convention Route
    { pattern="/:handler/:action?" }
];

Ok, so we added the moduleRouting bit.  The pattern is whatever URL placeholder you want to use and is automatically appended to the entry point of the admin module.  The moduleRouting key points to the real name of the nested module that we want to route the pattern to. This gives us the same result as the previous method, but we never have to touch the nested module's code.

http://localhost/admin/orders

And in case you're wondering-- the events inside the nested module just append to the URL like you would expect.  Basically, any convention routes, or custom routes in your inner module just append themselves onto the end of the pattern above.

http://localhost/admin/orders/home
http://localhost/admin/orders/home/index

Clean up, aisle 7

OK, our work here is done.  If you followed along at home, congrats.  Let's pretend this never happened and get back to work!

CommandBox> server stop --forget
CommandBox> cd ../ && rm moduleRouting --recurse --force

 

 

 

Add Your Comment

Recent Entries

Ortus & BoxLang November Recap 2025

Ortus & BoxLang November Recap 2025

November 2025 was a big month at Ortus. BoxLang 1.7.0 arrived with real-time streaming, distributed caching, and faster compiler internals. ColdBox gained a cleaner debugging experience with full Whoops support, while CBWIRE 5 launched with stronger security, smarter lifecycles, and easier uploads.

Victor Campos
Victor Campos
December 02, 2025
Thanksgiving Week Extended + Cyber Monday Deals Are Live!

Thanksgiving Week Extended + Cyber Monday Deals Are Live!

Because you asked; we’re extending the Thanksgiving Week offer and officially launching our Cyber Monday BoxLang Deals today!

To support everyone who wants to understand whether they’re running on legacy CFML or modern-ready code, and whether BoxLang is the right fit; we’ve decided to extend the dates and increase the number of companies we can support.

Maria Jose Herrera
Maria Jose Herrera
December 01, 2025
Registration Is Now Open for Your Free BoxLang Compatibility Report! 🦃

Registration Is Now Open for Your Free BoxLang Compatibility Report! 🦃

Originally set to open on the 24th, we’ve decided to release the registration early, starting November 20th, so we can begin scheduling your BoxLang Compatibility Report audits next week and make sure they’re completed before the end of the year.

Maria Jose Herrera
Maria Jose Herrera
November 20, 2025