Web Template
The web template creates a server-rendered Vix web application.
Use it when you want to build a web application where C++ renders HTML pages directly on the server.
Create a web project with:
vix new site --template webWhat this template is for
Use the web template when you want:
- HTML rendered by the Vix backend
- layouts and reusable partials
- pages generated from C++ route handlers
- static CSS and JavaScript
- simple dashboards
- internal tools
- admin pages
- status pages
- lightweight server-rendered websites
This template is not a Vue app.
This template is not only a JSON API.
It is a C++ web application where Vix handles:
HTTP routes
HTML templates
static files
middleware
health checks
server startupDesign used by this template
The web template uses a simple server-rendered MVC-style design.
MVC means:
Model -> data used by the page
View -> HTML template
Controller -> route handler that prepares data and renders the viewIn this template:
PageController
-> creates template context
-> calls res.render(...)
-> returns HTMLThe main flow is:
main.cpp
-> AppBootstrap
-> templates
-> static files
-> middleware
-> routes
-> PageController
-> views/*.htmlThis design is easy to understand:
controllers/decide what page to render.views/contain HTML templates.public/contains CSS and JavaScript.routes/register controllers.middleware/registers request middleware.AppBootstrapwires everything together.
Quick start
Create the project:
vix new site --template webEnter the project:
cd siteCreate local configuration:
cp .env.example .envStart development mode:
vix devOpen:
http://127.0.0.1:8080Open the dashboard:
http://127.0.0.1:8080/dashboardCheck health:
curl http://127.0.0.1:8080/healthGenerated structure
A web project generated with:
vix new site --template webhas this structure:
site/
├── include/
│ └── site/
│ ├── app/
│ │ └── AppBootstrap.hpp
│ └── presentation/
│ ├── controllers/
│ │ ├── PageController.hpp
│ │ └── HealthController.hpp
│ ├── middleware/
│ │ └── MiddlewareRegistry.hpp
│ └── routes/
│ └── RouteRegistry.hpp
├── src/
│ ├── main.cpp
│ └── site/
│ ├── app/
│ │ └── AppBootstrap.cpp
│ └── presentation/
│ ├── controllers/
│ │ ├── PageController.cpp
│ │ └── HealthController.cpp
│ ├── middleware/
│ │ └── MiddlewareRegistry.cpp
│ └── routes/
│ └── RouteRegistry.cpp
├── views/
│ ├── base.html
│ ├── header.html
│ ├── index.html
│ └── dashboard.html
├── public/
│ ├── app.css
│ └── app.js
├── storage/
├── tests/
├── .env.example
├── .env
├── vix.app
├── vix.json
└── README.mdWhat each folder does
| File or folder | Role |
|---|---|
src/main.cpp | Minimal entry point. |
app/ | Application startup and wiring. |
presentation/controllers/ | Page and health route handlers. |
presentation/routes/ | Central route registration. |
presentation/middleware/ | Central middleware registration. |
views/ | Server-rendered HTML templates. |
public/ | Static CSS, JavaScript, images, and assets. |
storage/ | Runtime local storage. |
tests/ | Generated test target. |
.env.example | Documented environment variables. |
.env | Local runtime configuration. |
vix.app | Build manifest. |
vix.json | Project metadata, tasks, and production orchestration. |
main.cpp
main.cpp stays intentionally small.
#include <site/app/AppBootstrap.hpp>
int main()
{
site::app::AppBootstrap bootstrap;
return bootstrap.run();
}Do not put all routes, template rendering, middleware, and startup logic in main.cpp.
The startup logic belongs in AppBootstrap.
AppBootstrap
AppBootstrap owns the startup sequence.
It does four important things:
load .env
create vix::App
configure templates and public files
register middleware and routes
start the serverThe generated bootstrap configures:
app.templates("views");
app.static_dir("public", "/");Then it registers:
MiddlewareRegistry::register_all(app);
RouteRegistry::register_all(app);Finally, it starts the server with configuration:
app.run(cfg);This means the port comes from .env, not from hardcoded source code.
presentation/
The presentation/ layer is the HTTP and rendering layer.
It contains:
controllers/
routes/
middleware/Use it for:
- page routes
- template rendering
- HTTP health checks
- request middleware
- browser-facing logic
For a web template, this layer is where most of your page logic starts.
PageController
PageController owns the browser-facing pages.
Generated routes:
GET /
GET /dashboardThe controller creates a template context:
vix::template_::Context ctx;
ctx.set("title", "Home");
ctx.set("app_name", "site");
ctx.set("user", "Guest");Then it renders a template:
res.render("index.html", ctx);For the dashboard, it also shows how to pass arrays to templates:
vix::template_::Array features;
features.emplace_back("Server-rendered HTML");
features.emplace_back("Layouts with extends");
features.emplace_back("Partials with include");
features.emplace_back("Static assets");
ctx.set("features", features);Then:
res.render("dashboard.html", ctx);This is the central idea of the web template:
C++ prepares data
HTML template displays dataHealthController
HealthController owns the health endpoint.
Generated route:
GET /healthIt returns JSON:
{
"ok": true,
"status": "ok",
"service": "site",
"template": "web"
}Use /health for:
- local checks
- deployment checks
- reverse proxy checks
- monitoring
- production diagnostics
RouteRegistry
Routes are centralized in:
src/site/presentation/routes/RouteRegistry.cppThe generated registry connects controllers to the app:
controllers::PageController::register_routes(app);
controllers::HealthController::register_routes(app);When you add a new page controller, register it here.
Example:
controllers::BlogController::register_routes(app);
controllers::AdminController::register_routes(app);This keeps AppBootstrap clean.
MiddlewareRegistry
Middleware is centralized in:
src/site/presentation/middleware/MiddlewareRegistry.cppThe generated middleware registry installs:
security headers
request logging
X-Web marker headerRecommended web middleware order:
CORS
-> rate limit
-> request logging
-> security headers
-> body limits
-> auth
-> routesUse this folder when you add:
- authentication checks
- sessions
- rate limiting
- security headers
- request logging
- body limits
- custom web headers
views/
The views/ folder contains server-side HTML templates.
Generated files:
views/base.html
views/header.html
views/index.html
views/dashboard.htmlThe generated templates show:
layout inheritance
partials
variables
loops
blocksbase.html
base.html is the layout.
It defines the shared HTML structure:
<!doctype html>
<html lang="en">
<head>
<title>{{ title }} - {{ app_name }}</title>
<link rel="stylesheet" href="/app.css" />
</head>
<body>
{% include "header.html" %}
<main class="page">{% block content %}{% endblock %}</main>
<script src="/app.js"></script>
</body>
</html>Use this file for shared structure:
<head>- CSS links
- scripts
- global layout
- shared header/footer
header.html
header.html is a partial.
It is included by base.html:
{% include "header.html" %}Use partials for repeated pieces:
- navbar
- footer
- sidebar
- alerts
- shared UI blocks
index.html
index.html extends the base layout:
{% extends "base.html" %} {% block content %} ... {% endblock %}It receives data from PageController.
Example variables:
{{ title }}
{{ app_name }}
{{ user }}dashboard.html
dashboard.html shows a more advanced page.
It receives:
title
app_name
user
total_orders
featuresIt also demonstrates a loop:
{% for feature in features %}
<li>{{ feature }}</li>
{% endfor %}Use this page as a starting point for:
- admin dashboard
- internal panel
- status page
- reporting page
- customer portal
public/
The public/ folder contains static assets.
Generated files:
public/app.css
public/app.jsThe generated app mounts it at /:
app.static_dir("public", "/");That means:
public/app.css -> http://127.0.0.1:8080/app.css
public/app.js -> http://127.0.0.1:8080/app.jsUse public/ for:
- CSS
- JavaScript
- images
- icons
- fonts
- static downloads
- browser assets
Do not put C++ source code in public/.
.env.example
.env.example documents the expected configuration.
It includes values such as:
APP_NAME=site
APP_ENV=development
APP_TEMPLATE=web
SERVER_HOST=0.0.0.0
SERVER_PORT=8080
SERVER_REQUEST_TIMEOUT=5000
SERVER_IO_THREADS=0
SERVER_SESSION_TIMEOUT_SEC=20
SERVER_TLS_ENABLED=false
VIX_LOG_LEVEL=info
VIX_LOG_FORMAT=kv
PUBLIC_PATH=public
VIEWS_PATH=views
TEMPLATE_AUTO_ESCAPE_HTML=true
TEMPLATE_CACHE=true
STORAGE_PATH=storage
VIX_SERVICE_NAME=site
VIX_HEALTH_LOCAL=http://127.0.0.1:8080/health
VIX_HEALTH_PUBLIC=
VIX_PROXY_DOMAIN=When someone clones the project, they should run:
cp .env.example .env.env
.env contains local runtime values.
Use it for:
- local port
- environment name
- logging level
- public directory
- views directory
- storage path
- production diagnostics values
To change the port:
SERVER_PORT=3000Then run:
vix devThe source code does not need to change.
vix.app
vix.app is the build manifest.
It describes the executable web target.
The generated web manifest includes source files such as:
src/main.cpp
src/site/app/AppBootstrap.cpp
src/site/presentation/routes/RouteRegistry.cpp
src/site/presentation/middleware/MiddlewareRegistry.cpp
src/site/presentation/controllers/PageController.cpp
src/site/presentation/controllers/HealthController.cppIt also includes runtime resources:
resources = [
".env=.env",
"public=public",
"views=views",
"storage=storage",
]That means the web app has access to its runtime files when built.
The build flow is:
vix.app
-> Vix generates internal CMake
-> vix build compiles the web app
-> vix dev starts the app in development modeDo not edit the generated CMake project manually.
Edit vix.app.
vix.json
vix.json stores project metadata, tasks, and production orchestration.
The web template uses it for:
- project name
- version
- template type
- tasks
- production service settings
- proxy settings
- health checks
- deployment settings
- logs
- required environment variables
- web runtime defaults
Common tasks include:
vix task dev
vix task build
vix task test
vix task checkThe generated production section prepares:
production.service
production.ports
production.proxy
production.health
production.deploy
production.logs
production.env
production.webConfiguration model
The web template uses two main configuration files:
.env -> runtime values
vix.json -> project orchestrationUse .env for values that change per environment:
SERVER_PORT
VIX_LOG_LEVEL
PUBLIC_PATH
VIEWS_PATH
STORAGE_PATHUse vix.json for project-level metadata:
tasks
service name
proxy configuration
health check URLs
deployment workflow
required environment variables
web defaultsSimple rule:
.env = how the app runs here
vix.json = how Vix manages the projectGenerated routes
The web template starts with:
GET / HTML home page
GET /dashboard HTML dashboard page
GET /health JSON health checkUse:
curl http://127.0.0.1:8080/healthFor HTML pages, open in the browser:
http://127.0.0.1:8080/
http://127.0.0.1:8080/dashboardHow to add a new page
Example: add an About page.
Create a template:
views/about.htmlExample:
{% extends "base.html" %} {% block content %}
<section class="card">
<p class="eyebrow">About</p>
<h1>{{ title }}</h1>
<p class="lead">This page is rendered by Vix.cpp.</p>
</section>
{% endblock %}Add a route in PageController.cpp:
app.get("/about", [](vix::Request &req, vix::Response &res)
{
(void)req;
vix::template_::Context ctx;
ctx.set("title", "About");
ctx.set("app_name", "site");
res.render("about.html", ctx);
});Then run:
vix devOpen:
http://127.0.0.1:8080/aboutHow to add a new controller
When pages grow, avoid putting every route in PageController.
Create a new controller:
include/site/presentation/controllers/BlogController.hpp
src/site/presentation/controllers/BlogController.cppRegister it in:
src/site/presentation/routes/RouteRegistry.cppExample:
controllers::BlogController::register_routes(app);Add the .cpp file to vix.app:
sources = [
"src/main.cpp",
"src/site/app/AppBootstrap.cpp",
"src/site/presentation/routes/RouteRegistry.cpp",
"src/site/presentation/middleware/MiddlewareRegistry.cpp",
"src/site/presentation/controllers/PageController.cpp",
"src/site/presentation/controllers/HealthController.cpp",
"src/site/presentation/controllers/BlogController.cpp",
]Then rebuild:
vix buildHow to add static assets
Put static files in:
public/Examples:
public/logo.svg
public/admin.css
public/dashboard.js
public/images/hero.pngUse them in templates:
<link rel="stylesheet" href="/admin.css" />
<img src="/images/hero.png" alt="Hero" />
<script src="/dashboard.js"></script>How to add shared layouts
Use base.html for common layout.
Use partials for repeated sections.
Example:
views/footer.html
views/sidebar.html
views/flash.htmlInclude them:
{% include "footer.html" %}How to add dynamic data
Dynamic data is passed from C++ to the template context.
Example:
vix::template_::Context ctx;
ctx.set("title", "Dashboard");
ctx.set("user", "Gaspard");
ctx.set("total_orders", 42);
res.render("dashboard.html", ctx);Then in the template:
<h1>{{ title }}</h1>
<p>Welcome back, {{ user }}.</p>
<strong>{{ total_orders }}</strong>For lists:
vix::template_::Array features;
features.emplace_back("Fast C++ server");
features.emplace_back("Server-rendered HTML");
ctx.set("features", features);Template:
<ul>
{% for feature in features %}
<li>{{ feature }}</li>
{% endfor %}
</ul>Web template vs backend template
Use the web template when the main output is HTML.
Use the backend template when the main output is JSON APIs and backend services.
| Need | Template |
|---|---|
| HTML pages rendered by C++ | web |
| JSON API service | backend |
| Static assets with server-rendered pages | web |
| Controllers, middleware, health checks, production API structure | backend |
| Large frontend app with Vue | vue |
The web template can still return JSON for /health.
The backend template can still serve static files.
The difference is the main purpose.
Web template vs Vue template
Use the web template when C++ renders the HTML.
Use the Vue template when Vue renders the UI in the browser.
| Need | Template |
|---|---|
| Server-rendered HTML | web |
| Vue SPA frontend | vue |
| Simple admin or internal pages | web |
| Complex interactive frontend | vue |
| Mostly C++ driven rendering | web |
| Mostly JavaScript frontend rendering | vue |
Build and run
Start development mode:
vix devBuild:
vix buildRun:
vix runRun tests:
vix testsCheck the project:
vix check --tests --runProduction direction
The web template is production-oriented, but it is still a starter.
Before production, you will usually add:
- real error pages
- real CORS policy if needed
- real sessions or authentication
- CSRF protection for forms
- rate limiting
- template caching policy
- Nginx proxy
- TLS termination
- health checks
- service management
- logs
- deployment workflow
The template gives you the structure where these pieces belong.
When not to use this template
Do not use the web template when you only want a tiny C++ experiment.
Use the application template:
vix new hello --appDo not use the web template when your main product is a JSON API.
Use the backend template:
vix new api --template backendDo not use the web template when your main frontend is Vue.
Use the Vue template:
vix new dashboard --template vueCommon mistakes
Thinking web means Vue
The web template is server-rendered.
The HTML is rendered by Vix on the server.
For Vue, use:
vix new dashboard --template vuePutting all pages in one controller forever
PageController is enough at the beginning.
When the app grows, create more controllers:
BlogController
AdminController
AuthController
SettingsControllerForgetting to update vix.app
When you add a new .cpp file, add it to:
sources = [
]in vix.app.
Putting CSS inside templates forever
For maintainability, keep CSS in:
public/Example:
public/app.css
public/admin.cssHardcoding runtime values
Avoid hardcoding ports and paths.
Use .env:
SERVER_PORT=8080
PUBLIC_PATH=public
VIEWS_PATH=viewsWhat you should remember
The web template is for server-rendered HTML with Vix.
The main flow is:
main.cpp
-> AppBootstrap
-> app.templates("views")
-> app.static_dir("public", "/")
-> MiddlewareRegistry
-> RouteRegistry
-> PageController
-> res.render("template.html", ctx)Use each folder for its role:
| Folder | Role |
|---|---|
app/ | Startup and wiring. |
presentation/controllers/ | Page and health handlers. |
presentation/routes/ | Route registration. |
presentation/middleware/ | Middleware registration. |
views/ | HTML templates. |
public/ | CSS, JavaScript, images, and static files. |
storage/ | Runtime local storage. |
tests/ | Tests. |
Create a web app:
vix new site --template web
cd site
cp .env.example .env
vix devOpen:
http://127.0.0.1:8080
http://127.0.0.1:8080/dashboardNext steps
Continue with: