Project Structure
Vantris is convention-light: an index.html at the root and a source directory are all it needs. This page explains each part and how it maps to configuration.
The anatomy of a project
my-app/
├── index.html # entry document (module-script points at src)
├── public/ # static assets, served at / and copied verbatim
│ └── favicon.svg
├── src/ # application source (rootDir)
│ ├── main.ts
│ ├── styles/
│ │ └── app.css
│ └── components/
├── dist/ # build output (outDir) — generated
├── .env # environment variables (optional)
├── vantris.config.ts # configuration (optional)
├── tsconfig.json # TypeScript config (also a source of aliases)
└── package.jsonindex.html — the entry point
Unlike bundlers that take a JS entry, Vantris treats index.html as the source of truth. It's a real HTML file served during development and processed during the build. Vantris scans it for module scripts:
<script type="module" src="/src/main.ts"></script>- Multiple entries are supported — add more
<script type="module">tags and each becomes a build entry. <link>,<img>,<script>whosesrc/hrefpoint intorootDirare hashed and rewritten at build time. References topublic/or external URLs are left untouched.
See Building for Production for how HTML is transformed.
src/ — the source directory (rootDir)
Your application code lives here. In the dev server, source modules are served from rootDir under /src/*. TypeScript, JSX, CSS, and asset imports all work from within it.
// config default
rootDir: "./src"Change it with the rootDir option.
public/ — static assets served as-is (publicDir)
Files in public/ are:
- served at the root URL during dev (
public/favicon.svg→/favicon.svg), - copied verbatim into
outDiron build — never hashed, never transformed.
Use it for robots.txt, favicon.svg, and files you must reference by a stable URL. Reference them with an absolute path from the root:
<link rel="icon" href="/favicon.svg" />build: { /* … */ }
publicDir: "./public" // defaultSee Static Assets.
dist/ — the build output (outDir)
vantris build writes here. It's emptied before each build (guarded so it can never delete anything outside outDir) and served as-is by vantris preview. Add it to .gitignore.
outDir: "./dist" // defaultvantris.config.ts — configuration
Optional. Placed at the project root, it can be .ts, .js, or .mjs. Export a config object (or a function returning one) wrapped in defineConfig:
import { defineConfig } from "vantris";
export default defineConfig({
// every field is optional
});The full option surface is documented in the Config reference.
tsconfig.json — TypeScript, and a source of aliases
Vantris transpiles TypeScript directly; you don't need a separate build step. Beyond typing, your tsconfig.json also feeds Vantris in two ways:
- Aliases — when
resolve.aliasis omitted from your config, Vantris falls back tocompilerOptions.paths(resolved againstbaseUrl). So"@/*": ["./src/*"]works with zero extra config. See Aliases. - JSX runtime —
"jsx": "react"selects the classic runtime;jsxImportSourceis honoured for Preact and friends. See React & JSX.
A recommended baseline:
{
"compilerOptions": {
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"jsx": "react-jsx",
"types": ["vantris/client"],
"baseUrl": ".",
"paths": { "@/*": ["./src/*"] }
}
}The "types": ["vantris/client"] line brings in ambient types for import.meta.env, import.meta.hot, and asset/CSS imports. See Client Types.
.env files — environment variables
Vantris loads .env, .env.local, .env.[mode], and .env.[mode].local. Only variables prefixed VANTRIS_ are exposed to client code via import.meta.env. See Env Variables & Modes.
What is not reachable in dev
Serving follows a Vite-style allowlist. Only these are reachable:
- source modules under
rootDir(/src/*), public/contents at/.
Everything else under the project root — node_modules, package.json, lockfiles, config files — is not served. This keeps secrets and tooling files out of the browser.
The internal cache
Vantris keeps a transparent cache in node_modules/.vantris/ — transpiled dev modules and pre-bundled dependencies. It's self-invalidating and never touches your project root. You don't manage it; see Internal Cache.
Monorepos
Vantris is a single package with no assumptions about your repo layout. It works inside pnpm/npm/yarn workspaces — install it where the app lives and run the commands from that package's directory. Plugins like @vantris/react are separate packages you add alongside it.