A modern desktop application template using Tauri v2, React 19, and TypeScript.
Skip the boilerplate. This template gives you a production-ready Tauri + React setup with type-safe Rust-to-TypeScript bindings, pre-configured CI/CD with auto-updates, and modern tooling (React Compiler, Tailwind v4, Biome) — so you can focus on building your app, not configuring it.
- React 19 with React Compiler enabled (automatic memoization)
- Tauri v2 for secure, lightweight native desktop apps
- tauri-specta for fully typesafe Tauri command bindings
- Vite 7 for lightning-fast development
- Tailwind CSS v4 with oklch color space
- shadcn/ui components (Button, Input included)
- Biome for linting and formatting (via ultracite)
- Lefthook pre-commit hooks with commitlint
- Bun as package manager
Before you begin, ensure you have the following installed:
-
Rust - Install via rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
-
Bun - Install from bun.sh
curl -fsSL https://bun.sh/install | bash -
Platform-specific dependencies - See Tauri Prerequisites
macOS
xcode-select --install
Linux (Debian/Ubuntu)
sudo apt update sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file \ libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
Windows
Install Microsoft Visual Studio C++ Build Tools and WebView2.
-
Create a new project using one of these methods:
# Using bun create (recommended) bun create somus/create-tauri-react-app my-app cd my-app # Or using degit bunx degit somus/create-tauri-react-app my-app cd my-app bun install
-
Follow the interactive setup prompts:
- Project name
- Product name (display name)
- GitHub username or organization
- Bundle identifier (e.g.,
com.username.appname) - Author name
- Description
- AI agents to configure (multi-select from 27+ supported agents)
The setup script automatically:
- Initializes a git repository
- Configures selected AI agents via Ruler
- Installs Lefthook git hooks for pre-commit checks
-
Start development:
bun tauri dev
├── src/ # React frontend
│ ├── components/ui/ # shadcn/ui components
│ ├── lib/ # Utility functions
│ │ ├── bindings.ts # Auto-generated Tauri bindings (gitignored)
│ │ ├── logger.ts # Logging utilities
│ │ └── utils.ts # General utilities
│ ├── assets/ # Static assets
│ ├── app.tsx # Main App component
│ ├── main.tsx # React entry point
│ └── index.css # Global styles + Tailwind
│
├── src-tauri/ # Rust backend
│ ├── src/
│ │ ├── lib.rs # Tauri commands
│ │ └── main.rs # Entry point
│ ├── capabilities/ # Security capabilities
│ ├── icons/ # App icons
│ └── tauri.conf.json # Tauri configuration
│
├── scripts/ # Development scripts
│ ├── setup.ts # Project initialization
│ └── start-dev.ts # Dev server launcher
│
└── public/ # Static public assets
| Command | Description |
|---|---|
bun tauri dev |
Start Tauri in development mode |
bun tauri build |
Build production app |
bun run check |
Run linter |
bun run test |
Run tests |
bun run typecheck |
TypeScript type checking |
Run bun run to see all available scripts.
This template uses shadcn/ui with the new-york style. To add more components:
bunx shadcn@latest add [component-name]Example:
bunx shadcn@latest add dialog
bunx shadcn@latest add dropdown-menuThis template uses tauri-specta for fully typesafe Tauri commands. TypeScript bindings are auto-generated to src/lib/bindings.ts when running bun tauri dev.
Define commands in src-tauri/src/commands.rs:
#[tauri::command]
#[specta::specta] // Required for type generation
pub fn greet(name: &str) -> Result<String, String> {
Ok(format!("Hello, {}!", name))
}Call from React using the generated bindings:
import { commands } from "@/lib/bindings";
const result = await commands.greet("World");
if (result.status === "ok") {
console.log(result.data); // "Hello, World!"
} else {
console.error(result.error);
}The Result pattern ensures you always handle both success and error cases at compile time.
To add new commands, see CONTRIBUTING.md.
This template includes structured logging via tauri-plugin-log with multiple targets (console, log files, webview).
In React/TypeScript:
import { logger } from "./lib/logger";
logger.debug("Debug message");
logger.info("Info message");
logger.warn("Warning message");
logger.error("Error message");In Rust:
log::debug!("Debug message");
log::info!("Info message");
log::warn!("Warning message");
log::error!("Error message");Tauri commands use a Result pattern for explicit error handling. The generated bindings return a discriminated union:
import { commands } from "@/lib/bindings";
import { logError, logger } from "@/lib/logger";
async function callCommand() {
const result = await commands.greet(name);
if (result.status === "ok") {
// Success: result.data is fully typed
return result.data;
} else {
// Error: result.error contains the error message
logError(new Error(result.error), { command: "greet" });
return null;
}
}This ensures error handling is enforced at compile time - you cannot access the data without checking the status first.
This template uses Vitest with Testing Library:
bun run test # Run tests once
bun run test:watch # Watch mode
bun run test:ui # Open Vitest UIFor mocking Tauri commands in tests, see CONTRIBUTING.md.
For production error tracking, you can integrate Sentry for both Rust (sentry crate) and React (@sentry/react). See Sentry's Tauri guide and React guide for setup instructions.
Build the application for your current platform:
bun tauri buildThe built application will be in src-tauri/target/release/bundle/.
This template includes automated release workflows using GitHub Actions with release-please and tauri-action.
- Push conventional commits to
main(e.g.,feat: add feature,fix: bug fix) - release-please automatically creates/updates a Release PR with version bumps and changelog
- Merge the Release PR to automatically build for all platforms
- Review and publish the draft GitHub Release
Before your first release:
-
Generate an updater keypair:
bun tauri signer generate -w ~/.tauri/myapp.key -
Update
src-tauri/tauri.conf.json:- Set
plugins.updater.pubkeyto your public key contents - Update the endpoint URL with your GitHub username/repo:
"endpoints": [ "https://github.com/YOUR_USERNAME/YOUR_REPO/releases/latest/download/latest.json" ]
- Set
-
Add GitHub secrets (Settings > Secrets and variables > Actions):
TAURI_SIGNING_PRIVATE_KEY- Contents of your private key fileTAURI_SIGNING_PRIVATE_KEY_PASSWORD- Password for the key
See .ruler/RELEASING.md for detailed documentation including code signing setup.
By default, macOS code signing is disabled. Unsigned apps will show a security warning when users first open them.
To enable code signing for production releases, see the macOS Code Signing section in the releasing documentation.
The publish workflow automatically builds for macOS (ARM64 & Intel), Windows, and Linux when you merge a Release PR. For manual cross-platform builds, use Tauri Action in GitHub Actions.
- Replace the icons in
src-tauri/icons/ - Use tauri-icon to generate all required sizes:
bunx tauri icon path/to/your-icon.png
Edit CSS variables in src/index.css to customize colors. The template uses oklch color space with semantic tokens:
--primary,--secondary,--accent--muted,--destructive--background,--foreground
Dark mode is supported via the .dark class.
Install the recommended extensions when prompted, or manually install:
Configuration is included in .zed/settings.json.
Ensure Rust is up to date:
rustup updateInstall the required WebKit dependencies for your distribution. See Tauri Linux Prerequisites.
The dev server uses port 1420 by default. If it's in use, update src-tauri/tauri.conf.json:
"devUrl": "http://localhost:YOUR_PORT"And vite.config.ts:
server: { port: YOUR_PORT }MIT