Getting Started
This walks through wiring Coldspa into a fresh project from scratch — installing both halves (CFML + Node), setting up the renderer, and rendering your first island.
Prerequisites
Section titled “Prerequisites”- ColdFusion (Adobe ColdFusion 2023+ or Lucee 5+)
- Node.js 22+
- A web server pointed at your CFML webroot
- One of: Vue 3 / React 18+
1. Install the CFML side
Section titled “1. Install the CFML side”Via CommandBox:
box install coldspaThis drops the package at ./modules/coldspa/, including Island.cfm, Slot.cfm, the renderer files (coldspa/renderers/Vue.cfm, coldspa/renderers/React.cfm), and the SSR sidecar.
2. Wire up Application.cfc
Section titled “2. Wire up Application.cfc”Two things need to happen here:
- Register the module’s directory as a custom tag path so
<cf_Island>and<cf_Slot>resolve from anywhere. - Delegate the three lifecycle methods to
coldspa.Bootstrapso Coldspa can cache its config and auto-spawn the Vite dev server + Node SSR sidecar.
component { this.name = "MyApp"; this.customTagPaths = expandPath("/modules/coldspa");
function onApplicationStart() { new coldspa.Bootstrap().onApplicationStart(); return true; }
function onApplicationStop() { new coldspa.Bootstrap().onApplicationStop(); }
function onRequestStart(targetPage) { new coldspa.Bootstrap().onRequestStart(); return true; }}What each delegate does:
onApplicationStart— cachesapplication.coldspaConfigand (in dev) spawnsviteand the SSR sidecar in the background. In production it validatesdist/.vite/manifest.jsonand runsnpm run buildonce if it’s missing.onApplicationStop— tears down the spawned Node processes so they don’t outlive the CF app.onRequestStart— enables the?reloadConfig=1and?reloadApp=1dev hooks. No-op otherwise.
Logs from the spawned processes land in WEB-INF/coldspa-logs/{vite,ssr,manager}.log.
ColdBox users can skip this step entirely — the bundled ModuleConfig.cfc registers the custom tag path and hooks Bootstrap into the afterAspectsLoad, preReinit, and preProcess interceptors.
Managing Node yourself? If you’d rather run Vite/SSR under systemd, docker-compose, or your platform’s process supervisor, set COLDSPA_NO_BOOTSTRAP=1 in the CF process env. Bootstrap.onApplicationStart will still cache config but skip the spawn. Coldspa also auto-detects this when npm isn’t on PATH (the typical CF-in-Docker case) — see Docker & cross-host setups.
3. Install the Node side
Section titled “3. Install the Node side”Coldspa uses Vite for asset bundling and a small Node sidecar for server-side rendering.
npm install coldspa vite vue @vitejs/plugin-vue # Vue# ornpm install coldspa vite react react-dom @vitejs/plugin-react # ReactColdspa lists every runtime framework package as an optional peer dependency, so you only install what you actually use. Install the matching Vite framework plugin in your app because your Vite config owns that setup.
4. Configure Vite
Section titled “4. Configure Vite”import { defineConfig } from 'vite';import vue from '@vitejs/plugin-vue';import coldspa from 'coldspa/vite';
export default defineConfig({ plugins: [ vue(), coldspa({ frameworks: ['vue'], globs: { vue: '/src/**/*.vue' } }) ]});For React, import react from @vitejs/plugin-react, add react() to plugins, and set frameworks: ['react']. For mixed Vue + React configs, include both framework plugins before coldspa(...).
The Coldspa plugin handles client-entry shims, manifest output, and dev-server host binding for you.
5. Add package.json scripts
Section titled “5. Add package.json scripts”{ "scripts": { "dev": "vite", "ssr": "coldspa-ssr", "build": "vite build && cross-env COLDSPA_SSR=1 vite build", "ssr:prod": "coldspa-ssr --prod" }}coldspa-ssr is the SSR sidecar binary shipped in the npm package. Keeping it behind an ssr script lets coldspa.Bootstrap start the sidecar automatically with npm run ssr.
If Vite’s dependency optimizer cache needs to be rebuilt during development, run the sidecar with coldspa-ssr --force or npm run ssr -- --force.
6. Configure runtime URLs (optional)
Section titled “6. Configure runtime URLs (optional)”For local single-host dev, the defaults are fine. Otherwise create a coldspa.config.json at the webroot:
{ "isDev": true, "ssrUrl": "http://127.0.0.1:5174", "viteUrl": "http://localhost:5173"}See Configuration for every key and Docker & cross-host setups when CF and Node live on different machines or containers.
7. Write your first component
Section titled “7. Write your first component”<script setup>defineProps({ hello: { type: String, default: '' } });</script>
<template> <div class="island"> <h2>Hello, {{ hello }}!</h2> <slot /> </div></template>8. Mount it from CFML
Section titled “8. Mount it from CFML”<!--- index.cfm ---><cfinclude template="/modules/coldspa/coldspa/renderers/Vue.cfm">
<cf_Island framework="#Vue#" path="./src/App.vue" props="#{ hello: 'World' }#" strategy="visible">
<p>This sentence comes from the default slot in CFML.</p></cf_Island>9. Run it
Section titled “9. Run it”Start your CF server. That’s it — Bootstrap.onApplicationStart spawns both vite and the SSR sidecar for you in the background. Load the page and you should see your component server-rendered into the response, then hydrated when it scrolls into view.
If you’d rather drive the Node side yourself (set COLDSPA_NO_BOOTSTRAP=1 first), use two terminals:
npm run dev # Vite dev server (HMR)npm run ssr # Node SSR sidecarDuring iteration:
?reloadConfig=1— re-readscoldspa.config.json+ env vars without bouncing the app.?reloadApp=1— also tears down and re-spawns the Node processes.
10. Build for production
Section titled “10. Build for production”npm run build # builds client bundle (dist/) AND SSR bundle (dist-ssr/)npm run ssr:prod # runs the sidecar against the built bundleSet isDev: false (or CF_ENV=production) so CFML reads from dist/.vite/manifest.json instead of the dev server. With Bootstrap wired up, the production sidecar (npm run ssr:prod equivalent) is launched automatically on onApplicationStart — no separate process to babysit. Set COLDSPA_NO_BOOTSTRAP=1 if you’d rather run it under systemd / docker-compose / your platform’s supervisor.
Where to next
Section titled “Where to next”- Hydration strategies —
load,idle,visible,client - Slots — default + named slots,
<cf_Slot>rules, gotchas - Configuration — full env var and
coldspa.config.jsonreference - Docker & cross-host setups — CF and Vite on different hosts