Definition
cfmodule (the <cfmodule> tag) in ColdFusion is a low-level way to invoke a custom tag or “module” (a CFML template that behaves like a tag). You point <cfmodule> at a .cfm file and pass attributes to it, optionally wrapping body content. The target template runs in a special custom-tag context, where it can read attributes, capture generated content, and communicate with the caller.
In plain terms: <cfmodule> lets you call a reusable CFML file as if it were a component or widget, feeding it parameters and content, and getting formatted output or data back.
How It Works
Custom tag invocation model
When you call <cfmodule template="path/to/tag.cfm" ...>Body</cfmodule>, ColdFusion:
- Locates the target template by the given path (or via the custom tag search paths).
- Executes the target template twice if it has a body: once in “start” mode and once in “end” mode, allowing the tag to treat the inner content as generated content.
- Provides special scopes to the tag:
attributes: the parameters passed in.thisTag: metadata about execution (mode, generated content).caller: a scope the tag can use to set variables in the caller’s context.
- Emits output (unless you suppress it) and returns control to the caller.
This mechanism is older than CFCs but remains valuable for reusable UI elements, wrappers, and templating.
Syntax and parameters
Basic usage:
template(required): Path to the tag template (.cfm).- Any custom attributes: Become available in the
attributesscope. attributeCollection(optional): A struct of attributes to pass in bulk.
You can place content between the opening and closing <cfmodule> tags; this “body” can be captured by the called template.
Syntax Examples
Simple call with attributes
<cfmodule template=”/customtags/renderCard.cfm”
title=”Welcome”
showIcon=”true”>
This content will be captured by the tag.
Inside renderCard.cfm:
/**
* Available:
* – attributes.title (string)
* – attributes.showIcon (boolean)
* – thisTag.ExecutionMode (“start” or “end”)
* – thisTag.GeneratedContent (available in “end” mode; inner body content)
* – caller (scope to push values back to caller)
*/
<cfif thisTag.ExecutionMode EQ “start”>
#htmlEditFormat(attributes.title)#
Passing a struct with attributeCollection
<cfset opts = {
title = “Notifications”,
showIcon = false,
cssClass = “card–secondary”
}>
<cfmodule template=”/customtags/renderCard.cfm”
attributeCollection=”#opts#”>
- No new alerts
Real-World Use Case: CMS Widget Library
A team building a CMS wants consistent, themed UI components. They implement a “widget” library as CFML Custom tags:
/customtags/renderCard.cfm/customtags/alertBox.cfm/customtags/buttonBar.cfm
Editors and developers can compose pages like:
Please update your profile.
Benefits:
- Consistent markup and styles across pages.
- Centralized changes: updating a single template updates every usage.
- Optional body content lets each widget wrap caller-supplied HTML in a standard structure.
When to Use CFModule vs Alternatives
Comparison snapshot
<cfmodule>: Explicitly call a CFML custom tag by template path; supports attributes, body content, and custom-tag lifecycle.- Custom tag syntax with
<cf_importPrefix:tagName>(via<cfimport>): A more declarative, readable approach to the same concept; often preferred when you want a “tag library” feel. <cfinclude>: Injects another template’s output inline—no custom-tag lifecycle, no attributes scope, no body content capture.- CFC methods (via
createObject,new, or DI): Call Business logic; typically return values/data instead of acting as a tag with markup. Best for services/utilities.
Tip: Use <cfmodule> or <cfimport> for UI/tag-like components; use CFCs for application logic, data, and services.
Best practices
Structure and naming
- Keep all tag templates under a known directory, e.g.,
/customtagsor use a ColdFusion mapping. This aids discoverability and Security. - Use descriptive names that reflect intent (e.g.,
renderCard.cfm,modalDialog.cfm).
Attribute handling
- Validate and normalize
attributesat the start:- Set defaults for optional attributes.
- Enforce types (e.g., boolean flags).
- Sanitize any user-visible content with
htmlEditFormat()orencodeForHTML().
Output control
- Wrap output in
cfoutputintentionally and considercfsetting enablecfoutputonly="true"inside tag templates to avoid accidental whitespace or Debugging noise. - Capture and control body output via
thisTag.GeneratedContentin the “end” phase.
Avoid dynamic template paths
- Never accept a raw
templatepath from user input. - Whitelist and map known tag locations to prevent path traversal or unexpected file execution.
Prefer cfimport for readability
- When building a tag library, use
<cfimport prefix="ui" taglib="/customtags">then call<ui:renderCard ...> ... </ui:renderCard>. - Keep
<cfmodule>for dynamic or low-level cases where you must compute a template path.
Testing and Performance
- Unit-test custom tag behavior by isolating the tag’s logic; where possible, push complex logic into CFCs and let the tag focus on presentation.
- Cache static or repetitive parts (e.g., with
cfcacheor generated HTML fragments) if tags are used heavily.
Deep Dive: The Custom Tag Lifecycle
Attributes and scopes
attributes: All name/value pairs passed by the caller, including those fromattributeCollection.caller: Use to set variables or return values to the caller, e.g.,caller.cardCount = 3;. Be intentional to avoid variable name collisions.variables: Local to the tag file—prefer this for internal state.
Execution modes: start and end (H5)
- On tags with body content, ColdFusion invokes the tag in two passes:
- Start phase:
thisTag.ExecutionMode EQ "start"— setup work here. - End phase:
thisTag.ExecutionMode EQ "end"— accessthisTag.GeneratedContentand produce final output.
- Start phase:
- On self-closing usage (no body), the tag might execute once, typically equivalent to “start” logic.
Pros and cons
Pros
- Simple, explicit way to reuse CFML markup as components.
- Supports body content capture and full custom-tag lifecycle.
- Flexible attributes passing via
attributeCollection. - Easy bridging for legacy apps that predate CFC-heavy architectures.
Cons
- Less declarative than
<cfimport>tag libraries; readability can suffer with long template paths. - Encourages template coupling if used for Business logic instead of presentation.
- Potential Security risks if template paths or attributes are not validated.
- Not as test-friendly as CFCs for complex logic.
Key Points
<cfmodule>is the foundational CFML mechanism for invoking a custom tag by template path.- Use it primarily for presentation components that accept attributes and optionally wrap caller-provided body content.
- Prefer
<cfimport>for a cleaner tag-based calling style; prefer CFCs for complex logic and testability. - Manage attributes, output, and scopes carefully to keep tags predictable and secure.
Use Cases
UI components and layout
- Cards, modals, tab panels, alert boxes, breadcrumb trails—everything that wraps HTML with consistent class names and structure.
Email templates
- Shared email sections (headers, footers, buttons) where body content varies but layout should be identical across messages.
CMS plugins
- Widgets that editors can drop into pages with parameters like
title,theme,showIcon, orlimit.
Reporting blocks
- Standardized report panels that take filters as attributes and render a consistent table/chart header and footer.
Practical Example: Building a Tag Library with cfmodule and cfimport
- Create tag files under
/customtags:renderCard.cfmalertBox.cfm
- You can call them directly with
<cfmodule>, or expose them as a tag library:- In the calling page:
<cfimport taglib="/customtags" prefix="ui"> - Then:
<ui:renderCard title="Projects"> ... </ui:renderCard>
- In the calling page:
- Internally,
<ui:renderCard>resolves to the same underlying custom tag mechanics that<cfmodule>triggers explicitly.
This hybrid approach gives you both developer ergonomics (via <cfimport>) and full control (via <cfmodule> when needed).
FAQ
What’s the difference between cfmodule and cfinclude?
<cfinclude> simply includes a CFML file and executes it inline—no attributes scope, no thisTag lifecycle, and no body content capturing. <cfmodule> treats the target as a custom tag with its own lifecycle, attributes, and optional body content.
Can cfmodule call a CFC method?
No. <cfmodule> invokes CFML templates as Custom tags. To call a CFC method, instantiate the component (e.g., new MyService().doWork()) or use dependency injection. You can, however, have your tag delegate complex logic to CFCs internally.
How do I pass a lot of attributes cleanly?
Use attributeCollection with a struct of values. This keeps calls cleaner and lets you build attributes programmatically before invoking <cfmodule>.
Is cfmodule deprecated or legacy?
It’s not deprecated, but it is older than the CFC-centric patterns many teams use today. It remains valid for UI/presentation tags, Legacy code, and plugin-style architectures.
How do I capture the inner content of a cfmodule call?
Inside the tag template, handle logic in the “end” phase and read thisTag.GeneratedContent. That string holds the caller-provided body content between the opening and closing <cfmodule> tags.
