# bun create

> Create a new Bun project from a React component, a `create-<template>` npm package, a GitHub repo, or a local template

<Note>
  `bun create` is optional — Bun works without any configuration. This command exists to make getting started faster.
</Note>

---

Template a new Bun project with `bun create`. It creates a project from a React component, a `create-<template>` npm package, a GitHub repo, or a local template.

To create an empty project, use [`bun init`](https://bun.aphrody.app/docs/runtime/templating/init).

## From a React component

`bun create ./MyComponent.tsx` turns an existing React component into a complete dev environment with hot reload and production builds in one command.

```bash
bun create ./MyComponent.jsx # .tsx also supported
```

<Frame>
  <video
    style={{ aspectRatio: "2062 / 1344", width: "100%", height: "100%", objectFit: "contain" }}
    loop
    autoPlay
    muted
    playsInline
  >
    <source
      src="https://bun.aphrody.app/docs/images/bun-create-shadcn.mp4"
      style={{ width: "100%", height: "100%", objectFit: "contain" }}
      type="video/mp4"
    />
  </video>
</Frame>

<Note>
🚀 **Create React App Successor** — `bun create <component>` provides everything developers loved about Create React App, but with modern tooling, faster builds, and backend support.
</Note>

#### How this works

When you run `bun create <component>`, Bun:

1. Uses [Bun's JavaScript bundler](https://bun.aphrody.app/docs/bundler) to analyze your module graph.
2. Collects all the dependencies needed to run the component.
3. Scans the exports of the entry point for a React component.
4. Generates a `package.json` file with the dependencies and scripts needed to run the component.
5. Installs any missing dependencies using [`bun install --only-missing`](https://bun.aphrody.app/docs/pm/cli/install).
6. Generates the following files:
   - `${component}.html`
   - `${component}.client.tsx` (entry point for the frontend)
   - `${component}.css`
7. Starts a frontend dev server.

If `${component}.css` already exists, Bun replaces it only when its content is identical to a stylesheet that `bun create` generates. Otherwise Bun keeps your file and prints `(already exists, skipping)`. Pass `--force` to overwrite every file Bun would otherwise keep, `package.json` included. Bun overwrites `${component}.html`, `${component}.client.tsx`, and `${component}.build.ts` on each run, so put your changes in other files.

### Using TailwindCSS with Bun

[TailwindCSS](https://tailwindcss.com/) is a utility-first CSS framework for styling web applications.

When you run `bun create <component>`, Bun scans your JSX/TSX file (and any files it imports) for TailwindCSS class names. If Bun detects TailwindCSS class names, it adds the following dependencies to your `package.json`:

```json package.json icon="file-json"
{
  "dependencies": {
    "tailwindcss": "^4",
    "bun-plugin-tailwind": "latest"
  }
}
```

Bun also configures `bunfig.toml` to use its TailwindCSS plugin with `Bun.serve()`:

```toml bunfig.toml icon="settings"
[serve.static]
plugins = ["bun-plugin-tailwind"]
```

Bun also writes a `${component}.css` file with `@import "tailwindcss";` at the top:

```css MyComponent.css icon="file-code"
@import "tailwindcss";
```

If Bun keeps your `${component}.css`, put `@import "tailwindcss";` at the top of that file to use TailwindCSS utilities.

### Using `shadcn/ui` with Bun

[`shadcn/ui`](https://ui.shadcn.com/) is a component library tool for building web applications.

`bun create <component>` scans for any shadcn/ui components imported from `@/components/ui`.

If it finds any, it runs:

```bash terminal icon="terminal"
# Assuming bun detected imports to @/components/ui/accordion and @/components/ui/button
bunx shadcn@canary add accordion button # and any other components
```

Since `shadcn/ui` itself uses TailwindCSS, `bun create` also adds the TailwindCSS dependencies to your `package.json` and configures `bunfig.toml` to use Bun's TailwindCSS plugin with `Bun.serve()`, as described earlier.

`bun create` also sets up:

- `tsconfig.json` to alias `"@/*"` to `"src/*"` or `.` (depending on whether there is a `src/` directory)
- `components.json` so that shadcn/ui knows it's a shadcn/ui project
- `styles/globals.css` file that configures Tailwind v4 the way shadcn/ui expects
- `lib/utils.ts` file with the `cn()` helper that shadcn/ui components import
- `${component}.build.ts` file that builds the component for production with `bun-plugin-tailwind` configured

Bun keeps a `tsconfig.json`, `components.json`, `styles/globals.css`, or `lib/utils.ts` that already exists. If Bun keeps your `${component}.css`, put `@import url("@/styles/globals.css");` at the top of that file to load the shadcn/ui theme.

Use `bun create ./MyComponent.jsx` to run code generated by LLMs like [Claude](https://claude.ai) or ChatGPT locally.

## From `npm`

```sh terminal icon="terminal"
bun create <template> [<destination>]
```

If you don't have a [local template](#from-a-local-template) with the same name, this command downloads and runs the `create-<template>` package from npm. These two commands are equivalent:

```sh terminal icon="terminal"
bun create remix
bunx create-remix
```

Refer to the `create-<template>` package's documentation for usage instructions. For `react` and `next`, Bun doesn't run a package; it only prints a message pointing to `react-app`/`vite` and `next-app`.

## From GitHub

`bun create <user>/<repo>` downloads the contents of the GitHub repo to disk.

```bash terminal icon="terminal"
bun create <user>/<repo>
bun create github.com/<user>/<repo>
```

Optionally specify a name for the destination folder. If you don't, Bun uses the repo name.

```bash terminal icon="terminal"
bun create <user>/<repo> mydir
bun create github.com/<user>/<repo> mydir
```

Bun then:

- Downloads the template
- Copies all template files into the destination folder
- Initializes a fresh Git repo. Opt out with the `--no-git` flag.
- Installs dependencies with `bun install`

<Note>By default Bun does _not overwrite_ existing files. Use the `--force` flag to overwrite them.</Note>

## From a local template

You can define custom templates on your local file system. Put them in one of the following directories:

- `$HOME/.bun-create/<name>`: global templates
- `<project root>/.bun-create/<name>`: project-specific templates

<Note>Set the `BUN_CREATE_DIR` environment variable to change the global template path.</Note>

You can also pass the absolute path of a template folder: `bun create /path/to/template mydir`.

Like a remote template, a local template is merged into an existing destination folder. Bun does _not overwrite_ existing files unless you pass `--force`, and never deletes files the template doesn't have. A symlink where the template has a file or a folder counts as an existing file: Bun never writes through it, and `--force` replaces the link itself.

To create a local template, create a directory in `$HOME/.bun-create` named after your template.

```bash
cd $HOME/.bun-create
mkdir foo
cd foo
```

Then, create a `package.json` file in that directory with the following contents:

```json package.json icon="file-json"
{
  "name": "foo"
}
```

Run `bun create foo` elsewhere on your file system to verify that Bun finds your local template.

#### Setup logic

You can specify pre- and post-install setup scripts in the `"bun-create"` section of your local template's `package.json`.

```json package.json icon="file-json"
{
  "name": "@bun-examples/simplereact",
  "version": "0.0.1",
  "main": "index.js",
  "dependencies": {
    "react": "^17.0.2",
    "react-dom": "^17.0.2"
  },
  "bun-create": {
    "preinstall": "echo 'Installing...'", // a single command
    "postinstall": ["echo 'Done!'"], // an array of commands
    "start": "bun run echo 'Hello world!'"
  }
}
```

`preinstall` and `postinstall` accept a string or an array of strings. An array of commands runs in order. Each command runs through the shell in the destination folder, like a `package.json` script; the name of a `package.json` script runs that script. If a command or `bun install` exits with a non-zero code, `bun create` stops with that code. The commands run even when the template has no dependencies. `--no-install` skips them. So do `--ignore-scripts` and what turns off lifecycle scripts for a `bun install` in the directory where you run `bun create`: `ignoreScripts = true` under `[install]` in `bunfig.toml`, or `ignore-scripts=true` in `.npmrc`. `bun install` then runs with `--ignore-scripts`. A `bunfig.toml` or `.npmrc` that is only in the destination folder does not skip the commands.

| Field         | Description                                                                                 |
| ------------- | ------------------------------------------------------------------------------------------- |
| `postinstall` | runs after installing dependencies                                                          |
| `preinstall`  | runs before installing dependencies                                                         |
| `start`       | the command Bun prints under "To get started, run:" when it finishes; defaults to `bun dev` |

After cloning a template, `bun create` removes the `"bun-create"` section from `package.json` before writing it to the destination folder.

## Reference

### CLI flags

| Flag               | Description                            |
| ------------------ | -------------------------------------- |
| `--force`          | Overwrite existing files               |
| `--no-install`     | Skip installing `node_modules` & tasks |
| `--ignore-scripts` | Skip tasks & lifecycle scripts         |
| `--no-git`         | Don't initialize a git repository      |
| `--open`           | Start & open in-browser after finish   |

### Environment variables

| Name                                      | Description                                                                                                                             |
| ----------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| `GITHUB_API_DOMAIN`                       | The GitHub domain Bun downloads from. Set this if you use GitHub Enterprise or a proxy                                                  |
| `GITHUB_TOKEN` (or `GITHUB_ACCESS_TOKEN`) | Lets `bun create` access private repositories and avoid rate limits. Bun picks `GITHUB_TOKEN` over `GITHUB_ACCESS_TOKEN` if both exist. |

<Accordion title={<span>How <code>bun create</code> works</span>}>

When you run `bun create ${template} ${destination}`, here’s what happens:

IF remote template (`elysia`, `elysia-buchta`, or `stric`; Bun hands any other npm template name to `bunx create-${template}` instead, except `react` and `next`, for which it only prints a message pointing to `react-app`/`vite` and `next-app`)

1. GET `registry.npmjs.org/@bun-examples/${template}/latest` and parse it
2. GET `registry.npmjs.org/@bun-examples/${template}/-/${template}-${latestVersion}.tgz`
3. Decompress & extract `${template}-${latestVersion}.tgz` into `${destination}`
   - If files would be overwritten, warn and exit unless you pass `--force`

IF GitHub repo

1. Download the tarball from GitHub’s API
2. Decompress & extract into `${destination}`
   - If files would be overwritten, warn and exit unless you pass `--force`

ELSE IF local template

1. Open local template folder
2. If files would be overwritten, warn and exit unless you pass `--force`
3. Copy files recursively using the fastest system calls available (on macOS, `fcopyfile`; on Linux, `copy_file_range`). Do not copy or traverse into the `node_modules` folder if it exists (this alone makes it faster than `cp`)

THEN, for remote templates, GitHub repos, and local templates alike:

4. Parse the `package.json` (again!), update `name` to be `${basename(destination)}`, remove the `bun-create` section from the `package.json` and save the updated `package.json` to disk.
5. Run `git init; git add -A .; git commit -am "Initial Commit";`
   - Skipped if `${destination}/.git` already exists.
   - Without a git `user.name` and `user.email`, the files are staged but not committed.
   - Rename `gitignore` to `.gitignore`, unless there is a `.gitignore` already (`--force` replaces one that was yours). npm strips `.gitignore` files from published packages.
   - Git finishes before the tasks and `bun install` start.
   - We tested using libgit2 if available, and it performed 3x slower in microbenchmarks
6. Run any tasks defined in `"bun-create": { "preinstall" }`
7. Run `bun install` unless you pass `--no-install` OR no dependencies are in package.json
8. Run any tasks defined in `"bun-create": { "postinstall" }`

</Accordion>
