App Bootstrap
The backend template keeps main.cpp small and moves the startup sequence into AppBootstrap. This file is the place where the backend is assembled before it starts listening for requests.
AppBootstrap does not own every feature in the backend. Its job is to create the application, load runtime configuration, configure shared runtime paths, register middleware, register base routes, connect generated modules, and start the server. That makes the backend startup path visible without turning the entry point into a large file.
src/main.cpp
-> AppBootstrap
-> configuration
-> vix::App
-> public files and views
-> middleware
-> routes
-> generated modules
-> app.run(...)Entry point
The generated main.cpp delegates directly to the bootstrap.
#include <api/app/AppBootstrap.hpp>
int main()
{
api::app::AppBootstrap bootstrap;
return bootstrap.run();
}This keeps the process entry point stable. The main function starts the backend, but it does not need to know how middleware, routes, static files, views, or modules are wired.
Bootstrap declaration
The bootstrap class is declared under the project include directory.
include/api/app/AppBootstrap.hppThe generated class exposes one main function.
namespace api::app
{
class AppBootstrap
{
public:
AppBootstrap() = default;
~AppBootstrap() = default;
AppBootstrap(const AppBootstrap &) = delete;
AppBootstrap &operator=(const AppBootstrap &) = delete;
AppBootstrap(AppBootstrap &&) = delete;
AppBootstrap &operator=(AppBootstrap &&) = delete;
int run();
};
}The class is intentionally small. It is not a service container and it is not a general application framework. It owns the startup sequence of this backend process.
Startup implementation
The implementation lives in:
src/api/app/AppBootstrap.cppThe generated implementation includes the backend registries and the generated app module bridge.
#include <api/app/AppBootstrap.hpp>
#include <api/presentation/middleware/MiddlewareRegistry.hpp>
#include <api/presentation/routes/RouteRegistry.hpp>
#include <vix_app_modules.hpp>
#include <vix.hpp>
#include <vix/log.hpp>The important include is:
#include <vix_app_modules.hpp>That header is generated by Vix when the project uses app modules. It gives the backend one stable generated entry point for enabled modules.
Configuration
The bootstrap starts by loading runtime configuration from .env.
vix::config::Config cfg{".env"};
vix::App app;This keeps runtime values outside the compiled binary. The generated .env.example documents the expected variables, and the local .env file provides the values used by the application during development or deployment.
A normal local workflow starts by copying the example file.
cp .env.example .envThe backend then reads values such as the server port, public directory, templates directory, static cache settings, compression settings, storage path, database defaults, and production diagnostics.
Public files and views
The generated bootstrap reads public file and template settings from configuration.
const std::string viewsPath = cfg.getString("templates.path", "views");
const std::string publicPath = cfg.getString("public.path", "public");
const std::string publicMount = cfg.getString("public.mount", "/");
const std::string publicIndex = cfg.getString("public.index", "index.html");
const std::string publicCacheControl =
cfg.getString("public.cache_control", "public, max-age=3600");
const bool publicSpaFallback =
cfg.getBool("public.spa_fallback", false);Then it configures the template directory and static files.
app.templates(viewsPath);
app.static_dir(
publicPath,
publicMount,
publicIndex,
true,
publicCacheControl,
true,
publicSpaFallback);This matters because the backend runs from the build output. Runtime directories such as public/, views/, and storage/ are declared as resources in vix.app, so they can be copied beside the built executable.
resources = [
".env=.env",
"public=public",
"views=views",
"storage=storage",
]Static compression
The generated backend can enable compression for static responses through configuration.
const bool publicCompression = cfg.getBool("public.compression", false);
const int publicCompressionMinSize =
cfg.getInt("public.compression_min_size", 1024);When enabled, the bootstrap creates compression options, registers compression middleware, and installs the static response hook.
const auto compressionOptions =
vix::middleware::performance::CompressionOptions{
.min_size = static_cast<std::size_t>(publicCompressionMinSize),
.add_vary = true,
.enabled = true,
};
auto compressionMiddleware = vix::middleware::app::adapt_ctx(
vix::middleware::performance::compression(compressionOptions));
app.use(std::move(compressionMiddleware));
vix::App::set_static_response_hook(
vix::middleware::performance::compressed_static_response_hook(
compressionOptions));The setting is disabled by default in the generated environment file.
PUBLIC_COMPRESSION=false
PUBLIC_COMPRESSION_MIN_SIZE=1024This gives the project a production-ready path without forcing compression during the first local run.
Middleware registration
After configuring runtime paths, the bootstrap registers global middleware.
presentation::middleware::MiddlewareRegistry::register_all(app);The generated middleware registry owns application-wide HTTP middleware such as security headers, request logging, and API-level markers.
AppBootstrap
-> MiddlewareRegistry
-> security headers
-> request logging
-> API marker headerMiddleware belongs outside AppBootstrap because it can grow independently. The bootstrap only decides when middleware is added to the application startup flow.
Route registration
The bootstrap then registers base application routes.
presentation::routes::RouteRegistry::register_all(app);The route registry connects the generated controllers.
RouteRegistry
-> HomeController
-> HealthControllerThe generated backend starts with:
GET /api
GET /health
GET /api/healthThese routes are application-level routes. Feature-specific routes should normally move into app modules as the backend grows.
Generated module registration
The backend template is ready for application modules. After registering base routes, the bootstrap calls the generated module bridge.
vix::app_generated::register_app_modules(app);This line is important. It lets enabled modules from vix.app register their routes without requiring AppBootstrap.cpp to include every module controller manually.
A module declaration may look like this:
[module.auth]
enabled = true
path = "modules/auth"
kind = "backend"
depends = []When the module is enabled, Vix can generate registration code that conceptually behaves like this:
void register_app_modules(vix::App &app)
{
api::auth::AuthModule::register_routes(app);
}The generated registration files are managed by Vix. Do not edit them directly. Change vix.app, the module files, or the module metadata, then run the normal workflow again.
vix modules check
vix buildStartup log
Before running the server, the bootstrap logs the startup message.
vix::log::info("Starting api on port {}", cfg.getServerPort());The port comes from runtime configuration. In a generated backend, the default local value is usually:
SERVER_PORT=8080This makes the startup behavior visible in logs and keeps the port controlled by environment configuration instead of hard-coding it in main.cpp.
Running the app
The final step is to run the Vix application.
app.run(cfg);
return 0;At that point, the backend has loaded configuration, configured runtime directories, registered middleware, registered routes, registered enabled modules, and started the server using the loaded config.
The normal local workflow is:
cp .env.example .env
vix build
vix runThen check the generated health route.
curl http://localhost:8080/healthWhat belongs in AppBootstrap
AppBootstrap should contain startup-level wiring.
Good responsibilities include:
loading configuration
creating vix::App
configuring public files
configuring templates
registering middleware registry
registering route registry
registering generated modules
starting the appThese are application shell responsibilities. They describe how the backend starts.
What should not go in AppBootstrap
Avoid putting feature-specific business logic directly in the bootstrap.
// Avoid this shape in AppBootstrap.
app.post("/api/auth/login", [](vix::Request &req, vix::Response &res)
{
// authentication logic
});A better shape is to let a controller or module own that route.
modules/auth/
include/auth/AuthModule.hpp
include/auth/controllers/AuthController.hpp
src/AuthModule.cpp
src/controllers/AuthController.cppThen the generated module bridge can connect the feature to the running application.
vix::app_generated::register_app_modules(app);The bootstrap should not become the place where every feature is implemented. It should remain the place where the backend is assembled.
Editing the bootstrap
Edit AppBootstrap.cpp when the application startup flow changes. Good reasons include changing how configuration is loaded, adding a global middleware registry step, changing static file mounting, changing template setup, or adding a new application-level startup phase.
Do not edit it every time a feature adds a route. Feature routes should live in controllers or modules.
If you add a new source file used by the bootstrap, remember to add it to vix.app.
sources = [
"src/main.cpp",
"src/api/app/AppBootstrap.cpp",
"src/api/presentation/routes/RouteRegistry.cpp",
"src/api/presentation/middleware/MiddlewareRegistry.cpp",
"src/api/presentation/controllers/HomeController.cpp",
"src/api/presentation/controllers/HealthController.cpp",
"src/api/support/HttpResponses.cpp",
]The manifest must describe every .cpp file compiled into the backend target.
Relationship with the backend manifest
The backend manifest includes the bootstrap source file and include roots.
sources = [
"src/main.cpp",
"src/api/app/AppBootstrap.cpp",
]
include_dirs = [
"include",
"src",
]That lets main.cpp include:
#include <api/app/AppBootstrap.hpp>and lets the bootstrap include the route and middleware registries.
#include <api/presentation/middleware/MiddlewareRegistry.hpp>
#include <api/presentation/routes/RouteRegistry.hpp>If the source list or include roots are wrong, the bootstrap may fail to compile even though the file exists.
Common mistakes
The most common mistake is adding feature routes directly to AppBootstrap.cpp. That works at first, but it makes the startup file harder to read as the backend grows. Put feature routes in controllers or modules.
Another mistake is editing generated module registration files instead of changing vix.app. The generated bridge is output. The manifest is the source of truth.
A third mistake is forgetting that runtime files must be available beside the built target. If the backend cannot find .env, public/, views/, or storage/, check the resources list in vix.app.
Recommended rule
Keep AppBootstrap focused on the startup sequence. It should explain how the backend is assembled, not contain the implementation of every feature. Configuration, runtime paths, middleware, routes, generated modules, and server startup belong there. Feature behavior belongs in controllers, support files, or app modules.
Next step
Continue with routes and middleware to understand how the backend template separates base HTTP routes from the application startup flow.