CFML Scopes and the Request Lifecycle

Understand where data lives, how long it survives, and why variable scoping is one of the most important skills in legacy ColdFusion maintenance.

Why Scopes Matter

ColdFusion has many places where a variable may live. Unscoped variable lookup made short code possible, but it also created ambiguity, accidental data exposure, and difficult bugs. A maintainer should identify both the variable name and its intended lifetime.

ScopeLifetimeTypical Use
variablesCurrent template or CFC instancePage variables and private component state
urlCurrent requestQuery-string input
formCurrent requestSubmitted form fields
cgiCurrent requestServer and request metadata
cookieBrowser-controlled persistenceSmall client-side identifiers or preferences
requestCurrent request, across includes/custom tagsRequest context shared by templates
sessionOne visitor sessionAuthenticated identity and per-user state
applicationShared application lifetimeRead-mostly configuration and cached data
serverEntire ColdFusion serverServer-wide data; generally avoid for application state
attributesCustom tag invocationInputs passed to a custom tag
callerCalling template from a custom tagReturning values to a custom-tag caller
argumentsFunction callFunction and CFC method parameters

Always Scope Request Input

<cfparam name="url.customerId" default="0">
<cfparam name="form.status" default="">

<cfset variables.customerId = Val(url.customerId)>
<cfset variables.status = Trim(form.status)>

Do not rely on ColdFusion to decide whether customerId came from URL, FORM, COOKIE, or another scope.

Function-Local Variables Before CF9

The explicit local scope arrived after the MX era. In MX CFC methods, declare temporary variables with var. For maximum compatibility, place those declarations before executable statements.

<cffunction name="findCustomer" access="public" returntype="query" output="false">
    <cfargument name="customerId" type="numeric" required="true">

    <cfset var customerQuery = "">

    <cfquery name="customerQuery" datasource="#variables.dsn#">
        SELECT id, name, status
        FROM customers
        WHERE id = <cfqueryparam value="#arguments.customerId#" cfsqltype="cf_sql_integer">
    </cfquery>

    <cfreturn customerQuery>
</cffunction>
Classic CFC bug: Failing to var-scope a temporary method variable can place it in the CFC's shared variables scope. Under concurrent requests, one call can overwrite another call's data.

Shared Scope Locking

Session, application, and server scopes can be shared across requests. MX-era applications often use cflock when reading or writing them.

<cflock scope="session" type="exclusive" timeout="5">
    <cfset session.lastCustomerId = variables.customerId>
</cflock>

<cflock scope="application" type="readonly" timeout="5">
    <cfset variables.supportEmail = application.supportEmail>
</cflock>

Do not hold a lock while performing a slow query, remote request, file operation, or mail send. Copy the needed value inside the lock, then do the slow work after releasing it.

Request Flow

  1. The web server maps a .cfm request to ColdFusion.
  2. ColdFusion locates the applicable Application.cfm or, in MX 7, Application.cfc.
  3. Application and request lifecycle code executes.
  4. The requested template and its includes/custom tags execute.
  5. Generated output is returned through the web server to the browser.

Scope Inspection During Debugging

<cfdump var="#url#" label="URL Scope">
<cfdump var="#form#" label="FORM Scope">
<cfdump var="#session#" label="SESSION Scope">
Never leave scope dumps enabled in production. They can reveal credentials, tokens, personal information, filesystem paths, SQL, and internal server details.