Dependencies and Checks
Application modules are useful only when their boundaries remain visible. A module should be able to use another module, but that relationship should not be hidden in random include paths or private implementation details. When projects depends on auth, the project should say so clearly.
Vix keeps this relationship visible in two places. In a vix.app project, the application manifest describes the module graph. In the module build files, CMake describes the target relationship. The manifest makes the architecture readable from the project root, while CMake makes the dependency correct for the build.
Module dependencies in vix.app
In a vix.app project, dependencies are declared with the depends field.
[module.auth]
enabled = true
path = "modules/auth"
kind = "backend"
depends = []
[module.projects]
enabled = true
path = "modules/projects"
kind = "backend"
depends = [
"auth",
]This says that projects depends on auth. The dependency is declared by module name, not by target name. A developer reading the manifest can understand the relationship without opening the module source files.
This becomes more useful as the application grows.
[module.builds]
enabled = true
path = "modules/builds"
kind = "backend"
depends = [
"projects",
]
[module.packages]
enabled = true
path = "modules/packages"
kind = "backend"
depends = [
"projects",
]Here, builds and packages depend on projects, and projects depends on auth. The manifest becomes a small map of the application’s internal feature graph.
Build dependencies
The manifest describes the architecture, but the module target still needs the correct build relationship. When one module uses another module, the module CMakeLists.txt should link the dependency explicitly.
target_link_libraries(api_projects
PUBLIC
api::auth
)The target name api_projects is the real module target. The alias api::auth is the public target name exported by the auth module.
This matters when a public header from one module includes a public header from another module.
#include <auth/api.hpp>The include shows what the code uses. The target link shows what the build depends on. Both should tell the same story.
Public headers and private implementation
A module has a public side and a private side.
modules/auth/
include/auth/ public headers
src/ private implementationPublic headers are allowed to be used by other modules.
#include <auth/api.hpp>Private implementation files under src/ should not be included by another module. They belong to the module target, but they are not part of the module’s public interface.
Avoid this from a public header:
#include "../src/AuthStore.hpp"If another module needs something from auth, expose that behavior through a public header under include/auth/, then declare the dependency.
target_link_libraries(api_projects
PUBLIC
api::auth
)This keeps implementation details inside the module that owns them.
The check command
vix modules check validates the module layer from the project root.
vix modules checkThe command is not a replacement for compilation. It catches structural problems before the build becomes the only signal. This is especially useful in larger backends, where a broken module graph can be harder to understand once the compiler starts reporting errors from generated files or indirect includes.
Run it after changing module declarations, dependencies, module folders, route prefixes, or public headers.
vix modules check
vix buildFor a stronger local workflow, run the project check after the module check.
vix modules check
vix check --tests --runWhat the check validates
In a vix.app project, the check command reads the module declarations from the root manifest and compares them with the filesystem.
It verifies that declared modules have folders.
[module.auth]
enabled = true
path = "modules/auth"
kind = "backend"
depends = []The path must exist.
modules/auth/For enabled modules, the command also expects the module build and metadata files to exist.
modules/auth/CMakeLists.txt
modules/auth/vix.moduleA disabled module may remain declared and may remain on disk, but an enabled module must be complete enough to be loaded by the generated build.
Undeclared dependencies
A module should not depend on a module that is not declared in vix.app.
[module.projects]
enabled = true
path = "modules/projects"
kind = "backend"
depends = [
"auth",
]If auth has no module declaration, the dependency is incomplete. The check command reports this because the application manifest no longer describes a valid module graph.
Fix it by declaring the dependency target as a module.
[module.auth]
enabled = true
path = "modules/auth"
kind = "backend"
depends = []Enabled modules depending on disabled modules
An enabled module cannot depend on a disabled module.
[module.auth]
enabled = false
path = "modules/auth"
kind = "backend"
depends = []
[module.projects]
enabled = true
path = "modules/projects"
kind = "backend"
depends = [
"auth",
]This state is unsafe because projects is active, but the module it needs is not active. The fix is to enable the dependency or disable the dependent module.
vix modules enable author:
vix modules disable projectsThe right choice depends on the feature state. The important rule is that the active module graph must be complete.
Dependency cycles
Module dependencies should form a readable direction. A cycle usually means two features know too much about each other.
[module.auth]
enabled = true
path = "modules/auth"
kind = "backend"
depends = [
"projects",
]
[module.projects]
enabled = true
path = "modules/projects"
kind = "backend"
depends = [
"auth",
]This creates a cycle.
auth -> projects -> authThe check command reports circular dependencies because they make the module graph harder to reason about and can also create build-level problems.
The fix is usually to move shared behavior into a lower-level module or to change the public API so only one direction is needed.
auth
projects -> author:
identity
auth -> identity
projects -> identityThe best shape depends on the application, but the dependency direction should remain clear.
Cross-module includes
When a public header includes another module, that module relationship should be declared.
#include <auth/api.hpp>If this include appears in a public header from projects, then projects should link to auth.
target_link_libraries(api_projects
PUBLIC
api::auth
)This is one of the main checks that protects the module boundary. Including another module’s public header is allowed, but the dependency must be visible to the build.
Without the explicit dependency, the project may compile by accident because of include path leakage. That kind of dependency becomes fragile as the codebase grows.
Private includes
Public headers should not include private implementation paths.
#include "../../auth/src/AuthStore.hpp"That include reaches into another module’s private implementation. It means the public API of the current module now depends on a file that the other module did not expose as public.
Move the shared type or function into a public header.
modules/auth/include/auth/AuthStore.hppThen include it through the module public path.
#include <auth/AuthStore.hpp>And declare the module dependency.
target_link_libraries(api_projects
PUBLIC
api::auth
)This keeps the dependency explicit and keeps private implementation files private.
Route prefix conflicts
Backend modules can declare a route prefix in vix.module.
name = "auth"
kind = "backend"
[routes]
prefix = "/api/auth"
[tests]
enabled = trueThe route prefix tells the project which HTTP namespace the module owns. Two routed modules should not use the same prefix.
[routes]
prefix = "/api/auth"If both auth and users declare /api/auth, the check command reports the conflict. This prevents route ownership from becoming ambiguous.
Use clear prefixes that match the module responsibility.
auth -> /api/auth
projects -> /api/projects
builds -> /api/builds
packages -> /api/packagesThe prefix does not need to expose every route in the module. It only gives the module a stable HTTP namespace.
Missing module files
An enabled module should have the files needed by the module system.
modules/auth/
CMakeLists.txt
vix.moduleIf a module is declared and enabled but the folder is incomplete, vix modules check reports it before the build reaches a more confusing error.
This usually happens after moving folders manually, resolving a bad merge, or editing vix.app before creating the actual module skeleton.
The fix is to create the module through the CLI or restore the missing files.
vix modules add authIf the module already exists but is incomplete, restore the missing CMakeLists.txt or vix.module from the module skeleton and then run the check again.
vix modules checkFolder exists but is not declared
In a vix.app project, a module folder can exist without being declared in the manifest.
modules/billing/If billing is not declared in vix.app, it is not part of the active module graph. The check command warns about this state because it may be intentional during migration, but it may also mean the module was created or copied without being registered.
Add the declaration when the module should belong to the application.
[module.billing]
enabled = true
path = "modules/billing"
kind = "backend"
depends = [
"auth",
]If the folder is not meant to be active yet, keep it disabled but declared.
[module.billing]
enabled = false
path = "modules/billing"
kind = "backend"
depends = [
"auth",
]This makes the project state explicit.
Checks in CMake projects
In a CMake-first project, the check command still protects the module layout. It scans module public headers and validates public/private boundaries and cross-module include relationships.
The active state is usually controlled by CMake in this mode. A module is active when the project loads and links the module target. vix modules enable, disable, and list are mainly useful for vix.app projects because they operate on module sections in the manifest.
For CMake projects, the most important habit is to keep module dependencies visible in target links.
target_link_libraries(api_projects
PUBLIC
api::auth
)This gives the check command and the build system the same dependency information.
Recommended workflow
Run module checks before builds when the module graph changes.
vix modules check
vix buildRun the full project check before a commit.
vix modules check
vix check --tests --runFor CMake projects with a custom target name, pass the project prefix when needed.
vix modules check --project apiThe check command is most useful when it becomes part of the normal development rhythm. It keeps the module layer honest while the application grows.
Next step
Continue with generated registration to understand how enabled modules are connected to the application startup flow in vix.app projects.