DevLearningTools

MODULE 17 · LESSON 01

Introduction to MVC

Model-View-Controller in ColdFusion: what each layer is actually responsible for, what vanilla CFML MVC looks like in code, a real gap between the pattern and what frameworks add on top of it, and the ColdFusion framework landscape.

New lessons are added one at a time as the course gets built out — a graded quiz for each lesson is still on the way.

Module 16 was about making an application fast and observable. Module 17 is about making it maintainable as it grows. A single .cfm file mixing a database query, business rules, and HTML in one place works fine for a small page and becomes unworkable once an application has dozens of them. MVC is the standard answer to that problem.

Learning Objectives

After completing this lesson, you'll be able to:

  • Explain what each of Model, View, and Controller is actually responsible for.
  • Write a basic Model, View, and Controller in vanilla CFML.
  • Know a real gap between the MVC pattern itself and what a framework like ColdBox adds on top of it.
  • Recognize the major ColdFusion MVC frameworks by name: ColdBox, FW/1, CFWheels, and the legacy ones you'll still see in older codebases.

How a Request Flows Through MVC

Client Request Arrives

a form submission or a URL

Controller Orchestrates

decides what to do about it

Model Handles Data

query, validation, business rules

View Renders the Output

HTML, or a JSON response

The Three Layers

LayerResponsible ForNever Does
ModelData access, validation, business rulesKnow anything about HTML or the browser
ViewPresentation, formatting data for outputRun a SQL query or decide application logic
ControllerReceiving the request, calling the Model, choosing the ViewContain the actual business logic itself

The Model: Data and Business Logic

CFScript (UserModel.cfc)
component {
    public query function getUsers() {
        return queryExecute(
            "SELECT id, name, email FROM users ORDER BY name",
            {},
            { datasource: "myDSN" }
        );
    }
}

The View: Presentation Only

Tag Syntax (views/users/list.cfm)
<h1>User List</h1>
<table>
    <cfoutput query="users">
        <tr>
            <td>#encodeForHTML(name)#</td>
            <td>#encodeForHTML(email)#</td>
        </tr>
    </cfoutput>
</table>
NOTE

The View only formats data it's handed, it never queries the database itself. encodeForHTML() here is the same output-encoding function from the XSS Prevention lesson, a View outputting unencoded data is exactly the vulnerability that lesson covered.

The Controller: The Traffic Cop

CFScript (UserController.cfc)
component {
    property name="userModel";

    public function list() {
        var users = userModel.getUsers();
        return view("users/list", { users: users });
    }
}

A Real Gap: view() Isn't a Native CFML Function

The Controller example above reads cleanly, but that view() call is doing a lot of invisible work: resolving "users/list" to an actual file path, passing variables into that template's scope, and rendering it as the response. None of that exists in vanilla CFML. Plain ColdFusion has no built-in router, no automatic Controller dispatch, and no view() helper, you'd wire all of that yourself with something like a single index.cfm front controller that reads the URL, calls the right CFC method, then cfincludes the matching .cfm template with the Model's data in scope. What ColdBox, FW/1, and CFWheels actually provide isn't the MVC pattern itself (you can write that by hand, as shown above), it's that routing and dispatch wiring, plus dependency injection, logging, and caching built on top of it.

Popular ColdFusion MVC Frameworks

FrameworkKnown For
ColdBoxThe most actively maintained, enterprise-grade option. Built by Ortus Solutions, with dependency injection via WireBox, plus built-in caching, logging, and security tooling
FW/1 (Framework One)Lightweight, convention-over-configuration, minimal setup, maps URLs to folders automatically
CFWheelsInspired by Ruby on Rails, with an Active Record-style approach to database interaction
Fusebox, Mach-II, Model-GlueOlder frameworks you're more likely to encounter maintaining an existing codebase than choosing for a new one

Common Beginner Mistakes

Letting the View run its own database query

The moment a .cfm template runs a cfquery directly, it's no longer just a View, it's back to mixing concerns. The Model fetches data, the View only formats what it's handed.

Putting business logic in the Controller instead of the Model

The Controller should orchestrate (call the Model, pick the View), not contain the actual validation rules or calculations itself. Logic that lives in the Controller is harder to reuse and test than logic that lives in the Model.

Assuming view() or a router is just part of CFML

They're not, vanilla ColdFusion has no built-in MVC dispatch mechanism. That convenience comes from adopting a framework like ColdBox or FW/1, or building the equivalent wiring by hand.

Best Practices

  • Keep the Model ignorant of HTML entirely, it should work the same whether its output ends up in a View or a REST API response.
  • Keep business logic out of the Controller, it orchestrates, the Model decides.
  • Encode output in the View the same way covered in the XSS Prevention lesson, regardless of which layer the data originally came from.
  • For a new project, reach for an established framework (ColdBox or FW/1) rather than hand-rolling the routing and dispatch layer from scratch.

Interview Questions

What's the core problem MVC solves compared to a traditional single-file .cfm page?

A single file mixing database queries, business rules, and HTML becomes hard to maintain and test as an application grows. MVC separates those concerns into three layers, each with one responsibility.

What exactly does a framework like ColdBox add on top of the MVC pattern itself?

The MVC pattern (Model, View, Controller as separate layers) can be hand-written in vanilla CFML. A framework adds the routing/dispatch wiring between them (resolving a URL to a Controller action, rendering the matching View), plus extras like dependency injection, caching, and logging.

Why shouldn't the View execute a database query directly, even if it would technically work?

It breaks the separation of concerns MVC exists for. The View would then depend on knowing how to fetch data, making it harder to reuse, test, or swap out independently of the Model.

Summary

In this lesson, you broke an application into Model, View, and Controller layers, wrote a basic version of each in vanilla CFML, saw a real gap between the MVC pattern itself and what a framework adds on top of it, and got an overview of the ColdFusion framework landscape: ColdBox, FW/1, CFWheels, and the legacy names you'll still run into.

What's Next?

The next lesson looks at ColdBox specifically, the most widely used modern ColdFusion MVC framework.