Run Your First C++ File
This page shows how to run a single C++ file with Vix.cpp.
Single-file mode is the fastest way to try Vix.cpp without creating a full project. It is useful for learning, quick experiments, small tools, examples, and testing small pieces of code.
The main command is:
vix run main.cppVix.cpp detects the source file, builds it with the native C++ toolchain, then runs the generated program.
Create a workspace
Create a clean folder for the example:
mkdir -p ~/tmp/vix-first-file
cd ~/tmp/vix-first-fileCreate main.cpp
Create a minimal C++ file:
cat > main.cpp <<'CPP'
#include <vix.hpp>
int main()
{
vix::print("Hello from Vix.cpp");
return 0;
}
CPPRun it:
vix run main.cppExpected output:
Hello from Vix.cppAt this point, you have compiled and executed a native C++ program through the Vix.cpp workflow.
What happened?
When you run:
vix run main.cppVix.cpp treats main.cpp as a single-file program.
It prepares the build, compiles the file, links the executable, and starts it.
You do not need a project folder, a CMakeLists.txt, or a vix.app file for this mode.
main.cpp
-> vix run
-> native executable
-> program outputThis mode is intentionally small. It gives you a direct path from a C++ file to a running program.
When single-file mode is useful
Use single-file mode when you want to:
- test a small idea
- learn a Vix.cpp API
- write a small local tool
- run a documentation example
- validate a short C++ snippet
- experiment before creating a project
When the code grows into multiple files, tests, dependencies, or a stable application, move to a Vix project.
Run a small HTTP server
A single file can also use Vix.cpp runtime APIs.
Replace main.cpp:
cat > main.cpp <<'CPP'
#include <vix.hpp>
using namespace vix;
int main()
{
App app;
app.get("/", [](Request &, Response &res) {
res.text("Hello from Vix.cpp");
});
app.run();
return 0;
}
CPPCreate a local .env file:
cat > .env <<'EOF'
SERVER_PORT=8080
VIX_LOG_LEVEL=info
VIX_LOG_FORMAT=kv
EOFRun the server:
vix run main.cppExpected output shape:
Vix.cpp READY v2.6.0
HTTP: http://localhost:8080/
Status: readyOpen another terminal and test it:
curl -i http://127.0.0.1:8080/Expected response body:
Hello from Vix.cppStop the server with:
Ctrl+CWhy .env is used
The server port is stored in .env so the source code stays focused on application logic.
SERVER_PORT=8080Then the code can simply call:
app.run();This is better than hardcoding the port in every example when the application is meant to behave like a real project later.
Return JSON
Most backend services return JSON.
Replace main.cpp with:
cat > main.cpp <<'CPP'
#include <vix.hpp>
using namespace vix;
int main()
{
App app;
app.get("/", [](Request &, Response &res) {
res.json({
"message", "Hello from Vix.cpp",
"mode", "single-file"
});
});
app.get("/health", [](Request &, Response &res) {
res.json({
"ok", true,
"service", "first-file"
});
});
app.run();
return 0;
}
CPPRun it:
vix run main.cppTest both routes:
curl -i http://127.0.0.1:8080/
curl -i http://127.0.0.1:8080/healthExpected response shape for /:
{
"message": "Hello from Vix.cpp",
"mode": "single-file"
}Expected response shape for /health:
{
"ok": true,
"service": "first-file"
}Add a route parameter
Route parameters let the application read values from the URL.
Update main.cpp:
cat > main.cpp <<'CPP'
#include <vix.hpp>
using namespace vix;
int main()
{
App app;
app.get("/", [](Request &, Response &res) {
res.json({
"message", "Hello from Vix.cpp",
"mode", "single-file"
});
});
app.get("/health", [](Request &, Response &res) {
res.json({
"ok", true,
"service", "first-file"
});
});
app.get("/hello/{name}", [](Request &req, Response &res) {
const std::string name = req.param("name");
res.json({
"greeting", "Hello " + name,
"powered_by", "Vix.cpp"
});
});
app.run();
return 0;
}
CPPRun it:
vix run main.cppTest it:
curl -i http://127.0.0.1:8080/hello/GaspardExpected response shape:
{
"greeting": "Hello Gaspard",
"powered_by": "Vix.cpp"
}The value Gaspard comes from this route segment:
/hello/{name}And is read with:
req.param("name")Add a query parameter
Query parameters are values passed after ? in the URL.
Update main.cpp again:
cat > main.cpp <<'CPP'
#include <vix.hpp>
using namespace vix;
int main()
{
App app;
app.get("/", [](Request &, Response &res) {
res.json({
"message", "Hello from Vix.cpp",
"mode", "single-file"
});
});
app.get("/health", [](Request &, Response &res) {
res.json({
"ok", true,
"service", "first-file"
});
});
app.get("/hello/{name}", [](Request &req, Response &res) {
const std::string name = req.param("name");
res.json({
"greeting", "Hello " + name,
"powered_by", "Vix.cpp"
});
});
app.get("/users/{id}", [](Request &req, Response &res) {
const std::string id = req.param("id");
const std::string page = req.query_value("page", "1");
res.json({
"id", id,
"page", page
});
});
app.run();
return 0;
}
CPPRun it:
vix run main.cppTest it:
curl -i "http://127.0.0.1:8080/users/42?page=2"Expected response shape:
{
"id": "42",
"page": "2"
}Here:
req.param("id")reads the route parameter:
/users/{id}And:
req.query_value("page", "1")reads the query parameter. If page is missing, the default value is "1".
Pass runtime arguments
Runtime arguments are arguments passed to your program after it starts.
Create a small argument example:
cat > main.cpp <<'CPP'
#include <vix.hpp>
int main(int argc, char **argv)
{
vix::print("argc = {}", argc);
for (int i = 0; i < argc; ++i)
{
vix::print("argv[{}] = {}", i, argv[i]);
}
return 0;
}
CPPRun it with program arguments:
vix run main.cpp --run --name VixThe arguments after --run are passed to your program, not to the compiler.
Pass compiler and linker flags
Use -- when you want to pass flags to the compiler or linker.
Optimization flags:
vix run main.cpp -- -O2 -DNDEBUGInclude paths:
vix run main.cpp -- -I./includeLibraries:
vix run main.cpp -- -lssl -lcryptoEverything after -- is treated as a compiler or linker option in single-file mode.
--run vs --
Use --run for arguments passed to the program:
vix run main.cpp --run --name VixUse -- for compiler or linker flags:
vix run main.cpp -- -O2 -DNDEBUGThese two separators solve different problems.
--run -> program arguments
-- -> compiler and linker flagsUse watch mode
During development, you can ask Vix.cpp to rebuild and restart when the file changes:
vix run main.cpp --watchThis is useful for a small single-file program.
For full projects, prefer:
vix devUse sanitizers
Sanitizers help detect memory errors and undefined behavior.
For memory-related debugging:
vix run main.cpp --sanFor undefined behavior checks:
vix run main.cpp --ubsanUse these options when debugging suspicious behavior or validating code before moving it into a larger project.
When to create a project
Single-file mode is useful, but it is not meant to replace a project structure.
Move to a project when you need:
- multiple source files
- headers
- dependencies
- tests
.env.example- stable configuration
- reusable tasks
- packaging
- production builds
Create a project with:
vix new hello --app
cd hello
vix devA project gives the code a stable place to grow.
Common mistakes
Passing runtime arguments with --
Wrong:
vix run main.cpp -- --name VixCorrect:
vix run main.cpp --run --name VixUse --run for program arguments.
Passing compiler flags with --run
Wrong:
vix run main.cpp --run -O2Correct:
vix run main.cpp -- -O2Use -- for compiler and linker flags.
Forgetting .env for the server port
If the HTTP example does not start on the expected port, check the .env file:
SERVER_PORT=8080Then run again:
vix run main.cppKeeping too much code in one file
Single-file mode is for small programs and examples.
When the file grows too much, move to a project:
vix new hello --app
cd helloThen split the code into src/, include/, and tests/.
What you should remember
Run a single C++ file:
vix run main.cppUse .env for runtime configuration:
SERVER_PORT=8080Use --run for program arguments:
vix run main.cpp --run --name VixUse -- for compiler and linker flags:
vix run main.cpp -- -O2 -DNDEBUGMove to a project when the code becomes an application.
Next step
Create your first Vix project.