Skip to content

Start Here

Anatomy of a Wheels App

Every Wheels 4 application — whether it came from wheels new, box install wheels-base-template, or a zip you extracted by hand — has the same shape. This page is the map. If you're coming from Wheels 2.x, the biggest change is that the framework moved from a wheels/ folder at the root into vendor/wheels/, and the web root moved to public/.

myapp/
app/ Your application code
controllers/ Controllers (plural PascalCase: Users.cfc)
models/ Models (singular PascalCase: User.cfc)
views/ One folder per controller, plus layout.cfm
events/ Application/request lifecycle hooks
global/ Global user-defined functions
jobs/ Background jobs (extend wheels.Job)
middleware/ Custom middleware components
migrator/migrations/ Database migration CFCs
snippets/ Scaffolded snippet templates
config/ Configuration, loaded at application start
settings.cfm Datasource, reload password, URL rewriting, …
routes.cfm Your routes (mapper() … .end())
environment.cfm Which environment this deployment runs as
app.cfm Application.cfc-level settings (this.name, mappings, …)
<environment>/ Per-environment overrides (production/settings.cfm, …)
db/ SQLite database files, if you use SQLite
public/ THE WEB ROOT — the only folder a browser can reach
Application.cfc Bootstraps the app: defines mappings, loads .env
index.cfm Single entry point; hands every request to the dispatcher
urlrewrite.xml Rewrite rules for Tuckey (CommandBox/wheels CLI servers)
stylesheets/, javascripts/, images/, files/, miscellaneous/
tests/ Your test suite
specs/ models/, controllers/, functional/ (+ views/, integration/, browser/)
populate.cfm Optional test-data seeding
vendor/ Third-party code — you don't edit anything in here
wheels/ THE FRAMEWORK ITSELF
<package>/ Installed packages (wheels-sentry, wheels-basecoat, …)
.env Environment variables (copy from env.example; never commit)
box.json ForgeBox manifest — only used by CommandBox installs
server.json CommandBox server config — only used by CommandBox

There is no magic registry and no generated wiring. public/Application.cfc defines six CFML mappings, all relative to the public/ folder:

this.mappings["/app"] = expandPath("../app/");
this.mappings["/vendor"] = expandPath("../vendor/");
this.mappings["/wheels"] = expandPath("../vendor/wheels/");
this.mappings["/tests"] = expandPath("../tests");
this.mappings["/config"] = expandPath("../config");
this.mappings["/plugins"] = expandPath("../plugins");

That's the whole contract. Point any CFML-capable web server at public/ and the app can find its own code, no matter where on disk the folder sits or what tool put it there. It also means everything outside public/ — your models, your config, your .env, the framework itself — is unreachable from a browser.

  • app/ — everything you write. Controllers extend Controller, models extend Model, views execute in the controller's variable scope. Conventions (naming, pluralization) are covered in Conventions over Configuration.
  • config/ — read once at application start. Changing anything here requires a reload (restart the app, or ?reload=true&password=… — see Working Without the CLI).
  • public/ — the web root and only the web root. Static assets are served directly; everything else routes through index.cfm to the dispatcher.
  • vendor/ — the framework plus any installed packages. Treat it as read-only: upgrades replace vendor/wheels/ wholesale, so local edits there are lost by design.
  • tests/ — your app's test suite, run via wheels test, or without the CLI at /wheels/app/tests in development. See Testing.
  • db/ — only meaningful for SQLite setups; other databases live wherever your server keeps them.
  • box.json / server.json — CommandBox metadata. If you neither use CommandBox nor plan to, they're inert; leaving them in place costs nothing and keeps the door open.

Inside vendor/wheels/ two things deserve a mention even though you never edit them:

  • vendor/wheels/Injector.cfc — the built-in dependency-injection container. Wheels 4 does not depend on WireBox; if you remember downloading WireBox for Wheels 3, that requirement is gone.
  • vendor/wheels/wheelstest/ — the built-in test framework (wheels.WheelsTest). Wheels 4 does not depend on TestBox either; the TestBox-and-four-hidden-modules scavenger hunt from the 3.0 era is over.

Both facts matter to one specific reader: the person assembling an app from zips. The complete dependency list for a Wheels 4 app is: the framework. See Manual Installation.