Skip to content

Commit bca0ee5

Browse files
os-zhuangCopilot
andcommitted
fix(cli): load .env files in os dev and os start
Previously only `os serve` called dotenv-flow, so `.env` / `.env.development` / `.env.production` / `.env.local` were silently ignored by the two most commonly used commands. Users who set up the conventional Vite/Next.js `.env.*` layout would see no effect from variables like OS_DATABASE_URL — and would assume the platform fell back to its default global path on purpose. Both commands now load `.env` files via dotenv-flow before any env lookups, matching `os serve`. `os dev` pins NODE_ENV=development; `os start` defaults to production (overridable). Process env still wins over file values. Documented the loading order and conventional layout in the CLI README. Adds a changeset. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 58c1368 commit bca0ee5

4 files changed

Lines changed: 52 additions & 0 deletions

File tree

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
`os dev` and `os start` now load `.env` files via dotenv-flow, matching
6+
the existing `os serve` behavior. Previously only `serve` honored
7+
`.env` / `.env.development` / `.env.production` / `.env.local`, which
8+
made env-based configuration (e.g. `OS_DATABASE_URL`) silently inert
9+
for the two most commonly used commands and surprised users who set up
10+
the conventional `.env.*` layout.
11+
12+
Loading order (later wins): `.env`, `.env.${NODE_ENV}`, `.env.local`,
13+
`.env.${NODE_ENV}.local`. `os dev` pins NODE_ENV to `development`; `os
14+
start` defaults to `production`. Process env still wins over file
15+
values, so CLI flags and shell exports remain authoritative.

‎packages/cli/README.md‎

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,29 @@ export default defineStack({
106106
});
107107
```
108108

109+
### Environment files (`.env`)
110+
111+
`dev`, `start`, and `serve` all load `.env` files following the
112+
Vite / Next.js convention, in this order (later files override earlier):
113+
114+
1. `.env`
115+
2. `.env.${NODE_ENV}` — `development` for `os dev`, `production` for `os start` (override with `NODE_ENV=...`)
116+
3. `.env.local`
117+
4. `.env.${NODE_ENV}.local`
118+
119+
Any variable already in the process environment wins. Typical project
120+
layout:
121+
122+
```
123+
.env # checked in — safe defaults
124+
.env.development # checked in — dev URLs, demo creds
125+
.env.production # checked in — production URLs
126+
.env.local # gitignored — secrets, personal overrides
127+
```
128+
129+
Common variables: `OS_DATABASE_URL`, `OS_DATABASE_DRIVER`,
130+
`OS_HOME`, `AUTH_SECRET`, `PORT`.
131+
109132
## CLI Options
110133

111134
### Global

‎packages/cli/src/commands/dev.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { Args, Command, Flags } from '@oclif/core';
44
import chalk from 'chalk';
55
import { spawnSync, spawn } from 'child_process';
6+
import dotenvFlow from 'dotenv-flow';
67
import fs from 'fs';
78
import path from 'path';
89
import { printHeader, printKV, printStep, printError } from '../utils/format.js';
@@ -60,6 +61,11 @@ export default class Dev extends Command {
6061
const { args, flags } = await this.parse(Dev);
6162
const packageName = args.package;
6263

64+
// Load .env files following Vite/Next.js convention (mirrors `serve`).
65+
// `dev` is always development mode, so prefer `.env.development*` over
66+
// `.env.production*`. Loaded BEFORE any env lookups.
67+
dotenvFlow.config({ node_env: 'development', silent: true });
68+
6369
printHeader('Development Mode');
6470

6571
// ── Single-Environment Mode ──────────────────────────────────────────────────

‎packages/cli/src/commands/start.ts‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Command, Flags } from '@oclif/core';
44
import chalk from 'chalk';
55
import { spawn, spawnSync } from 'child_process';
66
import crypto from 'crypto';
7+
import dotenvFlow from 'dotenv-flow';
78
import fs from 'fs';
89
import os from 'os';
910
import path from 'path';
@@ -106,6 +107,13 @@ export default class Start extends Command {
106107
async run(): Promise<void> {
107108
const { flags } = await this.parse(Start);
108109

110+
// Load .env files following Vite/Next.js convention (mirrors `serve`).
111+
// Loaded BEFORE any env lookups so OS_DATABASE_URL/OS_HOME/AUTH_SECRET
112+
// from `.env`, `.env.production`, `.env.local`, etc. are picked up.
113+
const mode = process.env.NODE_ENV === 'test' ? 'test'
114+
: (process.env.NODE_ENV || 'production');
115+
dotenvFlow.config({ node_env: mode, silent: true });
116+
109117
printHeader('ObjectStack');
110118

111119
// ── Project mode detection ─────────────────────────────────────

0 commit comments

Comments
 (0)