Everything in the file you downloaded
RustCFML is deliberately opinionated about what belongs in a language runtime: a lean, stable core, with the rest handled by libraries and by native extensions. What is in the core is the part that applications cannot do without.
Script first. Tags when you want them.
Most CFML written today is script, and it reads like it. The tags are still there: a preprocessor turns fifty-plus of them into CFScript, and everything after that is one pipeline: lexer, parser, AST, bytecode, VM. The two syntaxes are not modes bolted onto each other; by the time it runs, they are the same program.
- Arrow functions, closures and first-class functions
??,?:and?.for null coalescing, elvis and safe navigation- Member methods on arrays, structs, queries, lists and strings
- Higher-order
map(),filter(),reduce(),some(),every() - Components with single inheritance, interfaces and implicit accessors
- Spread,
for … in,try/catch/finallyand rethrow - And the tags: custom tags, tag files, and
.cfmincludes with their own output rules
Compilation pipeline and crate layout: Architecture.
component implements="Notifier" accessors="true" {
property name="webhook" type="string";
function init( required string webhook ) {
variables.webhook = arguments.webhook;
return this;
}
// Arrow functions and chained member methods.
public string function notifyAll( required array people, required string text ) {
return arguments.people
.filter( ( p ) => p.active ?: false )
.map( ( p ) => "@#p.handle#" )
.toList( " " ) & " #text#";
}
private string function truncate( required string body ) {
return arguments.body.len() > 3000
? arguments.body.left( 2997 ) & "..."
: arguments.body;
}
}
Four hundred of them, including the ones you would expect to install
Strings, arrays, structs, dates, maths, lists, queries, JSON, XML, regex, encoding and hashing, with the modern password algorithms included rather than left to a library. Where a built-in would duplicate something better served by a library, the project leaves it out and makes sure the engine can run the library.
hashPassword() and verifyPassword().xlsx read, edit and write including charts, styling and formulasencrypt(), and every hash from MD5 to SHA-512Partial surfaces and known divergences are listed under Known Issues.
<cfscript>
hash = hashPassword( form.password, "bcrypt")
digest = hash( form.email, "SHA-256" )
token = hmac( digest, application.secret, "SHA-256" )
payload = {
id = digest
, roles = [ "editor", "reviewer" ]
, seen = now()
}
body = serializeJSON( payload )
// Structs behave like structs, including in the debugger.
payload.roles
.map( ( r ) => uCase( r ) )
.each( ( r ) => writeLog( r ) )
</cfscript>
The application you already wrote, served by one flag
--serve gives you a real web server: the
Application.cfc lifecycle in the order you expect,
sessions that can live in process, in Memcached or across a cluster, cookies,
multipart uploads and Tuckey-compatible URL rewriting. This site is that feature
working: a plain CFML application with includes and a rewrite file.
- Full hook set:
onApplicationStartthroughonSessionEnd, plusonErrorandonMissingTemplate urlrewrite.xmlwith regex backreferences, conditions andlast="true"chaining- Session storage in process, Memcached or clustered, with
this.sessioncookiecontrol - Datasources, mappings and mail from
.cfconfig.json, with environment-variable substitution for secrets - Optional sandbox: isolate the filesystem the engine can see, or embed files in the binary
<?xml version="1.0" encoding="utf-8"?>
<urlrewrite>
<rule>
<from>^/([a-z][a-z0-9-]*)/?$</from>
<to last="true">/$1.cfm</to>
</rule>
<rule>
<from>^/old-page$</from>
<to type="permanent-redirect">/new-page</to>
</rule>
<rule>
<condition type="method">POST</condition>
<from>^/api/(.*)$</from>
<to>/api.cfm/$1</to>
</rule>
</urlrewrite>
Four databases, object storage, and SQL over queries
queryExecute and cfquery run
over SQLite, MySQL, PostgreSQL and MSSQL with connection pooling and
cftransaction. Query-of-queries runs on a pure-Rust SQL
engine parallelised across cores with rayon, with no JDBC and no HSQLDB in sight,
which is why it leaves Lucee more than seven times behind on the standard
benchmark suite.
.cfconfig.jsonS3* functions and transparent s3:// pathscfhttp, cfmail, and fluent Spreadsheet() builders<cftransaction>
<cfquery datasource="app">
UPDATE leads SET scored = 1
WHERE id = <cfqueryparam value="#row.id#" cfsqltype="cf_sql_integer">
</cfquery>
</cftransaction>
// No connection needed to ask a query a question.
<cfquery dbtype="query" name="hot">
SELECT region, count(*) AS n
FROM leads
WHERE scored = 1
GROUP BY region
HAVING n > 40
</cfquery>
// And the artefact lands in object storage.
fileWrite( "s3://reports/#dateFormat( now(), 'yyyymmdd' )#.csv", csv )
Threads that are actually threads
A cfthread body runs concurrently on a real OS thread,
on a separate core, not sequentially inline. application,
server, session and
request are shared live across them, which is what makes
fan-out useful and cflock necessary.
Two differences from Lucee are deliberate, and both come from doing threading
safely in Rust: terminate is cooperative rather than
forceful, because killing a thread mid-instruction can leave locks held; and a
cftransaction cannot span the parent-to-child boundary,
because its connection cannot be used from another thread.
<cfthread action="spawn" name="t#i#" tenant="#tenant#">
<cfset result = runReport( attributes.tenant )>
<cflock name="reportCache" type="exclusive" timeout="5">
<cfset application.cache[ attributes.tenant ] = result>
</cflock>
</cfthread>
<cfthread action="join" jointimeout="20">
<cfoutput>
<cfloop struct="#cfthread#" item="done">
#done.name#: #done.status# in #done.elapsedtime# ms
</cfloop>
</cfoutput>
WebSockets on the same port as your pages
One CFC per channel with lifecycle methods found by convention: authenticate on
connect, subscribe to rooms, presence in and out, and
lastEventId resumability so a reconnect does not lose
what happened while the tab was closed. Fan-out works across nodes, and any
template can emit with wsPublish().
- Raw WebSocket transport and socket.io, both supported
- Rooms, presence, per-connection auth and ack-by-return
- An imperative, socket.io-compatible API via
new SocketIoServer() - Live from a single binary, with no Redis adapter to stand up to get started
component {
// Checked before the socket is accepted.
function onAuth( required string token ) {
return accountService.verify( token );
}
function onSubscribe( required string room, required struct connection ) {
return len( room );
}
function onMessage( required string room, required string body, required struct connection ) {
wsPublish( room, { from = connection.id, text = body } )
return { delivered = true }; // ack-by-return
}
function onPresence( required string kind, required string room ) {
return kind; // "join" | "leave"
}
}
Profiler tooling, zero-cost when switched off
All of it is off by default and costs nothing until you ask for it: a Lucee-style debug footer with queries, template times and scopes; a threshold-gated sampling profiler that only records the requests slow enough to be worth recording; OpenTelemetry traces over OTLP; Prometheus RED metrics; and a native CPU profiler behind a command-line flag.
getDebugData(), isDebugMode(), debugAdd()profileNow() and getRequestProfile()--profile for a flamegraph or pprof output# a flamegraph of the running binary
rustcfml --serve ./webroot --production --profile=30
# the baseline config, with secrets from the environment
{
"datasources": {
"app": {
"type": "PostgreSQL",
"host": "db.internal",
"username": "{env:DB_USER}",
"password": "{env:DB_PASSWORD}"
}
},
"otlp": { "endpoint": "{env:OTEL_EXPORTER_OTLP_ENDPOINT}" }
}
Precompiled Rust, loaded at start-up
Drop a file in extensions/ and a stock, unmodified binary gains new built-in functions and classes. That is how this site’s sibling applications get a browser and a protocol monitor.
Statically linked into your binary
Building your own artifact? Link Rust built-ins and classes straight in, and ship one executable that contains the engine, your code and your extensions.
CFML inside a Rust program
The engine is a workspace of focused crates. Use cfml-compiler and cfml-vm as libraries and expose a scripting layer to your own application.
The same templates, everywhere you can put a binary
Static binaries for Linux and macOS, a Windows build, single-file applications, containers and a WebAssembly target that runs on Cloudflare Workers.
Start with one page
Download a binary, save a .cfm file, and be serving in under two minutes. Nothing to install, nothing to administer.