Skip to content

Commit 376e2f2

Browse files
committed
docs: overhaul TanStack Start guide for Vite default and Rsbuild
Rewrite the framework guide in the-voice register: Turbo lead, Vite as the default CLI path, Rsbuild Callout with manual install, Callouts instead of ::: directives, schema as its own H2, and named arkenvRsbuildPlugin import. Mention both plugins on the frameworks index card.
1 parent 4330be4 commit 376e2f2

2 files changed

Lines changed: 113 additions & 116 deletions

File tree

apps/www/content/docs/frameworks/index.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Choose your framework to get started:
1717

1818
<Card href="/docs/frameworks/vite" title="Vite" description="@arkenv/vite-plugin transform mode and VITE_ keys." />
1919

20-
<Card href="/docs/frameworks/tanstack-start" title="TanStack Start" description="@arkenv/vite-plugin with tanstackStart() and createServerFn." />
20+
<Card href="/docs/frameworks/tanstack-start" title="TanStack Start" description="@arkenv/vite-plugin / @arkenv/rsbuild-plugin with tanstackStart() and createServerFn." />
2121

2222
<Card href="/docs/frameworks/bun" title="Bun fullstack dev server" description="@arkenv/bun-plugin for Bun bundler and fullstack apps." />
2323

apps/www/content/docs/frameworks/tanstack-start.mdx

Lines changed: 112 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -3,131 +3,112 @@ title: TanStack Start
33
description: Learn how to use ArkEnv in a TanStack Start project.
44
---
55

6-
TanStack Start apps validate environment variables with `@arkenv/vite-plugin`
7-
or `@arkenv/rsbuild-plugin`, depending on your underlying bundler. ArkEnv
8-
inlines public keys (`VITE_` or `PUBLIC_`) into the client bundle, keeps server
9-
secrets inside server functions, and throws if client code reads them.
6+
TanStack Start is designed to work seamlessly with typesafe env
7+
validation. TanStack Start apps use ArkEnv to validate environment
8+
variables at boot, inline public keys into the client bundle, and keep
9+
server secrets inside server functions.
1010

1111
For high-level architectural trade-offs, see
1212
[Frameworks](/docs/frameworks).
1313

14-
:::warning[`arkenv` is CLI-only — import `@arkenv/core`]
15-
Runtime validation lives in `@arkenv/core` (ArkType) or `@arkenv/standard`
16-
(Zod/Valibot). The `arkenv` package on npm is the interactive CLI only.
17-
`import arkenv from "arkenv"` throws and points you at `@arkenv/core`.
18-
See [`init` reference](/docs/reference/init#import-the-validator-from-core).
19-
:::
20-
2114
## Quickstart
2215

23-
You can create a new TanStack Start project with ArkEnv pre-configured using the
24-
official TanStack CLI add-on, or scaffold it into an existing project.
16+
Vite is the default path. The TanStack CLI add-on scaffolds the Vite
17+
plugin, an `env.ts` schema, and ArkType as the validator engine.
2518

26-
### Create a new project with TanStack CLI
19+
### Create a new project
2720

28-
Generate a new TanStack Start project with the ArkEnv add-on:
21+
Generate a TanStack Start app with ArkEnv wired in:
2922

3023
```package-install
3124
npx @tanstack/cli create my-app --add-ons https://arkenv.js.org/tanstack/info.json
3225
```
3326

34-
By default, the add-on scaffolds with **ArkType** (`@arkenv/core`) and includes the interactive demo route at `/demo/arkenv`.
35-
36-
Configuration options supported by the add-on:
37-
38-
- **Validator Engine**:
39-
- **ArkType** (default) — installs `@arkenv/core` and `arktype`
40-
- **Zod** — installs `@arkenv/standard` and `zod`
41-
- **Valibot** — installs `@arkenv/standard` and `valibot`
42-
- **Interactive Demo Route**:
43-
- **Include `/demo/arkenv`** (default) — scaffolds an interactive secret leak test showcasing server-only isolation in the browser
44-
- **Skip demo route** — scaffolds only the schema definition and plugin configuration (automatically skipped when creating a project with `--no-examples` or the `blank` preset)
27+
The add-on installs the validator runtime, registers
28+
`arkenvVitePlugin()` in `vite.config.ts`, writes `src/env.ts`, and
29+
pre-populates declared keys in `.env.example`.
4530

46-
The add-on automatically:
31+
### Existing projects
4732

48-
- Installs the required validator runtime and dev dependencies
49-
- Configures `arkenvVitePlugin()` in `vite.config.ts`
50-
- Generates `src/env.ts` with your selected validator engine
51-
- Pre-populates declared keys in `.env.example`
33+
If you already have a TanStack Start app on Vite, add ArkEnv with either
34+
the TanStack CLI add-on or the ArkEnv CLI:
5235

53-
<Callout type="info" title="Adding to an existing TanStack project">
54-
If you already have a TanStack application, add ArkEnv directly with the TanStack CLI:
55-
56-
```package-install
57-
npx @tanstack/cli add https://arkenv.js.org/tanstack/info.json
58-
```
59-
</Callout>
60-
61-
### Existing projects with ArkEnv CLI
62-
63-
If you prefer using the ArkEnv CLI in an existing TanStack Start project:
36+
```package-install
37+
npx @tanstack/cli add https://arkenv.js.org/tanstack/info.json
38+
```
6439

6540
```package-install
6641
npx arkenv init
6742
```
6843

69-
The CLI detects `@tanstack/react-start` in your dependencies and installs
70-
`@arkenv/vite-plugin` the same way it does for Vite projects. For Rsbuild
71-
setups, follow [Manual installation](#manual-installation) below.
44+
`arkenv init` detects `@tanstack/react-start` and installs
45+
`@arkenv/vite-plugin` the same way it does for Vite projects.
7246

73-
:::info[Pinning alphas]
74-
Until GA, pin exact `@arkenv/*` alpha versions in the lockfile if you want
75-
bit-for-bit reproducibility across machines and CI.
76-
:::
47+
<Callout type="info" title="Using Rsbuild?">
48+
ArkEnv fully supports Rsbuild via `@arkenv/rsbuild-plugin`.
49+
`@tanstack/cli` does not currently support Rsbuild for scaffolding or
50+
add-ons (track
51+
[TanStack/cli#505](https://github.com/TanStack/cli/pull/505)).
52+
Configure via [Manual installation](#manual-installation) and
53+
[Rsbuild](#rsbuild).
54+
</Callout>
7755

7856
## Manual installation
7957

80-
Install the plugin that matches your bundler (`@arkenv/vite-plugin` for Vite or
81-
`@arkenv/rsbuild-plugin` for Rsbuild) alongside your chosen validation engine.
58+
Install the plugin that matches your bundler alongside your validation
59+
engine. Author bare `@arkenv/*` package names; the docs site applies the
60+
release tag automatically.
8261

8362
<Callout type="info">
84-
Prefer `@arkenv/core` and your host plugin as app dependencies — not the
85-
`arkenv` CLI package.
63+
Prefer `@arkenv/core` and your host plugin as app dependencies — not
64+
the `arkenv` CLI package.
8665
</Callout>
8766

88-
### ArkType engine
67+
### Vite
8968

90-
For Vite:
69+
#### ArkType engine
9170

9271
```package-install
9372
npm install @arkenv/core arktype
9473
npm install -D @arkenv/vite-plugin
9574
```
9675

97-
For Rsbuild:
76+
#### Standard Schema engine
77+
78+
If you aren't using ArkType, install `@arkenv/standard`:
9879

9980
```package-install
100-
npm install @arkenv/core arktype
101-
npm install -D @arkenv/rsbuild-plugin
81+
npm install @arkenv/standard
82+
npm install -D @arkenv/vite-plugin
10283
```
10384

104-
### Standard Schema engine
105-
106-
If you aren't using ArkType, install `@arkenv/standard`:
85+
### Rsbuild
10786

108-
For Vite:
87+
#### ArkType engine
10988

11089
```package-install
111-
npm install @arkenv/standard
112-
npm install -D @arkenv/vite-plugin
90+
npm install @arkenv/core arktype
91+
npm install -D @arkenv/rsbuild-plugin
11392
```
11493

115-
For Rsbuild:
94+
#### Standard Schema engine
95+
96+
If you aren't using ArkType, install `@arkenv/standard`:
11697

11798
```package-install
11899
npm install @arkenv/standard
119100
npm install -D @arkenv/rsbuild-plugin
120101
```
121-
122102
## Configuration
123103

124-
Register the plugin next to TanStack Start and React in your bundler config.
104+
Register the ArkEnv plugin next to TanStack Start and React in your
105+
bundler config.
125106

126107
### Vite
127108

128-
TanStack Start's React recipe on Vite expects `viteReact()` after `tanstackStart()`
129-
(for JSX / Fast Refresh). Add `arkenvVitePlugin()` to the same `plugins`
130-
array:
109+
TanStack Start's React recipe on Vite expects `viteReact()` after
110+
`tanstackStart()` (for JSX / Fast Refresh). Add `arkenvVitePlugin()` to
111+
the same `plugins` array:
131112

132113
```ts title="./vite.config.ts"
133114
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
@@ -149,20 +130,22 @@ Install `@vitejs/plugin-react` if it is not already a dependency. If you
149130
aren't using ArkType, import the ArkEnv plugin from
150131
`@arkenv/vite-plugin/standard`.
151132

152-
:::warning[React Refresh plugin required for client hydration]
153-
TanStack Start React dev mode requires the React Refresh runtime (`/@react-refresh`). You must include `@vitejs/plugin-react` (or `@vitejs/plugin-react-swc`) in your Vite `plugins` array and place it **after** `tanstackStart()`.
154-
155-
If the React plugin is missing, Vite fails to load the client entry (`/@react-refresh could not be resolved`). The page will still render via SSR, but client-side hydration fails, leaving interactive handlers (like `onClick` listeners) unattached.
156-
:::
133+
<Callout type="warn" title="React Refresh after tanstackStart()">
134+
Place `@vitejs/plugin-react` (or `@vitejs/plugin-react-swc`) **after**
135+
`tanstackStart()`. Without it, Vite cannot resolve `/@react-refresh`,
136+
SSR still renders, and client hydration fails so handlers never attach.
137+
</Callout>
157138

158139
### Rsbuild
159140

160-
TanStack Start also supports [Rsbuild](https://rsbuild.dev) via `@tanstack/react-start/plugin/rsbuild`. Register `arkenvRsbuildPlugin()` in your `rsbuild.config.ts`:
141+
TanStack Start also supports [Rsbuild](https://rsbuild.dev) via
142+
`@tanstack/react-start/plugin/rsbuild`. Register
143+
`arkenvRsbuildPlugin()` in your `rsbuild.config.ts`:
161144

162145
```ts title="./rsbuild.config.ts"
163146
import { pluginReact } from "@rsbuild/plugin-react";
164147
import { tanstackStart } from "@tanstack/react-start/plugin/rsbuild";
165-
import arkenvRsbuildPlugin from "@arkenv/rsbuild-plugin";
148+
import { arkenvRsbuildPlugin } from "@arkenv/rsbuild-plugin";
166149
import { defineConfig } from "@rsbuild/core";
167150

168151
export default defineConfig({
@@ -177,11 +160,19 @@ export default defineConfig({
177160
If you aren't using ArkType, import the plugin from
178161
`@arkenv/rsbuild-plugin/standard`.
179162

180-
### Define your schema
163+
## Define your schema
181164

182-
Create an `env.ts` file in your source tree. Keys your client bundle reads must
183-
match your bundler's client prefix: `VITE_` for Vite or `PUBLIC_` for Rsbuild.
184-
Everything else stays on the server:
165+
Create an `env.ts` file in your source tree. Keys your client bundle
166+
reads must match your bundler's client prefix: `VITE_` for Vite or
167+
`PUBLIC_` for Rsbuild. Everything else stays on the server.
168+
169+
<Callout type="info" title="Import from `@arkenv/core`, not `arkenv`">
170+
Runtime validation lives in `@arkenv/core` (ArkType) or
171+
`@arkenv/standard` (Zod/Valibot). The `arkenv` package is the
172+
interactive CLI only. Importing `arkenv` from the CLI package throws
173+
and points you at `@arkenv/core`. See
174+
[`init` reference](/docs/reference/init#import-the-validator-from-core).
175+
</Callout>
185176

186177
<Tabs items={["Vite", "Rsbuild"]}>
187178
<Tab value="Vite">
@@ -211,22 +202,22 @@ Everything else stays on the server:
211202
</Tab>
212203
</Tabs>
213204

214-
:::tip[Pass the schema as an object literal]
215-
Pass the object literal into `arkenv({ ... })`, or wrap a shared shape with
216-
`type(...)` from `@arkenv/core`. An untyped intermediate object can break
217-
overload inference.
218-
:::
205+
<Callout type="info" title="Pass the schema as an object literal">
206+
Pass the object literal into `arkenv({ ... })`, or wrap a shared shape
207+
with `type(...)` from `@arkenv/core`. An untyped intermediate object
208+
can break overload inference.
209+
</Callout>
219210

220211
## Server functions and client access
221212

222-
Read the validated `env` object from your schema module in routes and server
223-
functions.
213+
Read the validated `env` object from your schema module in routes and
214+
server functions.
224215

225216
### Server keys in createServerFn
226217

227-
Server-only keys work inside `createServerFn` handlers. The handler runs on the
228-
server, where `env.ts` executes the real validation runtime against your
229-
process environment:
218+
Server-only keys work inside `createServerFn` handlers. The handler runs
219+
on the server, where `env.ts` executes the real validation runtime
220+
against your process environment:
230221

231222
<Tabs items={["Vite", "Rsbuild"]}>
232223
<Tab value="Vite">
@@ -290,14 +281,15 @@ process environment:
290281

291282
### Client keys in components
292283

293-
Client components read public keys (`VITE_*` on Vite, `PUBLIC_*` on Rsbuild)
294-
from the same import. The plugin rewrites the client module so these values
295-
are inlined as coerced literals.
284+
Client components read public keys (`VITE_*` on Vite, `PUBLIC_*` on
285+
Rsbuild) from the same import. The plugin rewrites the client module so
286+
these values are inlined as coerced literals.
296287

297-
:::warning[Do not read `import.meta.env` directly]
298-
Reading `import.meta.env` skips ArkEnv. Import `{ env }` so public keys stay
299-
typed and coerced and server secrets stay out of the client bundle.
300-
:::
288+
<Callout type="warn" title="Do not read `import.meta.env` directly">
289+
Reading `import.meta.env` skips ArkEnv. Import `{ env }` so public keys
290+
stay typed and coerced and server secrets stay out of the client
291+
bundle.
292+
</Callout>
301293

302294
Reading a server-only key in the browser throws instead of leaking:
303295

@@ -320,29 +312,34 @@ Reading a server-only key in the browser throws instead of leaking:
320312
## SSR and the client boundary
321313

322314
TanStack Start builds two module graphs: the SSR graph for the server
323-
functions and routes you render on the server, and the client graph for what
324-
ships to the browser.
325-
326-
- **Server graph:** `env.ts` executes the real `@arkenv/core` runtime at boot
327-
and validates your process environment before requests are served. `createServerFn`
328-
handlers run on this graph, so they read real, validated values.
329-
- **Client graph:** `@arkenv/vite-plugin` or `@arkenv/rsbuild-plugin` transforms `env.ts` during the client
330-
build. It inlines public values and replaces private server keys with
331-
throwing getters, so the validator engine never ships to the browser.
332-
333-
Like Vite and Rsbuild, TanStack Start loads `.env*` files in development. In production, the
334-
environment comes from the process that starts your server, so containers must
335-
inject variables before boot.
315+
functions and routes you render on the server, and the client graph for
316+
what ships to the browser.
317+
318+
- **Server graph:** `env.ts` executes the real `@arkenv/core` runtime at
319+
boot and validates your process environment before requests are
320+
served. `createServerFn` handlers run on this graph, so they read
321+
real, validated values.
322+
- **Client graph:** `@arkenv/vite-plugin` or `@arkenv/rsbuild-plugin`
323+
transforms `env.ts` during the client build. It inlines public values
324+
and replaces private server keys with throwing getters, so the
325+
validator engine never ships to the browser.
326+
327+
Like Vite and Rsbuild, TanStack Start loads `.env*` files in
328+
development. In production, the environment comes from the process that
329+
starts your server, so containers must inject variables before boot.
336330

337331
## Examples
338332

339333
Run a complete setup end to end:
340334

341-
- [`with-tanstack-start`](https://github.com/yamcodes/arkenv/tree/v1/examples/with-tanstack-start): TanStack Start with Vite and `@arkenv/vite-plugin`.
342-
- [`with-tanstack-start-rsbuild`](https://github.com/yamcodes/arkenv/tree/v1/examples/with-tanstack-start-rsbuild): TanStack Start with Rsbuild and `@arkenv/rsbuild-plugin`.
335+
- [`with-tanstack-start`](https://github.com/yamcodes/arkenv/tree/v1/examples/with-tanstack-start):
336+
TanStack Start with Vite and `@arkenv/vite-plugin`.
337+
- [`with-tanstack-start-rsbuild`](https://github.com/yamcodes/arkenv/tree/v1/examples/with-tanstack-start-rsbuild):
338+
TanStack Start with Rsbuild and `@arkenv/rsbuild-plugin`.
343339

344-
Both examples demonstrate server-only `DATABASE_URL` accessed inside `createServerFn`,
345-
public keys rendered in a client component, and a button that demonstrates the client-side throw.
340+
Both examples demonstrate server-only `DATABASE_URL` accessed inside
341+
`createServerFn`, public keys rendered in a client component, and a
342+
button that demonstrates the client-side throw.
346343

347344
## Next steps
348345

0 commit comments

Comments
 (0)