Raw speed, refined desktop.
OxideDock is a Rust + Vue 3 desktop starter built on Tauri v2 β native performance, polished DX, ship-ready apps.
Starting a Tauri app from scratch means wiring up routing, state management, testing, linting, CI/CD, and release pipelines yourself. OxideDock gives you all of that out of the box so you can skip the boilerplate and start building your app from day one.
- Production-ready defaults β linting, formatting, testing, and CI all preconfigured
- Cross-platform releases β push a tag and get Linux, macOS, and Windows binaries
- One command β
make devand you're running
- Tauri v2 β lightweight, secure desktop runtime
- Vue 3 β reactive frontend with Composition API
- Vite β fast dev server and build tool
- TypeScript β type-safe frontend and configuration
- Guarded IPC β a test fails the build if Rust commands and the TypeScript layer drift apart
- Tailwind CSS v4 β utility-first styling with Vite plugin
- Vue Router β client-side routing
- Pinia β type-safe state management
- VueUse β essential Vue composables
- Vitest β fast unit and component testing
- Playwright β e2e testing against the web frontend
- ESLint β flat config with Vue 3 rules
- Biome β fast formatting and linting
- Clippy + Rustfmt β Rust linting and formatting
- cargo-audit β Rust dependency security auditing
- Lefthook β fast, parallel pre-commit hooks
- GitHub Actions β CI (lint + test + build) and release pipelines
- Makefile β unified task runner for all operations
- Rust (latest stable)
- Bun (v1.0+)
- Tauri v2 system dependencies for your OS
# Clone the template
git clone https://github.com/fridzema/oxide-dock.git
cd oxide-dock
# Verify prerequisites (Rust, Bun)
make check
# Install dependencies
make setup
# (Optional) Rename the project to your own app
make bootstrap
# Start development
make devoxidedock/
βββ .github/workflows/ # CI and release pipelines
βββ .vscode/ # Editor settings and extensions
βββ src/ # Vue 3 frontend
β βββ components/ # Reusable components
β βββ composables/ # Shared composables
β βββ layouts/ # Layout components
β βββ pages/ # Route views
β βββ router/ # Vue Router configuration
β βββ stores/ # Pinia stores
β βββ App.vue # Root component
β βββ main.ts # App entry point
β βββ style.css # Tailwind CSS imports
βββ src-tauri/ # Rust backend
β βββ src/ # Rust source code
β βββ capabilities/ # Permission capabilities
β βββ Cargo.toml # Rust dependencies
β βββ tauri.conf.json # Tauri configuration
βββ tests/
β βββ unit/ # Vitest unit tests
β βββ e2e/ # Playwright e2e tests
βββ Makefile # Task runner
βββ lefthook.yml # Git hooks
βββ README.md
| Command | Description |
|---|---|
make dev |
Start Tauri dev with hot reload |
make dev-frontend |
Start Vite dev server only |
make build |
Build production binary |
make build-debug |
Build with debug console |
| Command | Description |
|---|---|
make lint |
Run all linters (ESLint + Biome + Clippy) |
make lint-fix |
Auto-fix linting issues |
make format |
Format all files |
make format-check |
Check formatting |
| Command | Description |
|---|---|
make test |
Run all tests |
make test-unit |
Run Vitest unit tests |
make test-e2e |
Run Playwright e2e tests |
make test-watch |
Run Vitest in watch mode |
| Command | Description |
|---|---|
make rust-lint |
Run Clippy |
make rust-format |
Run Rustfmt |
make rust-audit |
Check for vulnerabilities |
make rust-test |
Run Rust tests |
| Command | Description |
|---|---|
make check |
Verify prerequisites are installed |
make setup |
Install all dependencies |
make bootstrap |
Rename project to your own app |
make ci |
Run full CI pipeline locally |
make coverage |
Run all coverage (Rust + Vue) |
make clean |
Remove build artifacts |
| Technology | Version | Purpose |
|---|---|---|
| Tauri | v2 | Desktop runtime |
| Vue | v3 | Frontend framework |
| Vite | v8 | Build tool |
| TypeScript | v6 | Type safety |
| Tailwind CSS | v4 | Styling |
| Vue Router | v5 | Routing |
| Pinia | v4 | State management |
| VueUse | latest | Composable utilities |
| Vitest | latest | Unit testing |
| Playwright | latest | E2e testing |
| ESLint | v10 | Vue linting |
| Biome | v2 | Formatting and linting |
| Lefthook | latest | Git hooks |
Commands cross the Rust/TypeScript boundary through src/shared/ipc.ts: every command gets a typed wrapper, and Rust's structured AppError gets a matching TypeScript type.
Three places have to agree for a command to work: it must be defined with #[tauri::command] in src-tauri/src/handlers.rs, registered in tauri::generate_handler! in src-tauri/src/lib.rs, and declared in CommandResults in src/shared/ipc.ts. Miss one and the failure shows up at runtime, usually as a confusing "command not found".
tests/unit/ipc-surface.test.ts reads all three and fails the build if they disagree, so that class of bug cannot reach a release.
This checks the command surface β that every command exists in all three places under the same name. It does not verify argument or payload field types; those still rely on the hand-written types in src/shared/ipc.ts matching the Rust structs.
Optional features are opt-in, not preinstalled. Each one is a recipe β an idempotent script that wires the feature into your checkout: dependency, plugin registration, capability, config.
make add-window-state # remember window size and position across restarts
make add-tray # system tray icon with a menu
make add-updater # in-app auto-updates (needs signing keys)Each recipe prints what it changed and points at its own README under recipes/. Recipes modify
your working tree and are meant to be run once and committed β review the diff like any other
change. git checkout -- is the undo.
recipes.yml applies every recipe to a clean checkout on every push and pull request, then runs
ESLint, Biome, the TypeScript type check, the Vitest suite, cargo clippy -- -D warnings and
cargo test against the result. It applies the recipe a second time and fails if that produces any
diff, so a recipe that stops being idempotent cannot land.
Pull requests deliberately skip the app build to keep the feedback loop short. recipes-nightly.yml
covers it: once a day it runs the full make ci β including bun tauri build β for every recipe on
Linux.
Runs on every push to main and on pull requests:
- Lint β ESLint, Biome check, TypeScript type check
- Rust Lint β Clippy + Rustfmt (Linux only)
- Test β Vitest unit tests, Playwright e2e (chromium), Rust tests on all platforms with coverage on Linux
- Audit β
cargo auditruns daily and on Cargo dependency changes (separate workflow) - Build β Linux smoke build (main branch only); full cross-platform build happens at release time
Releases are fully automated via release-please:
- Push conventional commits to
main(fix:,feat:,feat!:) - Release-please opens a PR bumping versions and updating
CHANGELOG.md - Merging the PR tags the release, triggering cross-platform builds
- A draft GitHub Release is created with platform binaries:
- Linux:
.deb,.AppImage - macOS:
.dmg(Intel + Apple Silicon) - Windows:
.msi,.exe
- Linux:
Check release status with make release-status.
- Update
nameinpackage.json - Update
productNameinsrc-tauri/tauri.conf.json - Replace icons in
src-tauri/icons/(usebun tauri icon /path/to/icon.png)
# Shadcn Vue
bunx shadcn-vue@latest init
# Or PrimeVue
bun add primevuebun add vue-i18nCreate locale files in src/locales/ and register the plugin in src/main.ts.
Follow the Tauri code signing guide to set up signing for macOS and Windows distribution.
Apps shipped on top of OxideDock:
- SoapDuck β a native macOS SOAP client for developers: load WSDLs, build and send SOAP requests, and inspect responses, with WS-Security and certificate signing.
Built something with OxideDock? Open a PR to add it here.
- Fork the repository
- Create a feature branch (
git checkout -b feature/your-feature) - Make your changes
- Run
make cito verify everything passes - Commit with a descriptive message
- Push and open a pull request
