Environment โ
Each app keeps its own environment variables. mono-env is a small wrapper (shipped with mono-utils) that loads a root env file first, then layers each app's env file from .apps/ on top, and finally runs your real command (vite, vue-tsc, โฆ) with the merged environment.
You don't call it directly โ it's already wired into every script in the templates, so day to day you just run pnpm dev / pnpm build.
mono env -e .env.dev -- viteThat single line means: load .env.dev (root, then every app), then run vite.
File layout โ
The .apps/ folder is produced by Sync. Each app brings its own env file, alongside the root env files:
mono-vue-remote/
โโโ .apps/
โ โโโ mono-host/
โ โโโ .env.dev # app env (overrides root)
โโโ .env.dev # root env (loaded first)
โโโ .env
โโโ package.jsonHow it loads โ
mono-env loads env files in order, and later files override earlier ones:
- Root โ the file you pass with
-e, resolved from the app you're running (e.g..env.dev). - Per app โ for every folder inside
.apps/, the file with the same name inside it (e.g..apps/mono-host/.env.dev).
Matched by file name
Per-app files are matched by the basename of your -e value. -e .env.dev loads .apps/<app>/.env.dev; -e .env loads .apps/<app>/.env. Missing files are skipped with a warning โ they don't stop the command.
Naming convention โ
mono-env loads every key into the environment of the command it runs โ but not every key reaches your client code. Vite only exposes variables matching the prefixes set in vite.config.ts:
ts
// vite.config.ts
envPrefix: ['VITE_', 'MONO_'],That gives two prefixes with different roles, plus everything else:
| Prefix | Read with | Use for |
|---|---|---|
MONO_ | import.meta.env.MONO_* | The only shared vars. Cross-app / mono-repo config exposed to the client bundle. |
VITE_ | import.meta.env.VITE_* | App-local client config (standard Vite). |
| (no prefix) | not exposed | Build/tooling-only secrets (tokens, generators). Stays in process.env for the running command, never shipped to the browser. |
Standard: shared = MONO_
Treat MONO_ as the contract between apps. Anything an app needs to read from another app โ or anything the Host shares with Remotes โ gets a MONO_ prefix so it's exposed via import.meta.env. Keep app-private values on VITE_, and keep secrets prefix-less so they never end up in the client bundle.
ts
// Shared, exposed to the client because of the MONO_ prefix
const port = import.meta.env.MONO_HOST_PORTpackage.json scripts โ
The templates already route every command through mono-env. The relevant lines from mono-vue / mono-host:
json
{
"scripts": {
"dev": "mono env -e .env.dev -- vite",
"dev:h": "mono env -e .env.dev -- vite --host",
"build": "mono env -e .env -- vue-tsc && mono env -e .env -- vite build --emptyOutDir",
"preview": "mono env -e .env -- vite preview"
}
}Everything after -- is the command to run. Dev scripts use .env.dev; build and preview use .env.
Flags โ
| Flag | Alias | Description |
|---|---|---|
-e <file> | --env | Env file to load. Repeatable โ pass -e multiple times to load several. |
-a <name> | --app | Load only .apps/<name> instead of every app folder. |
-r <dir> | --app-root | Folder to scan for apps. Defaults to .apps. |
-- | Everything after this is the command to run. |
Example โ load env for a single app only:
mono env -e .env.dev -a mono-host -- viteInjected variables โ
mono-env also exposes which app(s) it loaded, so your command can read them:
| Variable | When | Value |
|---|---|---|
MONO_APP_NAME | one app loaded | the app folder name (e.g. mono-host) |
MONO_APP_DIR | one app loaded | absolute path to that app folder |
MONO_APP_NAMES | multiple apps loaded | comma-joined list of app names |
Multiple apps โ
When no -a is given and .apps/ has more than one folder, mono-env loads them all. Because each app's env layers on top of the previous one, keys with the same name collide โ the last app wins.
Use unique keys per app
If two apps both define MONO_API_URL, whichever loads last overrides the other. Since shared vars use the MONO_ prefix, keep them unique per app โ e.g. MONO_HOST_API_URL, MONO_VUE_API_URL โ or scope each run to one app with -a.
See Sync for how the .apps/ folder gets populated.