# Tauri Setup Scaffolding

> Use when standing up a new Tauri v2 project from scratch or bolting Tauri onto an existing JS app — running `bun create tauri-app` (or `npm create tauri-app@latest`), picking the framework/package-manager flags, understanding the generated `src-tauri/` layout (`Cargo.toml`, `tauri.conf.json`, `capabilities/`, `icons/`, `src/lib.rs` vs `main.rs`), or invoking `tauri init` to inject Tauri into a repo that already has a Vite/Next/SvelteKit/etc. frontend.

- Skill: `stuffbucket/tauri-setup-scaffolding` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add stuffbucket/tauri-setup-scaffolding`
- Raw SKILL.md: https://api.skillmd.com/api/skills/stuffbucket/tauri-setup-scaffolding/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: stuffbucket (https://skillmd.com/u/stuffbucket)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/stuffbucket/tauri-setup-scaffolding

---


# Tauri v2 — Scaffolding

For prereq install see [[tauri-setup-prerequisites]]. For Vite specifics see [[tauri-setup-vite]].
For migrating an existing v1 app see [[tauri-setup-v1v2]].

## Fresh project (one command)

```sh
bun create tauri-app        # bun
npm create tauri-app@latest # npm
pnpm create tauri-app       # pnpm
yarn create tauri-app       # yarn
cargo create-tauri-app      # cargo only (no JS frontend)
```

You're prompted for:

- **App name** → folder name; reused as `productName`.
- **Identifier** → reverse-DNS, e.g. `com.acme.notes`. Cannot start with a digit. Used by the OS
  bundle ID. **Pick deliberately — changing it later breaks signed builds, installed-app discovery,
  deep links, and updater identity.**
- **Frontend language** → TypeScript / Rust / .NET. (TS is the common path.)
- **Package manager** → bun / npm / pnpm / yarn / deno.
- **UI template** → vanilla / Vue / Svelte / React / Solid / Angular / Preact / Yew / Leptos /
  Sycamore.
- **UI flavor** → JS or TS for JS frameworks; bundler choice (Vite is default and recommended).

Non-interactive (CI / scripts):

```sh
bun create tauri-app -- \
  --name my-app \
  --identifier com.acme.my-app \
  --template vanilla-ts \
  --manager bun
```

Flags map 1:1 to the prompts. See `bun create tauri-app -- --help` for the full list.

## Adding Tauri to an existing frontend

Run from the repo root. Tauri lives in `src-tauri/`; your existing `src/` (or wherever) stays put.

```sh
bunx @tauri-apps/cli@latest init
# you'll be asked for: app name, window title, frontend dist dir,
# dev-server URL, beforeDev / beforeBuild commands.
```

Answers you almost always want for a Vite app:

- **Frontend dist** → `../dist`
- **Dev URL** → `http://localhost:1420`
- **beforeDevCommand** → `bun run dev`
- **beforeBuildCommand** → `bun run build`

These land verbatim in `tauri.conf.json` under `build.*`.

Add the JS API + plugins you need:

```sh
bun add @tauri-apps/api
bun add @tauri-apps/plugin-opener   # etc.
```

## Generated layout (annotated)

```text
my-app/
├─ src/                     # your frontend (Vite/Next/SvelteKit/...)
├─ src-tauri/
│  ├─ Cargo.toml            # Rust deps. tauri = "2", tauri-build = "2".
│  ├─ tauri.conf.json       # ALL Tauri config. See `bun run tauri info`.
│  ├─ build.rs              # `tauri_build::build()` — runs at compile time
│  │                        #   to generate command/permission glue.
│  ├─ src/
│  │  ├─ main.rs            # Thin entry. Calls `my_app_lib::run()`.
│  │  └─ lib.rs             # ALL of your Rust app code lives here.
│  │                        #   Splitting like this enables mobile builds
│  │                        #   (iOS/Android consume the lib, not main).
│  ├─ capabilities/
│  │  └─ default.json       # ACL bundle granted to `main` window.
│  │                        #   Review and tighten before release.
│  ├─ icons/                # PNG + ICO + ICNS, generated by `tauri icon`.
│  ├─ gen/                  # Auto-generated. DO NOT commit (it's gitignored).
│  └─ target/               # Cargo build dir. DO NOT commit.
├─ package.json             # Frontend deps + scripts.
├─ index.html               # Vite entry (or framework equivalent).
└─ vite.config.ts           # See [[tauri-setup-vite]].
```

### Why `main.rs` and `lib.rs` are split

Mobile (iOS + Android) compile Tauri as a **static library** linked into a platform-native binary.
To make the same Rust code build on desktop and mobile, the v2 scaffolder puts everything in
`lib.rs` and reduces `main.rs` to:

```rust
fn main() {
    my_app_lib::run();
}
```

If you add a new module, put it under `src-tauri/src/` and `mod` it from `lib.rs`, not `main.rs`.
Don't fold logic back into `main.rs` — you'll lose mobile builds.

### Cargo.toml essentials

```toml
[package]
name = "my-app"
version = "0.1.0"
edition = "2021"

[lib]
name = "my_app_lib"     # <-- referenced by main.rs
crate-type = ["staticlib", "cdylib", "rlib"]

[build-dependencies]
tauri-build = { version = "2", features = [] }

[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
```

Add plugins as `tauri-plugin-<name> = "2"` and register them in `lib.rs::run()` with
`.plugin(tauri_plugin_<name>::init())`. See [[tauri-plugins]].

## Regenerate icons

`bunx @tauri-apps/cli icon path/to/source.png` rebuilds every icon size + format
into `src-tauri/icons/`. Source should be ≥1024×1024 with transparent
background. Do this before first release — the default Tauri logo will get a
PR rejected.

## Initial sanity check

```sh
bun install
bun run tauri info     # prints versions of every Tauri-related piece
bun run tauri dev      # builds Rust, runs frontend dev server, opens window
```

If `tauri dev` hangs on "Building...", it's compiling Rust (3–8 min first time). Subsequent runs are
seconds.

## Common scaffolding pitfalls

- **Identifier with a digit prefix** — `tauri build` refuses. Rename before any signed build ships.
- **Bundle identifier collision with another app on the same machine** — installs overwrite. Use a
  unique reverse-DNS you control.
- **`tauri init` answered with absolute paths** — config wants paths relative to `src-tauri/`. Use
  `../dist`, not `/Users/.../dist`.
- **Commit of `src-tauri/gen/` or `src-tauri/target/`** — bloats the repo. Verify `.gitignore`
  excludes both (the scaffolder does this for you; if you copied a partial layout, double-check).
- **Mixing `bun create tauri-app` template into an existing repo** — runs `git init` and trashes
  your history if you point it at a non-empty dir. Use `tauri init` instead.

## Templates

- `templates/tauri.conf.minimal.json` — minimal valid v2 config with placeholders.
- `templates/Cargo.toml` — minimal `src-tauri/Cargo.toml` with mobile-ready `[lib]`.
- `templates/lib.rs` — minimal `run()` with one plugin + one command registered.

