-
-
Notifications
You must be signed in to change notification settings - Fork 169
feat: add T3 Env support (needs testing) #544
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
WalkthroughAdds a new "t3env" addon across CLI, templates, and website: updates defaults, prompts, constants, dependency map, README/docs, presets, and stack command generation; implements setupT3Env to install env packages based on backend/frontend and adds Next/Nuxt env templates plus config imports. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant CLI as CLI
participant Setup as setupAddons()
participant T3 as setupT3Env()
participant FS as fs-extra
participant Pkg as addPackageDependency()
User->>CLI: init --addons turborepo t3env
CLI->>Setup: setupAddons(config)
Setup->>T3: invoke setupT3Env(config) [if includes t3env]
T3->>FS: check for apps/server and apps/web
alt backend == "none"
T3-->>Setup: log warning, skip
else
par server deps
T3->>Pkg: add @t3-oss/env-core, zod (if server exists)
and web deps
alt frontend == next
T3->>Pkg: add @t3-oss/env-nextjs
else frontend == nuxt
T3->>Pkg: add @t3-oss/env-nuxt, zod
else
T3->>Pkg: add @t3-oss/env-core, zod
end
end
T3-->>Setup: success
end
Setup-->>CLI: addons completed
CLI-->>User: project generated with t3env templates
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (6)
🚧 Files skipped from review as they are similar to previous changes (5)
🧰 Additional context used📓 Path-based instructions (3)**/*.{ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/convex_rules.mdc)
Files:
**/*.{js,jsx,ts,tsx,mjs,cjs}📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Files:
**/*.{js,jsx,ts,tsx}📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Files:
🔇 Additional comments (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 11
🧹 Nitpick comments (18)
apps/web/src/app/(home)/_components/npm-package.tsx (3)
15-17
: Guard against empty or unexpected GitHub releases payloadAccessing
data[0].tag_name
will throw if there are no releases or the payload shape changes. Add a defensive check and a safe fallback.Apply this diff:
- const data = await res.json(); - const latestVersion = data[0].tag_name.replace(/^v/, ""); - setVersion(latestVersion); + const data = await res.json(); + const tag = + Array.isArray(data) && data.length > 0 && typeof data[0]?.tag_name === "string" + ? data[0].tag_name + : null; + setVersion(tag ? tag.replace(/^v/, "") : "latest");
8-24
: Prevent state update on unmounted component; add AbortController and pass signal to fetchIf the component unmounts before the request resolves,
setVersion
may run after unmount. Abort the fetch and avoid potential React warnings. This also sets you up to add caching or retries later.Apply this diff:
useEffect(() => { - const getLatestVersion = async () => { + const controller = new AbortController(); + const getLatestVersion = async () => { try { - const res = await fetch( - "https://api.github.com/repos/AmanVarshney01/create-better-t-stack/releases", - ); + const res = await fetch( + "https://api.github.com/repos/AmanVarshney01/create-better-t-stack/releases", + { signal: controller.signal }, + ); if (!res.ok) throw new Error("Failed to fetch version"); - const data = await res.json(); + const data = await res.json(); const latestVersion = data[0].tag_name.replace(/^v/, ""); setVersion(latestVersion); } catch (error) { console.error("Error fetching NPM version:", error); setVersion("latest"); } }; getLatestVersion(); - }, []); + return () => controller.abort(); + }, []);Architecture note: For a public homepage, an unauthenticated client-side call to GitHub’s API risks rate limits. Consider moving this to a server component/route with caching (e.g., revalidate) or switching to the npm registry endpoint for the package’s
dist-tags.latest
, which is simpler to parse and cacheable by your edge/CDN.
19-20
: Clarify log message sourceThe message says “NPM” but the data source is GitHub. Align the message to reduce confusion during debugging.
- console.error("Error fetching NPM version:", error); + console.error("Error fetching version from GitHub releases:", error);apps/web/src/app/layout.tsx (1)
39-40
: Minor SEO nit: add common synonyms for the new keywordAdding a couple of variants can help searchability without changing behavior.
Apply this diff to extend the keywords list:
- "t3env", + "t3env", + "t3 env", + "t3-oss/env",apps/web/src/app/(home)/_components/stack-builder.tsx (1)
1166-1179
: Avoid hardcoding addon ids; derive from TECH_OPTIONS to prevent future driftvalidAddons is a hardcoded whitelist. It can silently drift from TECH_OPTIONS or the CLI if new addons are added later. Use TECH_OPTIONS.addons to derive the allowed set and filter out "none".
Apply this diff to make the list source-of-truth driven:
- const validAddons = stackState.addons.filter((addon) => - [ - "pwa", - "tauri", - "starlight", - "biome", - "husky", - "turborepo", - "ultracite", - "fumadocs", - "oxlint", - "ruler", - "t3env", - ].includes(addon), - ); + const knownAddons = + (TECH_OPTIONS.addons ?? []) + .map((opt) => opt.id) + .filter((id) => id !== "none"); + const validAddons = stackState.addons.filter((addon) => + knownAddons.includes(addon), + );apps/cli/package.json (1)
52-59
: Optional: consider migrating tests to Bun’s built-in runnerPer project guidelines, prefer “bun test” over external runners. This is out-of-scope for this PR but worth a follow-up to simplify toolchain and devDependencies.
Example scripts section using Bun’s runner:
{ "scripts": { "build": "tsdown", "dev": "tsdown --watch", "check-types": "tsc --noEmit", "check": "biome check --write .", "test": "bun test", "test:ui": "bun test --watch", "prepublishOnly": "npm run build" } }I can open a small follow-up PR to migrate tests and remove unused deps if you’d like.
apps/web/content/docs/cli/options.mdx (1)
248-248
: Docs LGTM: Addons list now includest3env
Reads well and matches the CLI flag. Consider adding a one-liner note that the CLI wires T3 Env with zod and provides Next/Nuxt env templates so users know what to expect.
Possible clarification right under the bullet:
- “The CLI sets up T3 Env with zod. Client/server templates are provided for Next/Nuxt; server-only uses env-core.”
If helpful, I can add a short “Usage” snippet showing
--addons t3env
in a full command.apps/cli/README.md (3)
44-44
: Keep feature list in sync with CLI options (missing addons in table).The Addons row omits several options present in the CLI (fumadocs, ultracite, oxlint, ruler). Add them for consistency.
-| **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Husky (Git hooks)<br>• Turborepo (optimized builds)<br>• T3 Env (Type-safe environment variables) | +| **Addons** | • PWA support<br>• Tauri (desktop applications)<br>• Starlight (documentation site)<br>• Biome (linting and formatting)<br>• Husky (Git hooks)<br>• Turborepo (optimized builds)<br>• T3 Env (Type-safe environment variables)<br>• Fumadocs (documentation site)<br>• Ultracite (Biome preset + AI)<br>• Oxlint (Rust linter)<br>• Ruler (AI rules) |
61-61
: Add missing addon "ruler" to the CLI flag help.The
--addons
list is missingruler
, which exists in code (ADDON_COMPATIBILITY
and web constants). Add it to prevent confusion.- --addons <types...> Additional addons (pwa, tauri, starlight, biome, husky, turborepo, fumadocs, ultracite, oxlint, t3env, none) + --addons <types...> Additional addons (pwa, tauri, starlight, biome, husky, turborepo, fumadocs, ultracite, oxlint, ruler, t3env, none)
195-195
: Generalize or update the "Addons 'none'" note to include all addons.Currently lists a subset; either remove the parenthetical or include all addons to avoid drift.
-- **Addons 'none'**: Skips all addons (PWA, Tauri, Starlight, Biome, Husky, Turborepo, T3 Env). +- **Addons 'none'**: Skips all addons (e.g., PWA, Tauri, Starlight, Biome, Husky, Turborepo, T3 Env, Fumadocs, Ultracite, Oxlint, Ruler).apps/cli/src/helpers/addons/t3env-setup.ts (3)
23-29
: Server deps: LGTM, but gate on backend existence.Install
@t3-oss/env-core
+zod
only if a server app exists andbackend !== "none"
.- const serverDir = path.join(projectDir, "apps/server"); - if (await fs.pathExists(serverDir)) { + const serverDir = path.join(projectDir, "apps/server"); + if (backend !== "none" && (await fs.pathExists(serverDir))) {
43-47
: Fix misleading comment for Nuxt branch.The comment says “use the core package” but you install
@t3-oss/env-nuxt
. Update the comment.- // For Nuxt, we'll use the core package + // For Nuxt, use the Nuxt-specific package
57-63
: Success/error messaging: enhance clarity.Consider coloring success with
pc.green
and include which apps were configured (server/web) to aid debugging in multi-app repos.- s.stop("T3 Env configured successfully!"); + s.stop(pc.green("T3 Env configured successfully!"));apps/web/src/lib/constant.ts (1)
513-520
: Icon path consistency for t3env.Most icons use
ICON_BASE_URL
;t3env
points to a local/icon/t3env.svg
. Prefer a consistent source (or confirm the asset exists inpublic/icon/
and is deployed).- icon: "/icon/t3env.svg", + icon: `${ICON_BASE_URL}/t3env.svg`,If the remote asset doesn’t exist yet, add it to the CDN or keep the local path and ensure the file is present in the web app’s public assets.
apps/cli/src/helpers/addons/addons-setup.ts (1)
63-65
: Consider allowing T3 Env without a backend
setupT3Env
exits early whenbackend === "none"
. T3 Env can still be valuable for Next-only apps (client/public env validation). Consider relaxing the restriction and running the web dependency/setup path even without a backend.If you choose to keep the restriction, make sure the prompt/README explicitly calls it out to avoid user confusion.
apps/cli/templates/addons/t3env/apps/server/next/src/env/server.ts.hbs (1)
1-15
: Tighten runtimeEnv mapping and add opt-out for validation in CICurrent config passes
experimental__runtimeEnv: process.env
but doesn’t explicitly scoperuntimeEnv
. To prevent accidental exposure and to improve treeshaking, explicitly map only the keys you declare. Also, add askipValidation
flag controlled bySKIP_ENV_VALIDATION
(commonly used in CI).Apply this diff:
export const env = createEnv({ server: { DATABASE_URL: z.string().url(), BETTER_AUTH_SECRET: z.string().min(1), BETTER_AUTH_URL: z.string().url(), CORS_ORIGIN: z.string().url(), {{#if (includes examples 'ai')}} GOOGLE_GENERATIVE_AI_API_KEY: z.string().min(1), {{/if}} }, - experimental__runtimeEnv: process.env, + // Only provide the vars you defined above to the runtime mapping + runtimeEnv: { + DATABASE_URL: process.env.DATABASE_URL, + BETTER_AUTH_SECRET: process.env.BETTER_AUTH_SECRET, + BETTER_AUTH_URL: process.env.BETTER_AUTH_URL, + CORS_ORIGIN: process.env.CORS_ORIGIN, + {{#if (includes examples 'ai')}} + GOOGLE_GENERATIVE_AI_API_KEY: process.env.GOOGLE_GENERATIVE_AI_API_KEY, + {{/if}} + }, + // Optional: allow skipping validation in CI/local scripts + skipValidation: !!process.env.SKIP_ENV_VALIDATION, + experimental__runtimeEnv: process.env, });Please confirm the targeted
@t3-oss/env-nextjs
version still recommendsexperimental__runtimeEnv
with Next.js, and whether you wantCORS_ORIGIN
to support multiple origins (array or CSV). If yes, we can tweak the schema accordingly.apps/cli/templates/addons/t3env/apps/web/next/src/env/client.ts.hbs (2)
4-17
: Add skipValidation and emptyStringAsUndefined for better DX and CI ergonomics.This prevents noisy failures in CI or on platforms that inject empty strings. It’s a common pattern across T3 Env templates.
Apply this diff:
export const env = createEnv({ client: { NEXT_PUBLIC_SERVER_URL: z.string().url(), {{#if (eq backend 'convex')}} NEXT_PUBLIC_CONVEX_URL: z.string().url(), {{/if}} }, runtimeEnv: { NEXT_PUBLIC_SERVER_URL: process.env.NEXT_PUBLIC_SERVER_URL, {{#if (eq backend 'convex')}} NEXT_PUBLIC_CONVEX_URL: process.env.NEXT_PUBLIC_CONVEX_URL, {{/if}} - }, + }, + // Skip validation in CI or when explicitly requested. + skipValidation: + process.env.CI === "true" || process.env.SKIP_ENV_VALIDATION === "true", + // Treat empty strings as undefined to avoid false positives on some hosts. + emptyStringAsUndefined: true, });
7-9
: Convex key naming LGTM; confirm docs alignment.
NEXT_PUBLIC_CONVEX_URL
matches typical Convex examples. Just ensure the CLI scaffold also writes this key into .env (local) and docs/readme so users don’t miss it.If helpful, I can add .env(.example) insertion and a short README section for Convex with a checklist.
Also applies to: 13-15
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (2)
apps/web/public/icon/t3env.svg
is excluded by!**/*.svg
demo.gif
is excluded by!**/*.gif
📒 Files selected for processing (22)
README.md
(1 hunks)apps/cli/README.md
(3 hunks)apps/cli/package.json
(1 hunks)apps/cli/src/constants.ts
(3 hunks)apps/cli/src/helpers/addons/addons-setup.ts
(2 hunks)apps/cli/src/helpers/addons/t3env-setup.ts
(1 hunks)apps/cli/src/helpers/core/create-readme.ts
(1 hunks)apps/cli/src/prompts/addons.ts
(2 hunks)apps/cli/src/types.ts
(1 hunks)apps/cli/templates/addons/t3env/apps/server/next/next.config.ts
(1 hunks)apps/cli/templates/addons/t3env/apps/server/next/src/env/server.ts.hbs
(1 hunks)apps/cli/templates/addons/t3env/apps/web/next/src/env/client.ts.hbs
(1 hunks)apps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs
(1 hunks)apps/cli/templates/addons/t3env/apps/web/nuxt/src/env/client.ts.hbs
(1 hunks)apps/cli/templates/frontend/nuxt/nuxt.config.ts.hbs
(1 hunks)apps/web/content/docs/cli/options.mdx
(1 hunks)apps/web/content/docs/index.mdx
(1 hunks)apps/web/src/app/(home)/_components/npm-package.tsx
(1 hunks)apps/web/src/app/(home)/_components/stack-builder.tsx
(1 hunks)apps/web/src/app/(home)/analytics/_components/types.ts
(1 hunks)apps/web/src/app/layout.tsx
(1 hunks)apps/web/src/lib/constant.ts
(7 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/convex_rules.mdc)
**/*.{ts,tsx}
: Use Id from './_generated/dataModel' to type document ids (e.g., Id<'users'>)
Ensure Record key/value types align with validators (e.g., v.record(v.id('users'), v.string()) => Record<Id<'users'>, string>)
Be strict with types for document ids; prefer Id<'table'> over string
Use 'as const' for string literals in discriminated unions
When using Array and Record types, declare with explicit generic types (e.g., const arr: Array = ...)
Files:
apps/cli/templates/addons/t3env/apps/server/next/next.config.ts
apps/cli/src/prompts/addons.ts
apps/cli/src/types.ts
apps/web/src/app/(home)/_components/stack-builder.tsx
apps/cli/src/helpers/core/create-readme.ts
apps/web/src/app/(home)/_components/npm-package.tsx
apps/cli/src/helpers/addons/t3env-setup.ts
apps/cli/src/helpers/addons/addons-setup.ts
apps/web/src/app/layout.tsx
apps/web/src/app/(home)/analytics/_components/types.ts
apps/cli/src/constants.ts
apps/web/src/lib/constant.ts
**/*.{js,jsx,ts,tsx,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{js,jsx,ts,tsx,mjs,cjs}
: Do not use dotenv; Bun auto-loads .env
UseBun.serve()
for HTTP/WebSockets; do not useexpress
Usebun:sqlite
for SQLite; do not usebetter-sqlite3
UseBun.redis
for Redis; do not useioredis
UseBun.sql
for Postgres; do not usepg
orpostgres.js
Use built-inWebSocket
; do not usews
PreferBun.file
overnode:fs
readFile/writeFile
UseBun.$
instead ofexeca
for shelling out
Files:
apps/cli/templates/addons/t3env/apps/server/next/next.config.ts
apps/cli/src/prompts/addons.ts
apps/cli/src/types.ts
apps/web/src/app/(home)/_components/stack-builder.tsx
apps/cli/src/helpers/core/create-readme.ts
apps/web/src/app/(home)/_components/npm-package.tsx
apps/cli/src/helpers/addons/t3env-setup.ts
apps/cli/src/helpers/addons/addons-setup.ts
apps/web/src/app/layout.tsx
apps/web/src/app/(home)/analytics/_components/types.ts
apps/cli/src/constants.ts
apps/web/src/lib/constant.ts
**/package.json
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
In package.json scripts, prefer running files with
bun <file>
instead ofnode <file>
orts-node <file>
Files:
apps/cli/package.json
{**/package.json,**/@(jest|vitest).config.@(js|ts|mjs|cjs)}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
{**/package.json,**/@(jest|vitest).config.@(js|ts|mjs|cjs)}
: Usebun test
instead ofjest
orvitest
Usebun test
to run tests
Files:
apps/cli/package.json
{**/package.json,**/webpack.config.@(js|ts|mjs|cjs),**/esbuild.config.@(js|ts|mjs|cjs)}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use
bun build <file>
instead ofwebpack
oresbuild
Files:
apps/cli/package.json
{**/package.json,**/vite.config.@(js|ts|mjs|cjs)}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
Use HTML imports with
Bun.serve()
; do not usevite
Files:
apps/cli/package.json
🧬 Code graph analysis (2)
apps/cli/src/helpers/addons/t3env-setup.ts (2)
apps/cli/src/types.ts (1)
ProjectConfig
(160-179)apps/cli/src/utils/add-package-deps.ts (1)
addPackageDependency
(6-43)
apps/cli/src/helpers/addons/addons-setup.ts (1)
apps/cli/src/helpers/addons/t3env-setup.ts (1)
setupT3Env
(9-64)
🪛 LanguageTool
README.md
[grammar] ~42-~42: There might be a mistake here.
Context: ...madocs, Ruler, Ultracite, Oxlint, T3 Env - Examples: Todo, AI - DB Setup: Turso, Ne...
(QB_NEW_EN)
🔇 Additional comments (19)
apps/web/src/app/(home)/_components/npm-package.tsx (1)
34-34
: LGTM: export formatting onlyNo behavioral change; default export remains intact.
README.md (1)
42-42
: LGTM: Added “T3 Env” to the feature listThe documentation change is consistent with the new addon’s display name used elsewhere. No issues.
apps/web/src/app/(home)/_components/stack-builder.tsx (1)
1166-1179
: t3env wiring verified end-to-endAll expected references to
t3env
have been found and correctly configured across the repository:
- CLI constants, types, and prompts (
apps/cli/src/constants.ts
,types.ts
,prompts/addons.ts
)- Dependency map including
@t3-oss/env-*
packages andzod
inapps/cli/src/constants.ts
- Addon setup module (
apps/cli/src/helpers/addons/t3env-setup.ts
)- Templates under
apps/cli/templates/addons/t3env
(with nodotenv
usage)- Web UI constants and types (
apps/web/src/lib/constant.ts
,layout.tsx
, analytics types)- Documentation mentions in CLI options and site docs (
apps/web/content/docs
)No missing wiring detected; this comment can be resolved.
apps/cli/package.json (1)
39-41
: LGTM: Added “t3env” to keywordsThe keyword helps npm search visibility and aligns with the new addon. No functional impact.
apps/cli/src/types.ts (1)
51-53
: Exhaustivet3env
coverage confirmed
All references to the newt3env
addon have been verified across the CLI and web layers, including:
- apps/cli/src/constants.ts (defaults & dependency map)
- apps/cli/src/prompts/addons.ts (prompt label/hint and grouping)
- apps/cli/src/helpers/core/create-readme.ts (README generation)
- apps/cli/src/helpers/addons/addons-setup.ts (import & invocation of setupT3Env)
- apps/web/src/lib/constant.ts (display metadata & default presets)
- apps/web/src/app/layout.tsx, analytics types, and stack-builder component
- Documentation in apps/web/content/docs (options.mdx & index.mdx)
Type narrowing for
Addons
remains exhaustive and consistent. No missing references detected—ready to merge.apps/cli/src/helpers/core/create-readme.ts (1)
471-473
: Feature blurb for T3 Env — good additionAccurately describes the addon and matches naming used elsewhere (“T3 Env”). No changes needed.
apps/cli/templates/addons/t3env/apps/web/nuxt/src/env/client.ts.hbs (1)
1-11
: Nuxt client env schema is correct; no runtimeEnv needed
@t3-oss/env-nuxt
auto-fillsruntimeEnv
, so providing only theclient
schema is expected. Validations for public URLs look good. (env.t3.gg)apps/web/src/app/(home)/analytics/_components/types.ts (1)
355-358
: Analytics config: New addon entry for T3 Env looks good.Label and color slot are consistent with neighboring entries.
apps/cli/src/constants.ts (2)
166-167
: Addon compatibility entry for t3env set to [] looks fine.No hard constraints makes sense since env tooling spans frameworks. Revisit later if specific frameworks require special handling.
17-17
: Addon Compatibility for “t3env” Verified– The
ADDON_COMPATIBILITY
map explicitly listst3env: []
, meaning it’s considered compatible by default (no frontend constraint) since an empty array is treated as “always compatible.”
– In the interactive prompt (getAddonsChoice
),validateAddonCompatibility("t3env", frontends)
always returnsisCompatible: true
, so “T3 Env” remains selectable even if no frontends are chosen.
– During scaffold execution,t3env
setup (helpers/addons/t3env-setup.ts
) bails out with a warning ifbackend === "none"
, skipping environment-file generation but not failing the overall flow.No further auto-removal logic exists for
t3env
when either backend or frontend is “none,” but the warning int3env-setup.ts
ensures graceful handling.No action required unless you’d prefer stricter UX (e.g., filtering “T3 Env” out of the prompt when
backend: none
or whenfrontend: none
).apps/cli/src/helpers/addons/t3env-setup.ts (1)
49-54
: No changes needed for the fallback branch’szod
dependency
The@t3-oss/env-core
package relies onzod
(as a peer dependency), so includingzod
alongside@t3-oss/env-core
in the “other frameworks” fallback is correct. There’s no template‐level import to correlate here—zod
is required at runtime by the core environment package.apps/web/src/lib/constant.ts (3)
600-601
: Preset default: including t3env by default is fine.Matches CLI defaults. Ensure “Generate command” and docs reflect this to avoid surprises for users.
736-737
: DEFAULT_STACK includes t3env: LGTM.Keeps the marketing site and CLI in sync.
622-623
: Verify T3 Env addon only targets the web layer in the Convex presetThe Convex preset still pulls in the
t3env
addon even though it setsruntime: "none"
and omits any server scaffolding. Please double-check thatsetupT3Env
does not assume or mutate a traditional backend package—i.e. it only operates on your web project and won’t touchapps/server
(or any non-existent serverpackage.json
).• In
apps/cli/src/helpers/addons/t3env-setup.ts
, confirm all file operations and dependency injections are scoped to the web app (e.g. underapps/web
or its equivalent).
• Ensure there are no references toapps/server
,serverAppDir
, or direct writes to a backendpackage.json
whenconfig.backend === "convex"
.
• If you’re unsure, run a targeted grep for backend paths in that file:
•grep -R "apps/server" -n apps/cli/src/helpers/addons/t3env-setup.ts
•grep -R "package\\.json" -n apps/cli/src/helpers/addons/t3env-setup.ts
If
setupT3Env
is already isolated to the web directory, no changes are needed here.apps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs (1)
1-1
: Use a relative import for the env module in next.config.tsNext.js loads next.config.ts via Node at runtime and does not resolve TypeScript path aliases like
"@/…"
. In your template, next.config.ts is placed under src/, so you should import the env client using a path relative to that file:- import "@/env/client"; + import "./env/client";If you ever move next.config.ts to the project root (outside src/), then use:
import "./src/env/client";Please confirm where the generator emits next.config.ts —in src/ or at the project root—and update the import path accordingly.
apps/cli/src/helpers/addons/addons-setup.ts (1)
12-12
: Import placement LGTMImporting
setupT3Env
alongside other addon setup helpers is consistent with the existing pattern.apps/cli/src/prompts/addons.ts (2)
61-64
: Addon display for “T3 Env” looks goodLabel and hint are concise and consistent with other entries.
76-76
: Grouping under “Other” is reasonable; no conflicts detected
t3env
sits well with other cross-cutting addons. No compatibility side-effects here.apps/cli/templates/addons/t3env/apps/web/next/src/env/client.ts.hbs (1)
1-2
: Imports look correct and minimal.No issues. These are the expected imports for the T3 Env + Zod setup in a Next.js client env module.
zod: "^4.0.14", | ||
"@t3-oss/env-core": "^0.13.8", | ||
"@t3-oss/env-nextjs": "^0.13.8", | ||
"@t3-oss/env-nuxt": "^0.13.8", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Pin checks: ensure versions exist and are compatible (Zod v4 + @t3-oss/env).*
Zod v4 is specified. Some ecosystems still assume v3; ensure templates and @t3-oss/env* peer ranges are compatible with v4 to avoid runtime/TS errors.
🏁 Script executed:
#!/bin/bash
# Check published versions and peer deps for compatibility.
for pkg in zod @t3-oss/env-core @t3-oss/env-nextjs @t3-oss/env-nuxt; do
echo "== $pkg latest =="
npm view "$pkg" version
echo "== $pkg peerDependencies =="
npm view "$pkg" peerDependencies --json | jq .
done
Length of output: 1642
Ensure zod version matches @t3-oss/env peer dependency*
The published v0.13.8 of @t3-oss/env-core, env-nextjs, and env-nuxt peer-depend on
"zod": "^3.24.0 || ^4.0.0-beta.0"
which does not include the stable v4.0.14 you’ve pinned. Installing zod@^4.0.14 will trigger a peer-dependency conflict.
You have two remediation paths:
• Pin to a prerelease zod that satisfies the peer range:
– In apps/cli/src/constants.ts (lines 147–150), change
- zod: "^4.0.14",
+ zod: "^4.0.0-beta.0",
This will align with the existing peer-dependency and avoid install-time errors.
• Upgrade to a future @t3-oss/env-* release that adds stable zod v4 support (once published).
🤖 Prompt for AI Agents
In apps/cli/src/constants.ts around lines 147–150, the pinned "zod": "^4.0.14"
conflicts with the peer range declared by @t3-oss/env-* (which accepts "zod":
"^3.24.0 || ^4.0.0-beta.0"); to fix, either change the zod entry to a prerelease
that satisfies the peer range (for example use a ^4.0.0-beta.x prerelease
specifier) so installs don't produce peer-dependency conflicts, or upgrade the
@t3-oss/env-* packages to a future release that formally supports stable zod v4
and then pin zod to a stable v4 once that dependency change is available.
💡 Verification agent
🧩 Analysis chain
Consider gating/removing dotenv when T3 Env is present.
Since T3 Env is now default and the guidelines discourage dotenv with Bun, ensure scaffolding doesn’t include both, to avoid duplicated/conflicting env loading.
🏁 Script executed:
#!/bin/bash
# Find any templates or code that still import/use dotenv.
rg -nP -C2 '\bdotenv\b|\bconfig\s*\(' apps/cli/templates apps || true
Length of output: 14762
Remove direct dotenv usage from CLI scaffolding now that T3 Env is the default
T3 Env packages (@t3-oss/env-core
, env-nextjs
, env-nuxt
, etc.) now handle .env
loading across runtimes, and Bun auto-loads .env
files out of the box. Keeping dotenv
imports/dependencies leads to duplicated or conflicting environment loading. Please remove or gate all direct dotenv
usage in your scaffolding and helper code:
• In apps/cli/src/constants.ts
– Remove the "dotenv": "^17.2.1",
entry.
• In all Prisma templates (apps/cli/templates/db/prisma/*/prisma.config.ts.hbs
)
– Drop the top-level import "dotenv/config";
.
• In backend server templates (apps/cli/templates/backend/server/**/src/index.ts.hbs
)
– Remove any import "dotenv/config";
(Hono, Elysia, Fastify, Express). If you still need to support plain Node projects without Bun, you can instead wrap this import under a {{#if (eq runtime "node")}}…{{/if}}
check.
• In package-template JSON files
– apps/cli/templates/backend/server/server-base/package.json.hbs
and …/next/package.json.hbs
: drop the "dotenv": "^17.2.1"
dependency.
• In deployment scripts and helpers
– apps/cli/templates/deploy/alchemy/alchemy.run.ts.hbs
: remove the import { config } from "dotenv";
and all config({ path: … })
calls.
– All Alchemy setup helpers (alchemy-*.ts
under src/helpers/deployment/alchemy/
): remove "dotenv"
from the devDependencies
arrays passed to addPackageDependency
.
• In database-provider setup code
– apps/cli/src/helpers/database-providers/prisma-postgres-setup.ts
: stop injecting import "dotenv/config";
into the generated Prisma config.
By eliminating these, you’ll avoid double-loading environment variables and fully rely on T3 Env’s loading across both Bun and Node runtimes.
🤖 Prompt for AI Agents
In apps/cli/src/constants.ts around lines 147 to 150, the package list still
includes a direct dotenv dependency which must be removed; delete the line
containing "dotenv": "^17.2.1" and ensure no other code in this file imports or
references dotenv. Also sweep the CLI scaffolding and templates as described in
the review: remove top-level import "dotenv/config" from Prisma and backend
server template files (or guard it with a {{#if (eq runtime "node")}}…{{/if}}),
drop "dotenv" from the package-template JSON files listed, remove dotenv imports
and config(...) calls from deployment scripts/helpers, and stop injecting import
"dotenv/config"; in prisma-postgres-setup.ts so T3 Env/Bun handle .env loading
exclusively.
if (addons.includes("t3env")) { | ||
await setupT3Env(config); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Ensure zod is installed for Next.js web when adding T3 Env
The client
/server
env templates rely on zod. In t3env-setup.ts
, Next.js branch currently installs @t3-oss/env-nextjs
only. It should also add zod
to the web app to avoid build-time errors in env/client.ts
and/or env/server.ts
.
Apply this diff in apps/cli/src/helpers/addons/t3env-setup.ts
:
- if (hasNext) {
- await addPackageDependency({
- dependencies: ["@t3-oss/env-nextjs"],
- projectDir: webDir,
- });
- } else if (hasNuxt) {
+ if (hasNext) {
+ await addPackageDependency({
+ dependencies: ["@t3-oss/env-nextjs", "zod"],
+ projectDir: webDir,
+ });
+ } else if (hasNuxt) {
// For Nuxt, we'll use the core package
await addPackageDependency({
dependencies: ["@t3-oss/env-nuxt", "zod"],
projectDir: webDir,
});
} else {
// For other frameworks, use the core package
await addPackageDependency({
dependencies: ["@t3-oss/env-core", "zod"],
projectDir: webDir,
});
}
Also confirm dependencyVersionMap
includes pinned versions for zod
, @t3-oss/env-core
, @t3-oss/env-nextjs
, and @t3-oss/env-nuxt
to keep installs deterministic.
🏁 Script executed:
#!/bin/bash
# Inspect Next.js branch in t3env-setup.ts to verify if "zod" is included
rg -n "addPackageDependency" -C3 --glob "apps/cli/src/helpers/addons/t3env-setup.ts"
# Locate dependencyVersionMap to ensure pinned versions for required packages
rg -n "dependencyVersionMap" -C3
Length of output: 5018
🏁 Script executed:
#!/bin/bash
# Display the section of dependencyVersionMap around @t3-oss/env-core, @t3-oss/env-nextjs, and zod
sed -n '120,160p' apps/cli/src/constants.ts
Length of output: 1224
Ensure zod
is added to the Next.js branch in t3env-setup.ts
The Next.js path in setupT3Env
currently installs only @t3-oss/env-nextjs
, but the generated env/client.ts
/env/server.ts
rely on zod
, which will lead to build failures.
• File: apps/cli/src/helpers/addons/t3env-setup.ts
(around line 38)
- if (hasNext) {
- await addPackageDependency({
- dependencies: ["@t3-oss/env-nextjs"],
- projectDir: webDir,
- });
- } else if (hasNuxt) {
+ if (hasNext) {
+ await addPackageDependency({
+ dependencies: ["@t3-oss/env-nextjs", "zod"],
+ projectDir: webDir,
+ });
+ } else if (hasNuxt) {
• I’ve confirmed in apps/cli/src/constants.ts
that dependencyVersionMap
pins versions for
– zod
(^4.0.14
)
– @t3-oss/env-core
(^0.13.8
)
– @t3-oss/env-nextjs
(^0.13.8
)
– @t3-oss/env-nuxt
(^0.13.8
)
so installs remain deterministic.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if (addons.includes("t3env")) { | |
await setupT3Env(config); | |
} | |
if (hasNext) { | |
await addPackageDependency({ | |
dependencies: ["@t3-oss/env-nextjs", "zod"], | |
projectDir: webDir, | |
}); | |
} else if (hasNuxt) { |
🤖 Prompt for AI Agents
In apps/cli/src/helpers/addons/t3env-setup.ts around line 38, the Next.js branch
of setupT3Env currently only installs @t3-oss/env-nextjs but omits zod (and
should also include @t3-oss/env-core), causing generated env/client.ts and
env/server.ts to fail; update the Next.js install step to add zod and
@t3-oss/env-core to the list of packages to install (using the pinned versions
from dependencyVersionMap/constants) so installs remain deterministic and match
the generated code's runtime dependencies.
// T3 Env requires a backend to be present | ||
if (backend === "none") { | ||
s.stop(pc.yellow("T3 Env requires a backend to be configured")); | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Incorrect early return and spinner misuse block web-only setups.
- T3 Env does not require a separate backend; Next/Nuxt-only projects should still be configured.
- Calling
s.stop()
befores.start()
is an API misuse.
Refactor to always process the web app and only skip the server section when no backend/server app exists.
- // T3 Env requires a backend to be present
- if (backend === "none") {
- s.stop(pc.yellow("T3 Env requires a backend to be configured"));
- return;
- }
+ // Proceed regardless of backend; we'll conditionally configure server/web below.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
// T3 Env requires a backend to be present | |
if (backend === "none") { | |
s.stop(pc.yellow("T3 Env requires a backend to be configured")); | |
return; | |
} | |
- // T3 Env requires a backend to be present | |
- if (backend === "none") { | |
- s.stop(pc.yellow("T3 Env requires a backend to be configured")); | |
- return; | |
// Proceed regardless of backend; we'll conditionally configure server/web below. |
🤖 Prompt for AI Agents
In apps/cli/src/helpers/addons/t3env-setup.ts around lines 13 to 17, remove the
early return and the s.stop() call so web-only projects still run; always run
the web app configuration path and only skip the server/backend configuration
when backend === "none" (or when there is no server app detected). Ensure you
never call s.stop() before s.start(): start the spinner before any long-running
step and stop it after that specific step completes or fails, and isolate
spinner usage to the server/backend section so skipping the server does not
attempt to stop a spinner that was never started.
try { | ||
s.start("Setting up T3 Env for type-safe environment variables..."); | ||
|
||
// Add dependencies to server | ||
const serverDir = path.join(projectDir, "apps/server"); | ||
if (await fs.pathExists(serverDir)) { | ||
await addPackageDependency({ | ||
dependencies: ["@t3-oss/env-core", "zod"], | ||
projectDir: serverDir, | ||
}); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Start the spinner before any conditional exits; improve messaging.
Begin the spinner first, then handle per-app setup. This avoids calling stop before start and provides clearer UX.
- try {
- s.start("Setting up T3 Env for type-safe environment variables...");
+ try {
+ s.start("Setting up T3 Env for type-safe environment variables...");
Optionally, after computing presence, add a note if neither app exists:
+ const serverDir = path.join(projectDir, "apps/server");
+ const webDir = path.join(projectDir, "apps/web");
+ const hasServer = await fs.pathExists(serverDir);
+ const hasWeb = await fs.pathExists(webDir);
+ if (!hasServer && !hasWeb) {
+ s.stop(pc.yellow("No apps/server or apps/web found; skipping T3 Env setup."));
+ return;
+ }
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
try { | |
s.start("Setting up T3 Env for type-safe environment variables..."); | |
// Add dependencies to server | |
const serverDir = path.join(projectDir, "apps/server"); | |
if (await fs.pathExists(serverDir)) { | |
await addPackageDependency({ | |
dependencies: ["@t3-oss/env-core", "zod"], | |
projectDir: serverDir, | |
}); | |
} | |
try { | |
s.start("Setting up T3 Env for type-safe environment variables..."); | |
const serverDir = path.join(projectDir, "apps/server"); | |
const webDir = path.join(projectDir, "apps/web"); | |
const hasServer = await fs.pathExists(serverDir); | |
const hasWeb = await fs.pathExists(webDir); | |
if (!hasServer && !hasWeb) { | |
s.stop(pc.yellow("No apps/server or apps/web found; skipping T3 Env setup.")); | |
return; | |
} | |
// Add dependencies to server | |
if (hasServer) { | |
await addPackageDependency({ | |
dependencies: ["@t3-oss/env-core", "zod"], | |
projectDir: serverDir, | |
}); | |
} |
🤖 Prompt for AI Agents
In apps/cli/src/helpers/addons/t3env-setup.ts around lines 19 to 29, the spinner
is started only inside a branch which can lead to stop being called before start
and unclear messaging; move s.start("Setting up T3 Env for type-safe environment
variables...") to before checking app directories so the spinner begins
unconditionally, then compute existence of apps (server/client) and run per-app
setup while updating spinner messages per-app; if neither app exists, update the
spinner or log a clear message indicating no apps found and then stop the
spinner.
if (hasNext) { | ||
await addPackageDependency({ | ||
dependencies: ["@t3-oss/env-nextjs"], | ||
projectDir: webDir, | ||
}); | ||
} else if (hasNuxt) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Next.js branch should also add zod.
Templates typically import zod schemas; env-nextjs
doesn’t pull zod
transitively. Add it to avoid compile-time errors.
- if (hasNext) {
+ if (hasNext) {
await addPackageDependency({
- dependencies: ["@t3-oss/env-nextjs"],
+ dependencies: ["@t3-oss/env-nextjs", "zod"],
projectDir: webDir,
});
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
if (hasNext) { | |
await addPackageDependency({ | |
dependencies: ["@t3-oss/env-nextjs"], | |
projectDir: webDir, | |
}); | |
} else if (hasNuxt) { | |
if (hasNext) { | |
await addPackageDependency({ | |
dependencies: ["@t3-oss/env-nextjs", "zod"], | |
projectDir: webDir, | |
}); | |
} else if (hasNuxt) { |
🤖 Prompt for AI Agents
In apps/cli/src/helpers/addons/t3env-setup.ts around lines 37 to 42, the Next.js
branch adds @t3-oss/env-nextjs but omits zod which is not pulled transitively;
update the call to addPackageDependency in the hasNext branch to also include
"zod" in the dependencies array so zod is installed alongside @t3-oss/env-nextjs
to prevent compile-time errors from missing schema imports.
@@ -0,0 +1 @@ | |||
import "@/env/server"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Same alias-resolution pitfall: switch to a relative import in server Next config
Using "@/env/server" in next.config.ts
is prone to resolution failures. Use a relative path.
-import "@/env/server";
+// If next.config.ts is at the app root:
+import "./src/env/server";
+// If placed under src/:
+// import "./env/server";
Double-check the final file location produced by the generator and align the relative path accordingly.
🏁 Script executed:
#!/bin/bash
set -e
# Print current working directory
pwd
# List files under the Next.js config directory
find apps/cli/templates/addons/t3env/apps/server/next -maxdepth 2 -type f -print
# Find environment schema files in the template
find apps/cli/templates/addons/t3env -type f \( -name "server.ts" -o -name "env.ts" \) -print
Length of output: 274
🏁 Script executed:
#!/bin/bash
set -e
echo "Listing all files under apps/cli/templates/addons/t3env:"
find apps/cli/templates/addons/t3env -type f
Length of output: 518
🏁 Script executed:
#!/bin/bash
# Display the beginning of the Next.js server template config to inspect import paths
sed -n '1,100p' apps/cli/templates/addons/t3env/apps/server/next/next.config.ts
Length of output: 102
Switch to a relative import in next.config.ts
Importing via the @/...
alias in your Next.js config isn’t supported at load time, causing resolution failures. Update the import to a relative path from the next.config.ts
file to the generated server.ts
module:
• File needing update:
– apps/server/next/next.config.ts
• Change the import to point at src/env/server.ts
:
-import "@/env/server";
+import "./src/env/server";
Verify this path matches your final project structure (e.g., if next.config.ts
ends up under a different directory, adjust accordingly).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
import "@/env/server"; | |
import "./src/env/server"; |
🤖 Prompt for AI Agents
In apps/cli/templates/addons/t3env/apps/server/next/next.config.ts around line
1, the file uses an absolute alias import "@" which Next.js can't resolve at
config load time; replace the aliased import with a relative import pointing to
the generated server module (e.g., "./src/env/server" or "../src/env/server"
depending on next.config.ts location) so the config uses a filesystem path;
update the import to the correct relative path to src/env/server and verify the
path matches the final project layout.
client: { | ||
NEXT_PUBLIC_SERVER_URL: z.string().url(), | ||
{{#if (eq backend 'convex')}} | ||
NEXT_PUBLIC_CONVEX_URL: z.string().url(), | ||
{{/if}} | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Keep client keys and runtimeEnv in lockstep.
Given the conditional Convex block, any future additions to client
must be mirrored in runtimeEnv
. T3 Env will usually catch mismatches at compile time, but template drift can still happen during refactors.
Run this quick repo check to ensure the Next template importing this file resolves path aliases and that the dependency is declared:
Also applies to: 11-16
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 1) Verify next.config imports the client env (fail fast validation at build time)
rg -n --color=always $'from\\s+[\'"]@/env/client[\'"]' apps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs || {
echo "Missing import of '@/env/client' in next.config.ts.hbs" >&2; exit 1; }
# 2) Ensure '@' path alias exists in the Next web template tsconfig
tsconfigs=$(fd -t f --full-path 'apps/cli/templates/addons/t3env/apps/web/next/.*tsconfig.*' || true)
if [ -n "$tsconfigs" ]; then
echo "$tsconfigs" | xargs -I{} rg -n -C2 --color=always '"paths"\s*:\s*\{\s*"@/\*"\s*:\s*\["\./src/\*"\]' {} || {
echo "Missing '@/ -> ./src/*' path alias in Next web tsconfig" >&2; exit 1; }
else
echo "No tsconfig found for Next web template; please verify alias setup." >&2; exit 1
fi
# 3) Confirm the dependency is declared somewhere in templates
rg -n --color=always '@t3-oss/env-nextjs' || {
echo "Dependency '@t3-oss/env-nextjs' not found in template manifests" >&2; exit 1; }
Length of output: 281
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# 2) Verify tsconfig path alias for '@/*'
echo "Checking tsconfig path aliases..."
tsconfigs=$(fd -t f --full-path 'apps/cli/templates/addons/t3env/apps/web/next/.*tsconfig.*' || true)
if [ -n "$tsconfigs" ]; then
echo "$tsconfigs" | while read -r f; do
echo "-- Inspecting $f --"
rg -n -C2 '"paths"\s*:\s*\{[^}]*"@/\*"\s*:\s*\["\.\/src\/\*"\]' "$f" \
|| echo "Missing '@/*' path alias in $f"
done
else
echo "No tsconfig found for Next web template"
fi
# 3) Confirm the dependency '@t3-oss/env-nextjs'
echo
echo "Checking for '@t3-oss/env-nextjs' dependency..."
rg -n '@t3-oss/env-nextjs' || echo "Dependency '@t3-oss/env-nextjs' not found in template manifests"
Length of output: 836
Action required: Add missing client env import & verify path alias
The repo check indicates two critical gaps in the Next web template:
- Missing import of the client env in
next.config.ts.hbs
.
The fileapps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs
does not import the client-side environment, causing failsafe validation to be bypassed run1. - No TypeScript config found for path alias.
Our search didn’t locate anytsconfig.json
underapps/cli/templates/addons/t3env/apps/web/next/
, so the@/* → ./src/*
alias may be unset or in a differently named config run2.
The dependency @t3-oss/env-nextjs
is already declared and used in templates—no action needed there run2.
Please address the following:
• In apps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs
, add at the top:
+ import { createEnv } from '@/env/client';
• Locate (or create) the Next web template’s TypeScript config (tsconfig.json
or tsconfig.base.json
) and ensure it includes:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
}
}
🤖 Prompt for AI Agents
In apps/cli/templates/addons/t3env/apps/web/next/src/client.ts.hbs around lines
5 to 10, the template defines client env schema but the Next template
next.config.ts.hbs is missing the required import of the generated client env;
update apps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs to
import the client env at the top (import { clientEnv } from
'<path-to-client-env>') and use it with env-nextjs middleware as needed, and
also locate or create the Next web template TypeScript config (tsconfig.json or
tsconfig.base.json) under apps/cli/templates/addons/t3env/apps/web/next/ and add
the compilerOptions.paths mapping to map "@/*" to "./src/*" so the import path
alias resolves correctly.
@@ -1,3 +1,5 @@ | |||
import "./env"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Import path and unconditional import will break non-t3env scaffolds
- Path is wrong: the generated file is
src/env/client.ts
, not./env
. - Import is unconditional; projects without the addon will fail at build/TS time.
Gate the import behind the addon flag and point to the correct file.
Apply:
- import "./env";
+ {{#if (includes addons "t3env")}}import "~/env/client";{{/if}}
If the includes
helper isn’t available in your Handlebars runtime, switch to whatever helper you already use for array membership (or add one) and keep the same intent.
To confirm helper availability across templates:
🏁 Script executed:
#!/usr/bin/env bash
# Look for existing array-membership helpers in templates
rg -n -C2 "{{#if \(includes " apps/cli/templates || true
rg -n -C2 "{{#if \(some " apps/cli/templates || true
Length of output: 293
🏁 Script executed:
#!/usr/bin/env bash
# Search for includes helper usage in Handlebars templates
rg -nF '{{#if (includes' -g '*.hbs' apps/cli/templates || true
# Search for 'some' helper usage in Handlebars templates
rg -nF '{{#if (some' -g '*.hbs' apps/cli/templates || true
# Search for includes helper registration in TypeScript code
rg -nP 'registerHelper\(\s*["'\'']?includes["'\'']?,' -g '*.ts' apps/cli || true
# Search for any helper registrations to locate available helpers
rg -n 'registerHelper' -g '*.ts' apps/cli || true
Length of output: 4376
🏁 Script executed:
#!/usr/bin/env bash
# Display the beginning of the helper registration file to verify available helpers
sed -n '1,200p' apps/cli/src/utils/template-processor.ts
Length of output: 1334
Fix conditional Nuxt env import for t3env addon
The Nuxt scaffold currently unconditionally imports ./env
, but the generated file actually lives at src/env/client.ts
, and projects without the t3env
addon will break at build time. We’ve confirmed that the includes
helper is already registered (see apps/cli/src/utils/template-processor.ts
) and used throughout other templates.
• File to update:
• apps/cli/templates/frontend/nuxt/nuxt.config.ts.hbs (line 1)
• Change the import to be conditional on the t3env
addon and point to the correct path:
- import "./env";
+ {{#if (includes addons "t3env")}}import "~/env/client";{{/if}}
This ensures that only projects with the t3env
addon include the client‐side env shim, and the module resolution aligns with the actual file location.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
import "./env"; | |
++ b/apps/cli/templates/frontend/nuxt/nuxt.config.ts.hbs | |
@@ -1,1 +1,1 | |
{{#if (includes addons "t3env")}}import "~/env/client";{{/if}} |
🤖 Prompt for AI Agents
In apps/cli/templates/frontend/nuxt/nuxt.config.ts.hbs around line 1, the
template currently unconditionally imports ./env which breaks projects without
the t3env addon and points to the wrong location; update the template to
conditionally include the client shim only when the t3env addon is present by
using the existing includes helper to wrap the import, and change the import
target to the correct client path (src/env/client.ts) so only projects with
t3env will import the client-side env shim.
color: "hsl(var(--chart-7))", | ||
}, | ||
none: { | ||
label: "No Addons", | ||
color: "hsl(var(--chart-7))", | ||
color: "hsl(var(--chart-8))", | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Verify availability of CSS token --chart-8 before using it.
You bumped turborepo to --chart-7
and none
to --chart-8
. Ensure --chart-8
exists in the theme; otherwise charts will fallback or render inconsistently.
🏁 Script executed:
#!/bin/bash
# Verify that --chart-8 is defined somewhere in CSS/vars.
rg -nP --type css --type scss --type tsx --type ts -C2 'var\(--chart-8\)' || true
rg -nP --type css --type scss --type tsx --type ts -C2 '--chart-8:' || true
Length of output: 599
🏁 Script executed:
#!/bin/bash
# Search for any definitions or usages of --chart-7 and --chart-8 across the codebase
# Find where --chart-7 is defined to locate the CSS variable declarations
rg -n -- '--chart-7' -C2
# Find any occurrences of --chart-8 (definition or usage)
rg -n -- '--chart-8' -C2
Length of output: 137
🏁 Script executed:
#!/bin/bash
# Correctly search for CSS variable definitions and usages of --chart-7 and --chart-8
# 1. Definitions in CSS/SCSS files
rg -n -C2 '\-\-chart-(7|8)\s*:' -g '*.css' -g '*.scss'
# 2. Usages via var(...) in CSS/SCSS/TS/TSX
rg -n -C2 'var\(--chart-(7|8)\)' -g '*.css' -g '*.scss' -g '*.ts' -g '*.tsx'
Length of output: 10659
Add missing CSS variable --chart-8
in your global styles
The lookup shows that --chart-8
is referenced in apps/web/src/app/(home)/analytics/_components/types.ts (lines 365–366) but not defined in your global stylesheet (only --chart-5
, --chart-6
, and --chart-7
exist). Without a definition, any usage of hsl(var(--chart-8))
will be invalid and render inconsistently.
Please add a matching entry for --chart-8
in apps/web/src/app/global.css alongside the other chart variables:
• File: apps/web/src/app/global.css
• Insert after the existing --chart-7
definition
diff --git a/apps/web/src/app/global.css b/apps/web/src/app/global.css
index abcdef0..1234567 100644
--- a/apps/web/src/app/global.css
+++ b/apps/web/src/app/global.css
@@ -191,6 +191,7 @@
--chart-5: 27 87% 67%;
--chart-6: 210 80% 55%;
--chart-7: 330 75% 60%;
+ --chart-8: 90 70% 50%; /* <-- define this to match your theme palette */
--sidebar: oklch(0.93 0.01 264.52);
--sidebar-foreground: oklch(0.44 0.04 279.33);
Adjust the HSL values (90 70% 50%
) to fit your design’s color scheme. Once defined, hsl(var(--chart-8))
will resolve correctly.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
color: "hsl(var(--chart-7))", | |
}, | |
none: { | |
label: "No Addons", | |
color: "hsl(var(--chart-7))", | |
color: "hsl(var(--chart-8))", | |
}, | |
++ b/apps/web/src/app/global.css | |
@@ -191,6 +191,7 @@ | |
--chart-5: 27 87% 67%; | |
--chart-6: 210 80% 55%; | |
--chart-8: 90 70% 50%; /* define this to match your theme palette */ | |
--sidebar: oklch(0.93 0.01 264.52); | |
--sidebar-foreground: oklch(0.44 0.04 279.33); |
🤖 Prompt for AI Agents
In apps/web/src/app/(home)/analytics/_components/types.ts around lines 361–366
the color uses hsl(var(--chart-8)) but --chart-8 is missing from the global
stylesheet; open apps/web/src/app/global.css and add a --chart-8 variable entry
immediately after the existing --chart-7 definition (use HSL values appropriate
for your theme, e.g., "90 70% 50%" or other chosen values) so that
hsl(var(--chart-8)) resolves correctly across the app.
Possible alternative: https://envin.turbostarter.dev/ |
plz |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (2)
apps/web/src/lib/constant.ts (1)
521-528
: Unify icon source with ICON_BASE_URL or confirm asset pathOther icons use
${ICON_BASE_URL}/...
. This one uses a root path"/icon/t3env.svg"
. Either switch to the CDN base for consistency/caching or ensure the file exists under the app’s public path.Proposed:
- icon: "/icon/t3env.svg", + icon: `${ICON_BASE_URL}/t3env.svg`,apps/web/src/lib/stack-utils.ts (1)
100-116
: De-duplicate addon allowlist: derive from TECH_OPTIONSHardcoding the addon list risks drift. Build the allowlist from
TECH_OPTIONS.addons
.Apply:
`--addons ${ - stack.addons.length > 0 - ? stack.addons - .filter((addon) => - [ - "pwa", - "tauri", - "starlight", - "biome", - "husky", - "turborepo", - "ultracite", - "fumadocs", - "oxlint", - "ruler", - "t3env", - ].includes(addon), - ) - .join(" ") || "none" - : "none" + stack.addons.length > 0 + ? (() => { + const allowedAddons = TECH_OPTIONS.addons.map((a) => a.id); + return ( + stack.addons.filter((addon) => allowedAddons.includes(addon)).join(" ") || + "none" + ); + })() + : "none" }`,
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
💡 Knowledge Base configuration:
- MCP integration is disabled by default for public repositories
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
⛔ Files ignored due to path filters (2)
apps/web/public/icon/t3env.svg
is excluded by!**/*.svg
demo.gif
is excluded by!**/*.gif
📒 Files selected for processing (22)
README.md
(1 hunks)apps/cli/README.md
(3 hunks)apps/cli/package.json
(1 hunks)apps/cli/src/constants.ts
(3 hunks)apps/cli/src/helpers/addons/addons-setup.ts
(2 hunks)apps/cli/src/helpers/addons/t3env-setup.ts
(1 hunks)apps/cli/src/helpers/core/create-readme.ts
(1 hunks)apps/cli/src/prompts/addons.ts
(2 hunks)apps/cli/src/types.ts
(1 hunks)apps/cli/templates/addons/t3env/apps/server/next/next.config.ts
(1 hunks)apps/cli/templates/addons/t3env/apps/server/next/src/env/server.ts.hbs
(1 hunks)apps/cli/templates/addons/t3env/apps/web/next/src/env/client.ts.hbs
(1 hunks)apps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs
(1 hunks)apps/cli/templates/addons/t3env/apps/web/nuxt/src/env/client.ts.hbs
(1 hunks)apps/cli/templates/frontend/nuxt/nuxt.config.ts.hbs
(1 hunks)apps/web/content/docs/cli/options.mdx
(1 hunks)apps/web/content/docs/index.mdx
(1 hunks)apps/web/src/app/(home)/_components/npm-package.tsx
(1 hunks)apps/web/src/app/(home)/analytics/_components/types.ts
(1 hunks)apps/web/src/app/layout.tsx
(1 hunks)apps/web/src/lib/constant.ts
(7 hunks)apps/web/src/lib/stack-utils.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- apps/cli/package.json
- apps/web/src/app/(home)/_components/npm-package.tsx
🚧 Files skipped from review as they are similar to previous changes (16)
- apps/cli/templates/addons/t3env/apps/server/next/next.config.ts
- apps/cli/templates/frontend/nuxt/nuxt.config.ts.hbs
- apps/cli/src/prompts/addons.ts
- apps/cli/src/types.ts
- apps/web/src/app/layout.tsx
- apps/web/content/docs/index.mdx
- apps/cli/src/helpers/addons/addons-setup.ts
- apps/web/content/docs/cli/options.mdx
- apps/cli/README.md
- apps/cli/templates/addons/t3env/apps/web/nuxt/src/env/client.ts.hbs
- apps/web/src/app/(home)/analytics/_components/types.ts
- apps/cli/src/helpers/addons/t3env-setup.ts
- apps/cli/src/constants.ts
- apps/cli/templates/addons/t3env/apps/server/next/src/env/server.ts.hbs
- apps/cli/src/helpers/core/create-readme.ts
- apps/cli/templates/addons/t3env/apps/web/next/src/env/client.ts.hbs
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/convex_rules.mdc)
**/*.{ts,tsx}
: Use Id from './_generated/dataModel' to type document ids (e.g., Id<'users'>)
Ensure Record key/value types align with validators (e.g., v.record(v.id('users'), v.string()) => Record<Id<'users'>, string>)
Be strict with types for document ids; prefer Id<'table'> over string
Use 'as const' for string literals in discriminated unions
When using Array and Record types, declare with explicit generic types (e.g., const arr: Array = ...)In TypeScript, use type aliases (type) instead of interface for type definitions
Files:
apps/web/src/lib/stack-utils.ts
apps/web/src/lib/constant.ts
**/*.{js,jsx,ts,tsx,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/use-bun-instead-of-node-vite-npm-pnpm.mdc)
**/*.{js,jsx,ts,tsx,mjs,cjs}
: Do not use dotenv; Bun auto-loads .env
UseBun.serve()
for HTTP/WebSockets; do not useexpress
Usebun:sqlite
for SQLite; do not usebetter-sqlite3
UseBun.redis
for Redis; do not useioredis
UseBun.sql
for Postgres; do not usepg
orpostgres.js
Use built-inWebSocket
; do not usews
PreferBun.file
overnode:fs
readFile/writeFile
UseBun.$
instead ofexeca
for shelling out
Files:
apps/web/src/lib/stack-utils.ts
apps/web/src/lib/constant.ts
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/better-t-stack-repo.mdc)
Use normal (function declaration) syntax; do not use arrow functions
Files:
apps/web/src/lib/stack-utils.ts
apps/web/src/lib/constant.ts
🪛 LanguageTool
README.md
[grammar] ~42-~42: There might be a mistake here.
Context: ...madocs, Ruler, Ultracite, Oxlint, T3 Env - Examples: Todo, AI - DB Setup: Turso, Ne...
(QB_NEW_EN)
🔇 Additional comments (2)
README.md (1)
42-42
: Docs update looks good“T3 Env” correctly added to the Addons list. No blocking issues.
apps/web/src/lib/constant.ts (1)
608-609
: Consistent preset/default updates to include t3envt3env added to all relevant presets and DEFAULT_STACK. Matches the UI/CLI changes and keeps defaults coherent. LGTM.
Also applies to: 632-633, 656-657, 680-681, 704-713, 754-755
@@ -0,0 +1 @@ | |||
import "@/env/client"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Avoid path alias in next.config; use a relative import
@/
may not resolve when Next evaluates next.config.ts
(Node context). Prefer a relative import to ensure env validation runs at build-time.
Apply:
-import "@/env/client";
+import "./env/client";
If this file is generated at the project root instead of src/
, use:
import "./src/env/client";
Also consider switching to the server env import if present (often recommended): ./env/server
.
To verify the recommendation:
🏁 Script executed:
#!/bin/bash
# 1. Show the import in the template
sed -n '1,50p' apps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs
# 2. Confirm any tsconfig path aliases
rg -n '"paths"' -g 'tsconfig.json' -C3
rg -n '"@/\*"' -g 'tsconfig.json' -C3
Length of output: 876
🌐 Web query:
Next.js tsconfig path aliases next.config.js Node context
💡 Result:
Short summary and practical guidance.
- What Next.js supports
- Next.js natively reads tsconfig.json/jsconfig.json "baseUrl" and "paths" so your imports inside the Next.js app/pages/app code (client + server-side rendering) work with aliases (e.g. import Foo from "@/components/Foo"). [1]
- What does NOT work automatically
- Those TypeScript path mappings are a compile-time / bundler convenience for Next.js and your editor — Node (runtime) does not automatically understand TS "paths". That means standalone Node scripts, ts-node processes, or code executed outside Next’s build pipeline (including some custom code you require from next.config.* or separate server scripts) will NOT resolve tsconfig "paths" unless you add runtime resolution. [1][2]
- Common solutions (pick one)
-
For Next.js code: just use tsconfig "baseUrl"/"paths" — no extra config needed. Example tsconfig snippet:
{
"compilerOptions": {
"baseUrl": ".",
"paths": { "@/components/": ["components/"] }
}
} [1] -
For next.config.ts behavior:
- You can use next.config.ts (typed), but note module resolution in next.config.ts is limited (CommonJS interoperability caveats). You can set typescript.tsconfigPath in next.config to point an alternate tsconfig for builds. [2]
-
For Node runtime (scripts, ts-node, custom server, CLI tools, or if you need aliases inside code executed outside Next’s bundler):
- Use tsconfig-paths with ts-node: install tsconfig-paths and require its register (or configure ts-node to require it). Example: npm i -D tsconfig-paths and run node -r tsconfig-paths/register or add "ts-node": { "require": ["tsconfig-paths/register"] } to tsconfig. This makes TS "paths" resolved at runtime. [3]
- Or use module-alias (npm package) and register aliases at startup (or via package.json _moduleAliases).
- Or use a bundler/babel plugin (babel-plugin-module-resolver) for packages that need compiled aliasing.
- Or simply use relative or absolute Node-style imports (path.resolve) in code executed by Node.
- Quick recommendations
- Keep tsconfig "paths" for app imports (simplest).
- For scripts run with ts-node, add tsconfig-paths/register.
- For next.config.* prefer relative requires or avoid relying on TS path aliases in that file; if you use next.config.ts test behavior locally and in CI. [1][2][3]
Sources
- Next.js docs: Absolute imports & module path aliases. [1]
- Next.js TypeScript config & next.config.ts notes (typescript.tsconfigPath, CommonJS note). [2]
- Runtime resolution with ts-node + tsconfig-paths (practical solution). [3]
Use a relative import in next.config.ts.hbs
Next evaluates next.config.ts in Node (outside Next’s bundler), so TS path aliases like @/…
won’t resolve at runtime. Replace with a relative import:
-import "@/env/client";
+import "./env/client";
If your config is at the project root instead of src/
, use:
import "./src/env/client";
🤖 Prompt for AI Agents
In apps/cli/templates/addons/t3env/apps/web/next/src/next.config.ts.hbs around
line 1, the file uses a TS path alias import ("@/env/client") which fails at
Node runtime because next.config.ts is evaluated outside Next's bundler; change
the import to a relative path pointing to the same file (e.g.,
"./src/env/client" if next.config.ts.hbs lives at project root referencing
src/env/client, or "./env/client" if the config file is inside src/) so Node can
resolve it without TypeScript path aliases.
This pull request introduces support for the T3 Env addon.
Next Steps
References:
[Feature Request] Add Support for t3-env package and backend static serving #253
Request for T3 ENV #422
Summary by CodeRabbit
New Features
Documentation
Style
Chores