Application.cfc VS Application.cfm

So… despite searching the forums, I have a feeling this has been addressed here and in other places. Feel free to point me to those places.

My question - Before Lucee 7 was finalized there was debate about making the Application.cfc the default choice. What I want to know is what is the advantage of Application.cfc over Application.cfm. I have asked our overload AI and also dug around a bit, but I can’t see any type of code placed in the CFC version that cannot also be in the CFM version. And as for speed, I can’t see that one would offer an advantage.

Yeah, I get the MVC angle and the Object Oriented angle as well. But most web apps honestly don’t take advantage of that in they way the designers think they will (IMO), meaning, code is often run in one place for one purpose (say, /updatePW.cfm) and the code for that doesn’t need to be shared in session scope or used in other places, so it seems overkill for a lot of CFCs aside from the MVC framework used to isolate code from a front end developer.

So with Application.cfc vs Application.cfm - why?

Well, I’d be surprised if there was much of any performance benefit. And indeed, any cfml can be placed in either file.

But there are functional differences between them, and benefits of switching to Application.cfc (though it’s true, many may not miss those). To be clear, there no real oo advantage: one could use cfc’s and oo design regardless of this choice.

So what are the differences? A few key ones are:

  • the onxxxxx methods not only provide clear separation of concerns/organization within the file, they also offer single-threading/implicit locking of their execution–when cf or Lucee implicitly call them, though NOT when other cfml explicitly calls them. The latter is little-understood but can lead to subtle bugs
  • the onrequest method, as a front-controller, has no parallel in Application.cfm (which essentially acts as the equivalent of being an implicit onrequeststart method instead)
  • the onerror method has more capability than cf error. Same with onmissingtemplate
  • there are some app-level settings that can be set only in the this scope of Application.cfc that cannot be set as attributes of cfapplication
  • Application.cfc, being a cfc, can extend/inherit from another

Others here may well offer still more benefits. But like many things in CF and Lucee, the question of whether one thing or another is “better” is as much a subjective as an objective one. Of course, some will disagree. :slight_smile:

4 Likes

Thanks Charlie! I certainly need to brush up on the items you pointed out, though it also sounds like this is a nuanced and case by case situation. That stated, it sounds like you have some specific reasons for cfc vs cfm.

To add on to @carehart 's reply, I really want to highlight that there are a growing number of settings that can ONLY be set via the application.cfc. Things like ORM, default databases, and now over a dozen others can only be set as a struct in the CFC.

If you are looking to migrate towards things like containers, it’s virtually the only way to inject server or context-level settings via code.

2 Likes

Default (or non) databases can still be set in Application.cfm. Perhaps I am not understanding your statement.

Could you give an example of “the only way to inject server or context-level settings via code.” vs in Application.CFM?

When using an Application.cfm, you are very limited in injecting structs as settings, and many of the newer features that are being rolled out in the 7.x train are set via those settings. You can technically set most of them, but you will need to write larger chunks of code to do it. The system will fight you. For example, if you want to set the new application.mailservers property, you will need to build a new array with ArrayNew, then create a new variable in a struct, and then add all the properties, one by one to the struct. It’s not going to be easy to follow.

If you want to see a selection of what those settings are, log into your Lucee Admin and go to any settings. On the bottom of each setting page (like when you edit a cache setting), it is going to give you the code you can copy into the application.cfc to propagate that setting to that application. Same with each DSN that you add into the server – you can propagate those with code – and that helps make your code more portable without having to worry about what is set in your admin registry (now .CFCconfig in modern Lucee deployments)

Honestly, it still sounds more like coding preference. For example, I set an application struct (array) used to populate the server environment, DSN, etc. Show me how this is better in Application.cfc - asking honestly, not sarcastically. The IF checks a default param and if negative, pulls the info from data, sets a struct and we’re off. If rewriting this in an Application.cfm is somehow more efficient (at the java level) or more future proof, I’d certainly like to know.

<!--- code location flag --->
<cfparam name="application.app.appSet" default="N" />
<!--- get the app settings --->
<cfif (#application.app.appSet# == "N")>
	<!--- get the settings for this app based on data from first query above --->
	<cfquery name="getAppSettings" datasource="#appStruct.tempDatasourceName#">
	SELECT app_var_names.*, app_var_values.* 
	FROM app_var_names, app_var_values 
	WHERE (app_var_names.nameID=app_var_values.nameID) 
	AND (app_var_values.codeLocation='#appStruct.codeLocation#') 
	AND (app_var_names.active='Y') 
	ORDER BY (app_var_names.varName) 
	</cfquery>
	<!--- clear previous scopes --->
	<cfscript>
		structClear(application); 
		structClear(session); 
	</cfscript>
	<!--- set the application vars --->
	<cfloop query="getAppSettings">
		<cfset "application.app." & "#varName#" = "#varValue#" />
	</cfloop>
	<!--- request and application vars set or not flag --->
	<cfset application.app.appSet="Y" />
</cfif>

So this will set application wide values I use under a custom name but within the application scope such as:

application.app.codeLocation
application.app.cookieName
application.app.datasource
application.app.hostHttps
application.app.orgName

So if application.mailservers needs an array, what’s the big deal?

I, for one, agree with you that it’s just as easy to set an app setting (such as a cfapplication attribute) to an array as it is to set it as a variable in the this scope of application.cfc.

But let’s not forget the point I’d made originally: “there are some app-level settings that can be set only in the this scope of Application.cfc that cannot be set as attributes of cfapplication”.

Finally, you somehow concluded (in your first reply to me) that “it sounds like you have some specific reasons for cfc vs cfm.”.

Actually I thought I communicated that I was pretty much on the fence of the debate, not “favoring” either side, just presenting objective considerations.

Still, @quetwo raises a practical point for the sake of Lucee folks, in that the Lucee admin feature which (uniquely) allows exporting settings for use at the app level instead does indeed only provide code suited to application.cfc.

Bottom line: as long as code using application.cfm WORKS, there’s not much reason to CHANGE it, other than for the sake of “modernizing” it (for the benefit of others who may inherit it, if not for you alone), or for such practical reasons as above.

Granted, you’ll be “swimming against the current” if you seek help related to the choice, but there are plenty of such debates in the cfml world, where some “stick with what they know”, for whatever reasons. Some will give you leeway, others will cast aspersions.

There are few hard and fast rules though, and when you hit them you’ll typically soon find the value of the alternative. :slight_smile:

As always @carehart covers most of what I wanted to say

Here’s my quick 2 cents, when I see any code using Application.cfm makes want to cry / sigh / miss my full head of hair!

Personally I find the Application.cfc approach is simply is so much cleaner

Here are some additional in depth insights

Application.cfc vs Application.cfm — What’s Actually Happening

Most articles say “use Application.cfc, it’s more modern.” Here’s what Lucee is
actually doing and why it matters.

Lookup precedence

Lucee’s application listener has two independent settings — Type and Mode
— both configurable in the admin (Settings → Request, also per mapping) or via system properties.

Type controls what it looks for:

  • Classical (CFML < 7) — only Application.cfm / OnRequestEnd.cfm
  • Modern — only Application.cfc
  • Mixed (CFML >= 7, default) — checks for both

Mode controls where it looks:

  • Current to root (default) — walks from current directory up to webroot
  • Current or root — checks current directory, then jumps straight to webroot
  • Root — webroot only
  • Current — current directory only

In Mixed + Current to root mode (the defaults), Lucee walks up from the
current directory. Within any given directory, Application.cfc is checked
before Application.cfm — but directory proximity wins over file type.

So if your layout is:

/app/subdir/Application.cfm   ← this wins
/app/Application.cfc           ← never reached

A .cfm closer to the requested page beats a .cfc further up the tree.

There is also a configurable Application Path Cache timeout — when set,
Lucee caches which application file to use for a given path rather than
re-walking the directory tree on every request. This applies to both .cfc and
.cfm equally — it’s caching the resolved path, not the compiled component.

Lifecycle methods aren’t just syntactic sugar

With Application.cfm, Lucee has no built-in code path for onApplicationStart
or onSessionStart. If you want application or session initialisation guards,
you’re writing your own locking with <cflock>.

With Application.cfc, Lucee handles it:

  • Application init — a double-checked lock keyed on your application name.
    50 concurrent cold-start requests? One runs onApplicationStart, the rest wait.
  • Session init — a lock keyed on applicationName:CFID. Same deal for
    onSessionStart.

You’d have to replicate all of that yourself in Application.cfm. Most don’t.

onRequest is genuinely different

Defining onRequest in Application.cfc routes all page requests through it —
a proper front-controller. There is no Application.cfm equivalent. Frameworks
like ColdBox rely on this.

Summary

Application.cfc Application.cfm
onApplicationStart locking Built-in (double-checked lock) DIY
onSessionStart locking Built-in (synchronized on CFID) DIY
Component singleton cache Yes No
onRequest front-controller Yes No
Inheritance Yes (extends) No

Application.cfm still works. But you’re either doing more work yourself or
quietly skipping things you probably shouldn’t be skipping.

2 Likes

Hey Charlie! Thanks for the responses! Sorry if my message came off different than intended. I certainly did not conclude that you had a preference, because you were pretty clear that you are on the fence about the argument.

When I wrote “That stated, it sounds like you have some specific reasons for cfc vs cfm.” what that should have said/read is “That stated, it sounds like people have some specific reasons for cfc vs cfm.” And you listed 6 bullet point examples.

At this moment in April of 2026, I am in agreement with what you wrote:

Bottom line: as long as code using application.cfm WORKS, there’s not much reason to CHANGE it, other than for the sake of “modernizing” it (for the benefit of others who may inherit it, if not for you alone), or for such practical reasons as above.

However, I also know you are correct here as well:

Granted, you’ll be “swimming against the current” if you seek help related to the choice, but there are plenty of such debates in the cfml world, where some “stick with what they know”, for whatever reasons. Some will give you leeway, others will cast aspersions.

There are few hard and fast rules though, and when you hit them you’ll typically soon find the value of the alternative

I want to respond to Zack and will elaborate more on my reasons for asking this. But I always value this community and the help it has provided me over the years!

1 Like

Thank you Zack! I do know that I need to change over to the cfc version. And I appreciate you being clear on how this makes you cry/sigh (LOL!). I get it.

At the moment, I have 3 CF applications that I run and I am building a 4th one for my own purposes. One of those apps was written in 1998 (IIR). I have migrated that (as noted previously in other threads) over three different OS’s and every version of CF from Macromedia, Adobe, Blue Dragon, Rails and now Lucee. And every time, the code just works becuase it’s pretty simple and straight forward.

I’d really like the apps I am running to continue to run for another 10-20 years, assuming the stack is still viable and in use. And so, it’s pretty clear that at some point I have to use Application.cfc even if I don’t change anything else in those apps.

So what I’m trying to understand is what exactly benefits me and my specific code by moving to the CFC version OTHER THAN simply modernizing the code which is 100% worth it in and of itself. But you know, it’s one of those things where -it’s not broke, -no immediate benefit and so -I’ll get to it next week/month/version/etc.

I really do appreciate everyone’s responses here and I am going to look at what you have listed here and make a plan to switch over.

:slight_smile:

Question, do you follow what I cited about locking, which avoids race conditions (and doing things every request, which means, better performance?

Happy to explain, if needed

This part?

With Application.cfc, Lucee handles it:

  • Application init — a double-checked lock keyed on your application name.
    50 concurrent cold-start requests? One runs onApplicationStart, the rest wait.
  • Session init — a lock keyed on applicationName:CFID. Same deal for
    onSessionStart.

I would love more detail.

My Application is currently set like so, using variables that are pulled from a database so that the code can be the same in both development environment and production.

<cfapplication name="#appStruct.applicationName#" clientmanagement="Yes" clientstorage="#appStruct.applicationNamePrefix#client_storage" sessionmanagement="Yes" sessionstorage="memory" sessiontimeout="#CreateTimeSpan(0,2,0,0)#" applicationtimeout="#CreateTimeSpan(21,0,0,0)#" setClientCookies="Yes" setDomainCookies="Yes">

I would be interested in finding someone to walk me though some of what I have done for so long vs “a better way,” but I know that’s not what the dev forums are for.

Mate, totally on topic here!

So a race condition is when two or more requests change an object at the same time, so at best you do everything over and over, or more subtly one request ends up seeing something being constructed or changing/ being reconstructed by another request.

You see this often surfacing has bizarre errors you can’t reproduce locally

One of the “downsides” of making Lucee faster is that it often exposes such problems.

Take for example your loading different Configs for different environments, the life cycle methods provide a great way to load them once based on your environment.

One key concept is that application settings != application scope, settings are completely isolated per request

Ok. I get the race condition and have been aware of that possibility in general in my code or any code for a long time. It do get that.

But, help me understand how the application.cfc settings prevent that and correct my thinking… and believe me I want to be motivated here. Also, when I say different environments, I am talking about the same source code being used on dev.site.com and www.site.com - one is dev, one is not.

When I set <cfapplication…> and the application is fired up for the very first time, how does a race condition happen when a user (let’s say you), pings the site 20 seconds later or even one millisecond later? Again, not arguing against the cfc version, just trying to get my head around how a race condition happens now using the cfm version and what changes with the cfc.

And to add on to that, if I have 20 default session variables that are set per user, when the user logs in, and those vars are set to the session scope (say, session.user.profile.name) how can that result in a race condition?

Derrick, what Zac is referring to is what I said in the first bullet of my first reply:

the onxxxxx methods not only provide clear separation of concerns/organization within the file, they also offer single-threading/implicit locking of their execution–when cf or Lucee implicitly call them, though NOT when other cfml explicitly calls them. The latter is little-understood but can lead to subtle bugs

To be clear, this matter has zero impact on the cfapplication tag you’ve shown. It applies only to what code you may run.

For example, you may set some application variables to hold some values. If you don’t do anything to wrap them in a condition, those run on EVERY request. If you put their assignments in onapplicationstart, Lucee and cf will ensure that only the first request making a request when the app doesn’t exist will make those assignments. Others that try to run at the very same time will be blocked, then will see that the app exists.

You could write code to do the same. It’s that you’d have to…if indeed you need to. If your app var assignments are always set to the same static values, there may be no “race condition”, if two requests run that code at the same time.

But some apps get a lot more susceptible to such race conditions, sometimes not so obviously, and the onxxxx methods help avoid them.

As for your session var assignments, it may seem reasonable that if you wrap those in a simple test for whether the session exists, you’d not hit trouble. Again there are scenarios where trouble can happen. Should you worry about it? Maybe not.

Again the main motivation of switching to application.cfc (besides simply “modernizing” or “avoiding seeming recalcitrant”) is to enjoy the benefit those on methods offer. Some don’t feel they’re motivation enough.

But the truth is that it’s usually pretty easy to convert from the one to the other, so unless it’s somehow REALLY painful in some case, there’s often more time spent debating/researching the effort than would be spent just doing it. :slight_smile:

But each has to decide for themselves. BTW, this is DEFINITELY something you could give to most any AI, asking it to convert your code from one to the other. You can/should remove any sensitive var values before doing so, if it’s a non-local AI.

Or let’s see what others may have to say in reply to you (or me).

But the truth is that it’s usually pretty easy to convert from the one to the other, so unless it’s somehow REALLY painful in some case, there’s often more time spent debating/researching the effort than would be spent just doing it.

Honestly, Charlie, Zack, Quito, you guys are awesome!

Charlie I think you answered a lot of my concerns in this response. Which is to say that I already wrap the application and session scope in conditions to prevent race conditions. However, as you say, it’s a lot easier to just get with the f’n program. (My words).

1 Like

Per page request?

yep!

I realise I am a little late to the party and in essence I am restating what has been said… but…

In your code, @derrickpeavy, you have to do the coding/work to ensure you have all the guards in all the needed places to have the protection you need.

By using Application.cfc you get to inherently (for the most part) leave that mental load at the door as the Application.cfc lifecycle methods handle it for you.

It isn’t you can’t do it - it’s why would you, when potentially (should you miss a guard somewhere) “you” have inserted (by negative means) been the reason for the fault. Using Application.cfc protects your users, your application and you.

And “I” think it bears repeating - it saves you the mental/cognitive load of checking off all the “guards”, while you code.

In your specific case - you have been doing it your way, for so long, it may now be muscle-memory to write the correct guard in the right place - but I would confidently say that I bet (even if it is just during a quick “scribble/muck-around”) that you’ve left one of those guards out - despite your comfort with your way of working for so long.

As always - do what works for you and your customers.
Change only if your needs demand it / if it is going to benefit you.

Most people, also, really like the “organisation” of Application.cfc - having THIS code in THAT function… easy to find / easy to reason about.