Client Variables sit between Session and Cookies: like Session, they hold data about one specific visitor. Like Cookies, they're designed to survive across completely separate visits, days or weeks apart, not just one browsing session. The difference from a plain cookie is where the data actually lives — a cookie stores everything in the browser, while Client Variables can be stored server-side (registry or database), with only an identifier kept in the browser.
Learning Objectives
After completing this lesson, you'll be able to:
- Enable client management and choose a storage backend.
- Set and read Client Variables, and know which data types they actually support.
- Explain the three storage options and why database storage is the right one for production.
- Recognize two real, easy-to-hit gotchas: a reserved datasource name, and runaway growth from bot traffic.
Enabling Client Variables
component {
this.name = "MyApp";
this.clientManagement = true;
this.clientStorage = "datasourceName"; // or "registry" or "cookie"
}The Three Storage Options
| Storage | Where it lives | Good for |
|---|---|---|
| Registry (default) | Windows registry on the server | Quick local testing only — not supported on non-Windows systems or in a server cluster |
| Cookie | The visitor's own browser | Small amounts of data, when you specifically don't want anything stored server-side |
| Database | A datasource you configure | Production — the only option that scales and works across a server cluster |
Cookie storage has real limits worth knowing: roughly 17 unique applications per browser/host combination, and a 4KB size cap per cookie (with a further hit from URL-encoding overhead). Database storage is what almost every real production app should use.
Setting and Reading Client Variables
Data Type Limits
Client Variables only support simple values directly: strings, numbers, dates, booleans, and lists. Arrays, structs, queries, and other complex types don't work directly — serialize them (with WDDX, or serializeJSON()) into a string first, and deserialize on the way back out.
Built-in, Read-Only Client Variables
- client.CFID and client.CFToken — the visitor's identifiers
- client.HitCount — how many requests this client has made
- client.LastVisit — timestamp of their previous visit
- client.TimeCreated — when this client record was first created
Deleting a Client Variable
<cfscript> structDelete(client, "favoriteColor"); </cfscript>
Lucee also has getClientVariablesList(), which returns a comma-delimited list of the client variables the current page actually has write access to (excluding the built-in read-only ones).
Real Gotcha: A Reserved Datasource Name
A genuinely reported case: naming a datasource "coldfusion" caused client variables to silently fail to persist to the database, with no error at all — client.user = "bob" simply had no effect. The datasource name collided with a reserved word. Renaming the datasource to anything else fixed it immediately. If client variables seem to just not be saving with zero errors anywhere, a colliding name is worth ruling out.
Real Gotcha: Runaway Table Growth from Bot Traffic
A new client-variable database row gets created for any request that arrives with no CFID/CFTOKEN cookies at all, to an application with client management enabled. A real, documented case: a site got hit by a scraper/bot with no cookies support, and its client-variables table grew by hundreds of rows a minute, ballooning into the millions.
This is made worse because automatic expiration cleanup for old client-variable rows doesn't always run reliably — production databases sometimes need a scheduled job to explicitly purge expired rows rather than trusting it to happen automatically.
Common Beginner Mistakes
Trying to store an array or struct directly in a Client Variable
Only simple types are supported. Serialize a complex value to a string (serializeJSON() or WDDX) before storing it, and deserialize it after reading it back.
Using Registry storage in production
It's Windows-only and doesn't work across a server cluster — fine for quick local testing, but database storage is what production applications should use.
Assuming client variable data won't grow without limits
Any request with no session cookies creates a new client-variable entry if client management is on — bot/scraper traffic with no cookie support can silently balloon the table. Monitor its size and make sure expired-row cleanup is actually running.
Best Practices
- Use database storage for anything beyond local testing.
- Avoid naming a datasource (or anything else) after a CFML reserved word — it can cause silent failures with no error message.
- Set up a scheduled job to purge expired client-variable rows rather than assuming automatic cleanup is running.
- Reserve Client Variables for genuinely long-lived, low-sensitivity preferences — not anything that changes frequently or holds sensitive data.
Interview Questions
What's the practical difference between Client Variables and Session?
Session data disappears when the visitor's session times out or their browser closes. Client Variables are designed to persist across entirely separate visits, days or weeks apart.
What's the practical difference between Client Variables and a plain cookie?
A plain cookie stores its data entirely in the browser. Client Variables can store the actual data server-side (registry or database), with only an identifier kept in the browser — and they support a defined, structured storage backend rather than raw browser storage.
Which Client Variable storage option should a production application use, and why?
Database storage — Registry is Windows-only and doesn't work in a server cluster, and cookie storage has real size and per-host application limits.
What data types can be stored directly in a Client Variable?
Only simple types — strings, numbers, dates, booleans, and lists. Complex types like arrays and structs need to be serialized to a string first.
Summary
In this lesson, you enabled Client Variables, covered the three storage options and when to use each, the simple-types-only limitation, and two real production gotchas: a reserved datasource name silently breaking persistence, and bot traffic silently ballooning the client-variables table.
That wraps up Module 8 — Application.cfc, its lifecycle, Scopes, Session Management, Cookies, and Client Variables.
What's Next?
The next module covers Reusable Code — cfinclude, custom tags, cfmodule, and building reusable layouts and templates.