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
vp create
vp create <template>
vp create <template> -- <template-options>Built-in Templates
Vite+ ships with these built-in templates:
vite:monorepocreates a new monorepovite:applicationcreates a new applicationvite:librarycreates a new libraryvite:generatorcreates 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, andvue - Use full package names like
create-viteorcreate-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/repoorhttps://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-agentskips agent instruction setup--editor <name>writes editor config files--no-editorskips editor config setup--gitinitialize a git repository--no-gitskips git repository initialization--hooksenables pre-commit hook setup--no-hooksskips hook setup--package-manager <name>uses a specified package manager (pnpm,npm,yarn, orbun)--no-interactiveruns without prompts--verboseshows detailed scaffolding output--listprints 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:
vp create vite -- --template react-tsExamples
# 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-repoCode 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:
vp create vite:generatorThis 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.tsdefines the template usingcreateTemplatefrombingo: an options schema built with Zod and aproduce()function that returns the files to generatebin/index.tsis the CLI entry, powered by Bingo'srunTemplateCLI
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:
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:
# 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/buttonWhen 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:
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`,
},
},
};
},
});optionsdefines the generator's prompts and flags using Zod schemasproduce()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
# 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 createBehind 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.mdManifest-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.mdThe 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:
{
"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:
| Field | Required | Notes |
|---|---|---|
name | yes | Kebab-case identifier. Used by vp create @org:<name> for direct selection. Must be unique within the array. |
description | yes | One-line description shown in the picker. |
template | yes | An 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. |
monorepo | no | If 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:
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-interactivePublishing checklist
- Create
@org/create(scoped npm package) if you don't already have one. - Add a
createConfig.templatesarray topackage.json. (Bundle the templates under./templates/...or point at external packages.) - (Optional) Provide a
binlauncher fornpm create @orgcompatibility. - Publish.
- Verify:
vp create @org --no-interactiveprints the manifest table;vp create @orgopens the picker. - (Optional) Commit
create: { defaultTemplate: '@org' }in your internal template repos.