A high-performance CFML (ColdFusion Markup Language) runtime engine and application server. Compiles .cfm/.cfc templates on-the-fly into native machine code via LLVM JIT compilation and serves requests through the FastCGI protocol.
WebStrada is a from-scratch re-implementation of a ColdFusion server. Instead of interpreting CFML, it parses templates into an AST using TextParser, generates LLVM IR, and JIT-compiles to native code for execution.
CFML Source → TextParser AST → LLVM IR → MCJIT → Native Code → Execution
- CMake >= 3.16
- Ninja build system
- C++23 compiler (GCC or Clang)
- LLVM development libraries
- libfcgi (FastCGI)
- libminizip (for
<cfzip>archive support; Debian/Arch package:minizip)
git submodule update --init --recursive
./build.sh # GCC (default)
# or
./build_clang.sh # Clang
# or
./build-release.sh # Size-optimized release build (see below)Release builds (smaller binary) can be produced with ./build-release.sh
into the build-release/ directory. It configures -O3,
-ffunction-sections/-fdata-sections with --gc-sections, folds
byte-identical functions with gold --icf=safe, and strips symbols. It
uses gold because the project enables LTO (-flto) and GNU ld/lld
cannot combine GCC's LTO plugin with ICF. Optional LTO is on by default
via the project's CMake settings; pass --lto to also enable CMake
interprocedural optimization. On this project this roughly halves the
binary size versus the plain debug build.
Release builds use precompiled headers (include/webstrada/pch.h for the
runtime and include/webstrada/pch_llvm.h for the LLVM code generator) to
speed up compilation: on a 24-core machine a full clean release build drops
from ~54s to ~36s. PCH is enabled for Release builds only: in debug
builds a developer edits headers frequently, and editing any header listed
in the PCH invalidates it and forces a full project rebuild -- the opposite
of a fast debug edit-rebuild cycle. Only stable headers are precompiled
(the STL, the C libraries, and the core webstrada/* headers); frequently
edited headers such as cffunctions/common.h stay out of the PCH so edits
do not invalidate it. pcre2.h is also excluded because its API is
selected by PCRE2_CODE_UNIT_WIDTH at include time. PCH can be forced on
or off with -DWEBSTRADA_USE_PCH=ON/OFF.
Artifacts are placed in bin/:
| Binary | Description |
|---|---|
WebStrada |
FastCGI application server |
WebStrada-cli |
CLI tool for compiling/running CFML from stdin or file |
libwebstrada-core.a |
Core runtime static library |
libwebstrada-compiler.a |
LLVM compiler static library |
build_docker.sh builds a multi-stage Arch Linux Docker image: a builder
stage (archlinux:base-devel) compiles the textparser dependency from
upstream plus the project sources, and a runtime stage (archlinux) keeps
only the binaries and shared libraries the server needs. The image web root is
/app; http-dev.py serves HTTP on port 8501 and auto-starts the FastCGI
daemon, which can also be run directly on the TCP socket :6000.
./build_docker.sh # builds webstrada:latest
docker run --rm -p 8501:8501 webstrada # dev web serverEnvironment overrides: IMAGE=name:tag (default webstrada:latest) and
TEXTPARSER_VERSION=x.y.z (default 1.0.7).
# Execute CFML from stdin without loading Application.cfm/cfc
echo '<cfdump var="hello" />' | ./bin/WebStrada-cli --stdin
# Print LLVM IR instead of executing
echo '<cfdump var="hello" />' | PRINT_AST= ./bin/WebStrada-cli --stdin
# Compile and run a file (loads Application.cfm/cfc if present)
./bin/WebStrada-cli mytemplate.cfm./bin/WebStrada -n :6000 -b 100 -w 4Options:
-n <socket>— FastCGI socket name (default:6000)-b <backlog>— connection backlog (default100)-w <workers>— number of worker processes (default1)
http-dev.py is a single-file Python dev server (stdlib only) for quick
manual testing without nginx. It listens on TCP port 8501 (all interfaces)
by default, serves a web root and forwards .cfm/.cfc requests to the
WebStrada FastCGI daemon — which it starts automatically on a unix socket in
<app-root>/tmp/ (reusing an already running daemon if present) — while
serving everything else as a static file.
By default the web root is the directory containing the script, but it can be
pointed at any directory (e.g. a mounted host volume) with --webroot or the
WEBROOT environment variable. The built admin panel (admin/dist/...) and
its /admin/api/*.cfm endpoints are always served from the app root at
/admin/, independent of the web root.
python3 http-dev.py [--host 0.0.0.0] [--port 8501] [--workers 4] [--webroot DIR]
WEBROOT=/path/to/site python3 http-dev.py --port 8501The webstrada:latest image bundles the WebStrada binaries, the textparser
libraries and the built admin panel. Run it with your CFML site mounted as the
web root:
# Serve a host directory as the web root (port 8501):
docker run --rm -p 8501:8501 -v /path/to/your/cfml/site:/app/webroot -e WEBROOT=/app/webroot webstrada:latest
# then visit http://localhost:8501/ (your pages) and http://localhost:8501/admin/ (admin panel)
# Or just run the stock web root (the app dir, includes /admin):
docker run --rm -p 8501:8501 webstrada:latestBuild the image with ./build_docker.sh (pass --no-cache to force a full
rebuild).
MIT