Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .agents/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ node ../cli/packages/cli/dist/index.js create my-app
| Add-on | Plugin that extends apps (auth, DB, etc) | `--add-ons` |
| Template | Reusable project template | `--template` |
| Framework | React or Solid | `--framework` |
| Bundler | Vite (default) or Rsbuild | `--bundler` |

## CLI Commands

Expand All @@ -70,6 +71,7 @@ node ../cli/packages/cli/dist/index.js create my-app
| -------------------- | ------------------------------------------------------- |
| `--add-ons <ids>` | Comma-separated add-on IDs |
| `--framework <name>` | React or Solid |
| `--bundler <name>` | Vite (default) or Rsbuild |
Comment thread
SyMind marked this conversation as resolved.
Outdated
| `--toolchain <id>` | Toolchain (use `--list-add-ons` to see options) |
| `--deployment <id>` | Deployment target (use `--list-add-ons` to see options) |
| `--template <url-or-id>` | Use template URL/path or built-in ID |
Expand All @@ -86,6 +88,7 @@ node ../cli/packages/cli/dist/index.js create my-app
| `projectName` | string | Project name |
| `typescript` | boolean | Always true (TanStack Start requires TS) |
| `tailwind` | boolean | False for blank unless an add-on requires it |
| `bundler` | string | Resolved bundler (`vite` or `rsbuild`) |
| `blank` | boolean | True when using the blank project preset |
| `fileRouter` | boolean | Always true |
| `addOnEnabled` | object | `{ [id]: boolean }` |
Expand Down Expand Up @@ -131,7 +134,7 @@ This project uses [TanStack Intent](https://github.com/TanStack/intent). Run `np
<!-- intent-skills:start -->
# Skill mappings — when working in these areas, load the linked skill file into context.
skills:
- task: "scaffold a new TanStack app with create command, framework, template, toolchain, deployment, or add-on flags"
- task: "scaffold a new TanStack app with create command, framework, bundler, template, toolchain, deployment, or add-on flags"
load: "packages/cli/skills/create-app-scaffold/SKILL.md"
- task: "add add-ons to an existing project using tanstack add"
load: "packages/cli/skills/add-addons-existing-app/SKILL.md"
Expand Down
7 changes: 7 additions & 0 deletions .changeset/green-builders-rise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@tanstack/create': minor
'@tanstack/cli': minor
---

Add first-class Rsbuild bundler support for React and Solid TanStack Start and
router-only scaffolds, including Tailwind and ESLint/Biome toolchains.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ npx @tanstack/cli create my-app

- **TanStack Start** - Full-stack SSR framework (default)
- **TanStack Router** - Type-safe routing (`--router-only` for SPA)
- **Vite or Rsbuild** - Choose the bundler for React and Solid projects
- **Add-ons** - Auth, database, deployment, monitoring, and more
- **CLI Introspection** - Agent-friendly discovery via JSON CLI output

Expand All @@ -59,6 +60,9 @@ npx @tanstack/cli create my-app --blank -y
# Create Router-only SPA (no SSR)
npx @tanstack/cli create my-app --router-only

# Create with Rsbuild
npx @tanstack/cli create my-app --bundler rsbuild -y

# With add-ons
npx @tanstack/cli create my-app --add-ons clerk,drizzle,tanstack-query

Expand All @@ -84,7 +88,7 @@ npx @tanstack/cli search-docs "loaders" --library router --framework react --jso

TanStack CLI sends anonymous usage telemetry by default.

- Sent: command usage, durations, selected framework/package manager/add-on ids, and coarse result metadata
- Sent: command usage, durations, selected framework/bundler/package manager/add-on ids, and coarse result metadata
- Never sent: project names, file paths, target directories, raw search queries, raw template URLs/paths, add-on config values, env vars, or raw error messages
- Disabled automatically in `CI`, or when `DO_NOT_TRACK=1` or `TANSTACK_CLI_TELEMETRY_DISABLED=1`

Expand Down
4 changes: 4 additions & 0 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ tanstack create [project-name] [options]
| `--blank` | Create a minimal one-route Start project without default starter UI, examples, Tailwind, devtools, or a test stack |
| `--package-manager <pm>` | `npm`, `pnpm`, `yarn`, `bun`, `deno` |
| `--framework <name>` | `React`, `Solid` |
| `--bundler <name>` | `vite` (default), `rsbuild` |
| `--router-only` | Create file-based Router-only app without TanStack Start (add-ons/deployment/template disabled) |
| `--toolchain <id>` | Toolchain add-on (use `--list-add-ons` to see options) |
| `--deployment <id>` | Deployment add-on (use `--list-add-ons` to see options) |
Expand All @@ -41,6 +42,8 @@ tanstack create my-app --blank -y
tanstack create my-app --blank --deployment cloudflare -y
tanstack create my-app --add-ons clerk,drizzle,tanstack-query
tanstack create my-app --router-only --toolchain eslint --no-examples
tanstack create my-app --bundler rsbuild -y
tanstack create my-app --framework Solid --bundler rsbuild --router-only --blank --toolchain biome -y
tanstack create my-app --template https://example.com/template.json
tanstack create my-app --template ecommerce
tanstack create --list-add-ons --framework React --json
Expand Down Expand Up @@ -126,6 +129,7 @@ await create.createApp(environment, {
targetDir: '/app',
framework: framework!,
mode: 'file-router',
bundler: 'vite',
typescript: true,
tailwind: true,
packageManager: 'pnpm',
Expand Down
6 changes: 6 additions & 0 deletions docs/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ npx @tanstack/cli create my-app --add-ons tanstack-query,clerk,drizzle -y

# Router-only SPA (no SSR)
npx @tanstack/cli create my-app --router-only -y

# Rsbuild instead of the default Vite bundler
npx @tanstack/cli create my-app --bundler rsbuild -y

# Minimal router-only Rsbuild app
npx @tanstack/cli create my-app --bundler rsbuild --router-only --blank -y
```

Blank projects omit the default starter interface, examples, Tailwind,
Expand Down
18 changes: 16 additions & 2 deletions packages/cli/skills/create-app-scaffold/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
---
name: create-app-scaffold
description: >
Scaffold a TanStack app with tanstack create using --framework, --template,
Scaffold a TanStack app with tanstack create using --framework, --bundler, --template,
--toolchain, --deployment, --add-ons, --blank, and --router-only. Covers flag
compatibility, non-interactive defaults, and intent-preserving command
construction.
metadata:
type: core
library: tanstack-cli
library_version: "0.70.0"
library_version: "0.71.0"
---

# Create App Scaffold
Expand All @@ -28,6 +28,19 @@ npx @tanstack/cli create acme-web \

## Core Patterns

### Choose Vite or Rsbuild explicitly

Vite is the default. Use Rsbuild for React or Solid when the requested project
fits its initial compatibility surface.

```bash
npx @tanstack/cli create acme-web \
--framework react \
--bundler rsbuild \
--toolchain biome \
-y
```

### Build a deterministic non-interactive scaffold

```bash
Expand Down Expand Up @@ -162,5 +175,6 @@ See also: query-docs-library-metadata/SKILL.md § Common Mistakes

- [Create flag compatibility matrix](references/create-flag-compatibility-matrix.md)
- [Framework adapter options](references/framework-adapters.md)
- [Bundler options](references/bundlers.md)
- [Deployment provider options](references/deployment-providers.md)
- [Toolchain options](references/toolchains.md)
27 changes: 27 additions & 0 deletions packages/cli/skills/create-app-scaffold/references/bundlers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Bundler Options

Targets `@tanstack/cli` v0.71.0.

## Supported values

- `vite` (default)
- `rsbuild`

## Usage

```bash
npx @tanstack/cli create app --framework react --bundler vite -y
npx @tanstack/cli create app --framework solid --bundler rsbuild -y
```

Rsbuild supports full TanStack Start and router-only projects, including the
standard and `--blank` presets, built-in example pages, Tailwind, ESLint, and
Biome. It does not currently support templates, deployment adapters, or
catalog business/example add-ons. `tanstack add` is limited to ESLint/Biome in
Rsbuild projects.

Use the bundler-aware catalog view before constructing an Rsbuild command:

```bash
npx @tanstack/cli create --list-add-ons --bundler rsbuild --json
```
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
# Create Flag Compatibility Matrix

Targets `@tanstack/cli` v0.70.0.
Targets `@tanstack/cli` v0.71.0.

## Compatibility

| Flag | Works with normal create | Works with `--router-only` | Notes |
|---|---|---|---|
| `--framework` | yes | yes | Framework is still honored in both modes. |
| `--bundler` | yes | yes | `vite` is the default; `rsbuild` supports React and Solid. |
| `--toolchain` | yes | yes | Toolchain selection remains available. |
| `--add-ons` | yes | no | Ignored in router-only mode. |
| `--deployment` | yes | no | Ignored in router-only mode. |
Expand All @@ -15,14 +16,18 @@ Targets `@tanstack/cli` v0.70.0.
| `--blank` | yes | yes | Omits starter UI, examples, Tailwind, devtools, and test tooling unless an explicit integration requires them. Cannot be combined with a template, `--examples`, or `--tailwind`. |
| `--tailwind` / `--no-tailwind` | deprecated/ignored | deprecated/ignored | Standard scaffolds enable Tailwind; use `--blank` for the supported minimal preset. |

With `--bundler rsbuild`, only toolchain catalog entries are compatible.
Templates, deployments, and business/example add-ons are rejected. Built-in
demo pages controlled by `--examples` remain available.

Source: `packages/cli/src/command-line.ts:337`

## Recommended command construction order

1. Choose mode (`--router-only` or full scaffold).
2. If full scaffold, resolve add-ons and deployment first.
3. Add framework and toolchain.
4. Pass explicit add-on ids and use `-y` only after flags are final.
1. Choose framework and bundler.
2. Choose mode (`--router-only` or full scaffold).
3. If using Vite full scaffold, resolve add-ons, template, and deployment.
4. Add the toolchain and use `-y` only after flags are final.

## Safe presets

Expand All @@ -35,4 +40,7 @@ npx @tanstack/cli create app --blank --framework react --deployment cloudflare -

# Router-only preset
npx @tanstack/cli create app --router-only --framework react --toolchain biome -y

# Rsbuild preset
npx @tanstack/cli create app --framework solid --bundler rsbuild --toolchain biome -y
```
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Framework Adapter Options

Targets `@tanstack/cli` v0.70.0.
Targets `@tanstack/cli` v0.71.0.

## Supported values

Expand Down
37 changes: 35 additions & 2 deletions packages/cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ import {
createApp,
devAddOn,
getAllAddOns,
getBundlers,
getFrameworkByName,
getFrameworks,
initAddOn,
initStarter,
isDemoFilePath,
resolveBundler,
} from '@tanstack/create'
import {
LIBRARY_GROUPS,
Expand Down Expand Up @@ -167,7 +169,7 @@ function getCreateCommandVariant(options: CliOptions) {
return 'scaffold'
}

function getCreateTelemetryProperties(projectName: string, options: CliOptions) {
export function getCreateTelemetryProperties(projectName: string, options: CliOptions) {
const addOnIds = Array.isArray(options.addOns)
? sanitizeIdList(options.addOns)
: undefined
Expand All @@ -181,6 +183,7 @@ function getCreateTelemetryProperties(projectName: string, options: CliOptions)
: undefined,
command_variant: getCreateCommandVariant(options),
deployment: options.deployment ? sanitizeId(options.deployment) : undefined,
bundler: options.bundler ? sanitizeId(options.bundler) : undefined,
examples: options.examples,
blank: !!options.blank,
framework: options.framework ? sanitizeId(options.framework) : undefined,
Expand All @@ -200,7 +203,7 @@ function getCreateTelemetryProperties(projectName: string, options: CliOptions)
}
}

function getResolvedCreateTelemetryProperties(
export function getResolvedCreateTelemetryProperties(
finalOptions: Options,
cliOptions: CliOptions,
) {
Expand All @@ -221,6 +224,7 @@ function getResolvedCreateTelemetryProperties(
add_on_count: addOnIds.length,
add_on_ids: addOnIds,
deployment: deployment ? sanitizeId(deployment.id) : undefined,
bundler: sanitizeId(finalOptions.bundler ?? 'vite'),
examples: includeExamples,
blank: finalOptions.projectPreset === 'blank',
framework: sanitizeId(finalOptions.framework.id),
Expand Down Expand Up @@ -306,6 +310,9 @@ export function cli({
lines.push(` Project: ${finalOptions.projectName}`)
lines.push(` Location: ${finalOptions.targetDir}`)
lines.push(` Framework: ${finalOptions.framework.name}`)
lines.push(
` Bundler: ${resolveBundler(finalOptions.framework, finalOptions.bundler).name}`,
)
lines.push(` Mode: ${finalOptions.mode}`)
if (finalOptions.projectPreset === 'blank') {
lines.push(` Preset: blank`)
Expand Down Expand Up @@ -565,6 +572,13 @@ export function cli({
}
}

const bundlers = new Set<string>()
for (const framework of getFrameworks()) {
for (const bundler of getBundlers(framework)) {
bundlers.add(bundler.id)
}
}

// Mode is always file-router (TanStack Start)
const defaultMode = 'file-router'
const categoryAliases: Record<string, string> = {
Expand Down Expand Up @@ -660,6 +674,7 @@ export function cli({
const addOns = await getAllAddOns(
getFrameworkByName(options.framework || defaultFramework || 'React')!,
defaultMode,
options.bundler,
)
const visibleAddOns = addOns.filter((a) => !forcedAddOns.includes(a.id))
telemetry.mergeProperties({
Expand Down Expand Up @@ -705,6 +720,7 @@ export function cli({
const addOns = await getAllAddOns(
getFrameworkByName(options.framework || defaultFramework || 'React')!,
defaultMode,
options.bundler,
)
const addOn =
addOns.find((a) => a.id === options.addonDetails) ??
Expand Down Expand Up @@ -958,6 +974,23 @@ export function cli({
}

cmd
.option<string>(
`--bundler <${Array.from(bundlers).join('|')}>`,
'select the project bundler',
(value) => {
const bundler = Array.from(bundlers).find(
(item) => item.toLowerCase() === value.toLowerCase(),
)
if (!bundler) {
throw new InvalidArgumentError(
`Invalid bundler: ${value}. The following are allowed: ${Array.from(
bundlers,
).join(', ')}`,
)
}
return bundler
},
)
.option(
'--starter [url-or-id]',
'DEPRECATED: use --template. Initializes from a template URL or built-in id',
Expand Down
Loading