Skip to content

Creating a Project ​

vp create interactively scaffolds new Vite+ projects, monorepos, and apps inside existing workspaces.

Overview ​

The create command is the fastest way to start with Vite+. It can be used in a few different ways:

  • Start a new Vite+ monorepo
  • Create a new standalone application or library
  • Add a new app or library inside an existing project

This command can be used with built-in templates, community templates, or remote GitHub templates.

Usage ​

bash
vp create
vp create <template>
vp create <template> -- <template-options>

Built-in Templates ​

Vite+ ships with these built-in templates:

  • vite:monorepo creates a new monorepo
  • vite:application creates a new application
  • vite:library creates a new library
  • vite:generator creates a new code generator (monorepo only, see Code Generators)

Template Sources ​

vp create is not limited to the built-in templates.

  • Use shorthand templates like vite, @tanstack/start, svelte, next-app, nuxt, react-router, and vue
  • Use full package names like create-vite or create-next-app
  • Use local monorepo templates declared in create.templates (for example an internal component or service generator)
  • Use remote templates such as github:user/repo or https://github.com/user/template-repo

Run vp create --list to see the built-in templates and the common shorthand templates Vite+ recognizes.

Options ​

  • --directory <dir> writes the generated project into a specific target directory
  • --agent <name> creates agent instructions files during scaffolding
  • --no-agent skips agent instruction setup
  • --editor <name> writes editor config files
  • --no-editor skips editor config setup
  • --git initialize a git repository
  • --no-git skips git repository initialization
  • --hooks enables pre-commit hook setup
  • --no-hooks skips hook setup
  • --package-manager <name> uses a specified package manager (pnpm, npm, yarn, or bun)
  • --no-interactive runs without prompts
  • --verbose shows detailed scaffolding output
  • --list prints the available built-in and popular templates

Template Options ​

Arguments after -- are passed directly to the selected template.

This matters when the template itself accepts flags. For example, you can forward Vite template selection like this:

bash
vp create vite -- --template react-ts

Examples ​

bash
# Interactive mode
vp create

# Create a Vite+ monorepo, application, library, or generator
vp create vite:monorepo
vp create vite:application
vp create vite:library
vp create vite:generator

# Use shorthand community templates
vp create vite
vp create @tanstack/start
vp create svelte

# Use full package names
vp create create-vite
vp create create-next-app

# Use remote templates
vp create github:user/repo
vp create https://github.com/user/template-repo

Code Generators ​

Monorepos often need to scaffold their own building blocks: a UI component, a service, or an internal package that follows house conventions. Vite+ supports this through generator packages powered by Bingo templates.

Scaffold a generator ​

Inside a Vite+ monorepo, run:

bash
vp create vite:generator

This requires a monorepo workspace. If you don't have one yet, create it first with vp create vite:monorepo.

The scaffolded generator package contains:

  • src/template.ts defines the template using createTemplate from bingo: an options schema built with Zod and a produce() function that returns the files to generate
  • bin/index.ts is the CLI entry, powered by Bingo's runTemplateCLI

If the monorepo has a parent directory matching generators or tools, the new package is placed there by default.

Registration ​

Local generators are declared in create.templates in the monorepo's vite.config.ts. This is the source of truth: only registered templates appear in the vp create picker.

vp create vite:generator registers the generator for you, adding an entry to create.templates in the root vite.config.ts:

ts
import { defineConfig } from 'vite-plus';

export default defineConfig({
  create: {
    templates: [
      { name: 'my-generator', description: 'Generate new components', template: 'my-generator' },
    ],
  },
});

Re-running is idempotent (no duplicate entries), and an existing create.defaultTemplate is preserved. You can also add entries by hand, for example to register a template you didn't scaffold this way. The template value is the generator's workspace package name, or a relative ./path to it.

Run a generator ​

Inside the monorepo, run vp create and pick the generator from the template list, or pass its entry name directly:

bash
# Interactive mode lists registered local templates alongside the built-ins
vp create

# Run a registered template by its name
vp create component

# Pass options to the generator after --
vp create component -- --name @your-org/button

When the generator depends on bingo, Vite+ appends --skip-requests automatically so it skips Bingo's outbound network requests (such as GitHub API calls).

After the generator runs, the created package goes through the regular monorepo integration: workspace registration, dependency installation, and formatting.

Customize a generator ​

Edit src/template.ts to define the options and the files to produce:

ts
import { createTemplate } from 'bingo';
import { z } from 'zod';

export default createTemplate({
  options: {
    name: z.string().describe('Package name'),
  },
  async produce({ options }) {
    return {
      files: {
        'package.json': JSON.stringify({ name: options.name, version: '0.0.0' }, null, 2),
        src: {
          'index.ts': `export const name = '${options.name}';\n`,
        },
      },
    };
  },
});
  • options defines the generator's prompts and flags using Zod schemas
  • produce() returns the files to create, plus optional scripts to run after generation and suggestions to print for the user

See the Bingo documentation for the full template API.

Organization Templates ​

An organization can publish a curated set of templates under a single npm scope by shipping an @org/create package whose package.json carries a createConfig.templates manifest. Once published, vp create @org opens an interactive picker over those templates.

Pick from an org ​

bash
# Open an interactive picker over @your-org/create's manifest
vp create @your-org

# Run a specific manifest entry directly
vp create @your-org:web

# Pin to an exact version or a dist-tag
vp create @your-org@1.2.3
vp create @your-org:web@next

# Set the org as the default for a repo (see create.defaultTemplate config)
vp create

Behind the scenes, vp create @org maps to @org/create (the existing npm create-* convention). If that package has no createConfig.templates field, Vite+ falls back to running the package normally — so adopting the manifest is zero-risk for orgs that already publish @org/create.

Private registries work automatically: Vite+ reads .npmrc files from the project root and ~/, honoring @your-org:registry=... scope mappings and //host/:_authToken=... credentials.

Authoring @org/create ​

There are two common layouts. Pick the one that matches the org's template count and release cadence.

Bundled (recommended for most orgs). All templates live as subdirectories of @org/create itself. Manifest entries use relative ./path values. One repo, one publish, one versioning story — the same pattern used by create-vite and create-next-app.

@your-org/create/
├── package.json              # "createConfig": { "templates": [{ "template": "./templates/web" }, ...] }
├── templates/
│   ├── web/
│   │   ├── package.json
│   │   └── src/...
│   └── library/...
└── README.md

Manifest-only. When the org already publishes independent @org/template-* packages (or hosts them on GitHub), @org/create stays a thin index.

@your-org/create/
├── package.json              # "createConfig": { "templates": [{ "template": "@your-org/template-web" }, ...] }
└── README.md

The two layouts can be mixed — a manifest can point most entries at external packages and keep a few as bundled subdirectories.

Optionally, provide a bin script so npm create @org (the legacy path) keeps working for non-Vite+ users. vp create @org reads the manifest directly and never runs the bin.

Manifest schema ​

The manifest lives at createConfig.templates in @org/create's package.json:

json
{
  "name": "@your-org/create",
  "version": "1.0.0",
  "createConfig": {
    "templates": [
      {
        "name": "monorepo",
        "description": "Monorepo",
        "template": "@your-org/template-monorepo",
        "monorepo": true
      },
      {
        "name": "web",
        "description": "Web app template (Vite + React)",
        "template": "@your-org/template-web"
      },
      {
        "name": "demo",
        "description": "Bundled demo template",
        "template": "./templates/demo"
      }
    ]
  }
}

Each entry supports:

FieldRequiredNotes
nameyesKebab-case identifier. Used by vp create @org:<name> for direct selection. Must be unique within the array.
descriptionyesOne-line description shown in the picker.
templateyesAn npm specifier (@org/template-foo, optionally @version), a GitHub URL (github:user/repo), a vite:* builtin, a local workspace package name, or a relative path (./templates/foo) that resolves against the @org/create root.
monoreponoIf true, marks this entry as a monorepo-creating template. Hidden from the picker when vp create runs inside an existing monorepo, mirroring the built-in vite:monorepo filter.

An invalid manifest is a hard error, not a silent fall-through — a maintainer who shipped a manifest should hear about the offending field, e.g. @your-org/create: createConfig.templates[2].template must be a non-empty string.

Bundled subdirectory templates ​

Relative ./... paths resolve against the enclosing @org/create package root — not the user's cwd. The referenced directory is copied into the target project as-is (no template-engine processing); the only exception is that a small set of underscore-prefixed scaffold files (_gitignore, _npmrc, _yarnrc.yml) are renamed to their dotfile equivalents. Paths that escape the package root are rejected.

Make the org the default in a repo ​

Commit this in vite.config.ts at the project root:

ts
import { defineConfig } from 'vite-plus';

export default defineConfig({
  create: { defaultTemplate: '@your-org' },
});

Now vp create (with no argument) drops straight into the @your-org picker. See create.defaultTemplate for details.

The picker always appends a trailing Vite+ built-in templates entry so vite:monorepo / vite:application / vite:library / vite:generator stay reachable from the picker — selecting it routes to the standard built-in flow. For scripts and CI, explicit specifiers (vp create vite:library) bypass the configured default.

Non-interactive inspection ​

vp create @org --no-interactive prints the manifest as a table and exits 1:

A template name is required when running `vp create @your-org` in non-interactive mode.

Available templates in @your-org/create:

  NAME     DESCRIPTION                          TEMPLATE
  web      Web app template (Vite + React)      @your-org/template-web
  library  TypeScript library template          @your-org/template-library
  demo     Bundled demo template                ./templates/demo

Examples:
  # Scaffold a specific template from the org
  vp create @your-org:web --no-interactive

  # Or use a Vite+ built-in template
  vp create vite:application --no-interactive

Publishing checklist ​

  1. Create @org/create (scoped npm package) if you don't already have one.
  2. Add a createConfig.templates array to package.json. (Bundle the templates under ./templates/... or point at external packages.)
  3. (Optional) Provide a bin launcher for npm create @org compatibility.
  4. Publish.
  5. Verify: vp create @org --no-interactive prints the manifest table; vp create @org opens the picker.
  6. (Optional) Commit create: { defaultTemplate: '@org' } in your internal template repos.