What is Tauri Configuration?
Learn how Tauri configuration files act as the central blueprint for your desktop app, coordinating the frontend, backend, build process, and runtime behavior.
The Role of Configuration in a Tauri Project
A Tauri project marries two separate ecosystems: a web frontend (React, Vite, HTML/CSS/JS) and a Rust backend. The configuration file — usually tauri.conf.json — is the document that tells Tauri how these two halves fit together. It specifies where your built frontend lives, what commands to run before starting development or building, what your application is called, how its windows should look, and what native capabilities the webview is allowed to use. Without it, the Tauri CLI has no instructions for turning your code into a running application.
Not the Only Config File:
A full Tauri project also uses Cargo.toml for Rust dependencies and package.json for Node.js scripts. However, tauri.conf.json is the primary file that the Tauri CLI and runtime read to orchestrate the entire app. The other files complement it, but this one is the control center.
For a React + Vite frontend, this configuration file is where you connect Vite’s dev server (typically on port 5173) to Tauri’s development workflow and point the build process to the dist folder Vite generates. When you create a project with npm create tauri-app, a default configuration is scaffolded that already wires up these connections — you can tweak it later as your app grows.
Why Configuration Matters
Tauri treats security and explicitness as first-class concerns. Unlike frameworks that bury defaults in boilerplate, Tauri requires you to declare what your app can do. The configuration file is where you grant permissions, set window sizes, name your app, and define its bundle identifier. This explicit approach means:
- You always know exactly what your app is allowed to access — file system, network endpoints, system tray, and so on.
- The build process can be automated reliably because the commands for development and production are spelled out in one place.
- Another developer can pick up your project and run it without guessing hidden settings.
If the configuration is wrong, the app might not start, windows might appear blank, or platform-specific builds could fail. Understanding the structure at a high level pays off before you dive into fine‑tuning every option.
The Configuration Landscape
A Tauri v2 project contains several configuration points, but this chapter focuses on the main Tauri configuration (tauri.conf.json) and closely related files like capability definitions and platform‑specific overrides. Here is an overview of the pieces you will encounter:
src-tauri/tauri.conf.json— The central configuration file that defines product metadata, build commands, window properties, bundle settings, plugin configurations, and security policies.src-tauri/capabilities/— A directory containing capability files (JSON or TOML) that map sets of permissions to specific windows. The main config references these capabilities.src-tauri/Cargo.toml— Rust’s manifest that declares your Rust dependencies (liketauriandtauri-build) and features that enable optional config formats (JSON5 or TOML).package.json— The Node‑side descriptor, used to manage frontend dependencies and define scripts that the Tauri config calls (e.g.,npm run dev,npm run build).
The Tauri configuration file is the hub that connects these pieces: it references the frontend build output, triggers the Node scripts via beforeDevCommand/beforeBuildCommand, and links capability files for runtime permissions.
Runtime vs Build‑Time Configuration
To understand the configuration better, split the settings into two categories based on when they take effect.
Build‑time settings are used by the Tauri CLI during development and packaging. They include:
build.devUrl— the URL of your Vite dev server while developing.build.beforeDevCommand— the command that starts that dev server (e.g.,npm run dev).build.beforeBuildCommand— the command that builds your frontend before bundling (e.g.,npm run build).build.frontendDist— the path to the folder containing the built frontend assets.
These values never become part of the final executable; they are only needed while compiling and assembling the application.
Runtime settings are embedded into the final binary and control what happens when the user runs your app. Examples:
app.windows— array of window definitions with titles, sizes, and behaviors.app.security— Content Security Policy and other security constraints.app.trayIcon— system tray configuration (if any).plugins— plugin‑specific settings that the Rust core reads at startup.
The separation exists because the CLI and the compiled app need different information. The CLI needs to know how to gather assets; the compiled app needs to know how to present itself. The configuration file unifies them in one readable document so you do not have to hunt across multiple places.
You Are on the Right Track:
If you can look at a tauri.conf.json and mentally separate the build section (used during development/building) from the app and bundle sections (used at runtime or packaging time), you already understand the core structure. Everything else is just detail.
A Tour of a Minimal Configuration File
Before exploring every option, here is a realistic tauri.conf.json for a React + Vite project. It contains exactly what you need to get a window on screen and connect the frontend.
{
"productName": "my-app",
"version": "0.1.0",
"identifier": "com.mycompany.myapp",
"build": {
"beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:5173",
"beforeBuildCommand": "npm run build",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"label": "main",
"title": "My App",
"width": 800,
"height": 600
}
],
"security": {
"csp": null
}
},
"bundle": {
"active": true,
"targets": "all",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}
Walking through each section:
productName,version, andidentifierform the app’s identity. The identifier must be in reverse‑domain notation and unique per application — it is used for bundle IDs and data directories.buildties in Vite.beforeDevCommandstarts the Vite dev server when you runtauri dev.devUrltells Tauri where to load the frontend during development.beforeBuildCommandruns Vite’s production build before Tauri bundles the app.frontendDistpoints to the output folder (../distrelative tosrc-tauri).app.windowsdefines the main window. Here it is given a label"main", a title, and a default size.app.security.cspcontrols Content Security Policy;nulldisables it for simplicity, but in production you would set appropriate directives.bundleactivates bundling and specifies icon files for various platforms.
This file is enough to build a functional Tauri app. As you progress through this chapter, you will learn to customize each section in detail.
Configuration File Formats
By default, Tauri uses JSON. If you prefer comments or a more concise syntax, you can switch to JSON5 or TOML. The configuration structure stays identical across formats, but the file syntax and naming conventions differ.
To use an alternative format, add the corresponding feature flag to both tauri and tauri-build dependencies in src-tauri/Cargo.toml:
[build-dependencies]
tauri-build = { version = "2", features = ["config-json5"] } # or "config-toml"
[dependencies]
tauri = { version = "2", features = ["config-json5"] }
After changing these features, rename your config file appropriately:
- JSON5:
tauri.conf.jsonortauri.conf.json5 - TOML:
Tauri.toml(note the capital T)
The examples below show the same configuration in all three formats.
{
"productName": "my-app",
"version": "0.1.0",
"identifier": "com.example.app",
"build": {
"beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:5173",
"frontendDist": "../dist"
},
"app": {
"windows": [{ "title": "My App" }]
}
}
Feature Flags Are Mutually Exclusive:
Do not enable both config-json5 and config-toml features at the same time. Tauri will reject the build. Pick one format and stick with it.
JSON5 allows trailing commas and comments, which can make the file more maintainable for humans. TOML uses kebab-case for keys (before-dev-command instead of beforeDevCommand), which some developers find more natural for configuration files. The choice is purely aesthetic; the app behavior is identical.
Platform-Specific Configuration Overrides
Tauri reads additional platform‑specific files and merges them with the base configuration. This lets you customize settings for Linux, Windows, macOS, Android, or iOS without duplicating the entire file.
The files follow this naming pattern:
tauri.linux.conf.json/Tauri.linux.tomltauri.windows.conf.json/Tauri.windows.tomltauri.macos.conf.json/Tauri.macos.tomltauri.android.conf.json/Tauri.android.tomltauri.ios.conf.json/Tauri.ios.toml
The merging uses the JSON Merge Patch (RFC 7396) specification. You only need to include the keys you want to override; any missing keys fall back to the base file. Arrays are replaced entirely, not concatenated, so be careful when overriding lists like app.windows or bundle.icon.
Array Replacement in Merges:
If your base config has "icon": ["icons/app.png"] and your platform‑specific file has "icon": ["icons/linux-app.png"], the final merged icon array will be only the Linux icon — the original app.png is lost. If you want to add platform‑specific icons without losing the defaults, you must repeat the common entries in the override file.
Platform‑specific files are invaluable when you need different window sizes for macOS vs Windows, or when you want to set a different application name for Android builds. They keep your base config clean and avoid cluttering tauri.conf.json with platform conditionals.
Extending the Configuration at Build Time
The Tauri CLI also supports overriding configuration values on the fly using the --config flag. This flag accepts either a raw JSON string or a path to a JSON file, and the provided data is merged on top of the final resolved configuration (after platform‑specific merges).
This is useful for creating variants of your app — for example, a beta version with a different name and identifier — without maintaining separate config files permanently.
Here is a file src-tauri/tauri.beta.conf.json that redefines only the product name and identifier:
{
"productName": "My App Beta",
"identifier": "com.mycompany.myappbeta"
}
Then build the beta version with:
npm run tauri build -- --config src-tauri/tauri.beta.conf.json
The same mechanism lets you inject environment‑specific settings during CI/CD pipelines — an API endpoint, a feature flag, or a version suffix — all without modifying the base configuration.
The Configuration Workflow
When you work with Tauri configuration, the process follows a predictable rhythm. Here is the typical lifecycle from first setup to a refined config.
Step 1: Create the Project with the Default Config
Running npm create tauri-app scaffolds a tauri.conf.json already tailored to your chosen frontend (React + Vite). It sets the correct devUrl, beforeDevCommand, and frontendDist paths. At this point, the app compiles and runs with default window settings.
Step 2: Personalize the Metadata
Open src-tauri/tauri.conf.json and update productName, version, and identifier to match your application. The identifier is critical — choose a unique reverse‑domain string (e.g., com.yourcompany.yourapp) and never change it after the first release, or you risk breaking data storage paths.
Step 3: Adjust Build Settings for Your Workflow
Verify that beforeDevCommand and beforeBuildCommand match your package manager (npm, yarn, pnpm). If you changed Vite’s port, update devUrl accordingly. Ensure frontendDist points to the correct output directory (usually ../dist for Vite).
Step 4: Define Windows and Basic Behavior
In app.windows, set window titles, default sizes, and enable or disable features like resizing, fullscreen, or decorations. For now, a single window with a label of "main" is enough.
Step 5: Run `tauri dev` and Verify
Start the development server with npm run tauri dev. Your React app should appear inside a native window. If it does not, double‑check the devUrl and ensure the Vite server is reachable at that address. The terminal output from tauri dev will show exactly which config is loaded.
Step 6: Iterate and Extend
As you add features (system tray, file system access, updater), you will edit the configuration to enable plugins, add capability permissions, and fine‑tune bundle settings. Always test with tauri build --debug before a full release to catch configuration errors early.
Do Not Forget `frontendDist`:
A surprisingly common mistake is to leave frontendDist pointing to a non‑existent directory. When you run tauri build, Tauri will embed an empty directory, and your app will show a blank white screen. Always verify that the path is correct and that Vite has successfully generated the files there.
Common Misconceptions and Mistakes
Beyond the blank‑screen issue, here are a few pitfalls that new Tauri developers hit:
- Mixing up
devUrlandfrontendDist.devUrlis only used duringtauri devand must point to a live dev server.frontendDistis the static folder used for production builds. They serve completely different purposes. - Forgetting to set the
identifier. The build will fail with a cryptic error because bundle IDs on macOS/iOS and package names on Android require a valid identifier. - Assuming the config is only for the Rust side. The configuration also affects the frontend indirectly: capability files and security settings control which Tauri APIs are accessible from JavaScript. If a plugin is not working, check that you added its permission to the capability file referenced in
tauri.conf.json. - Editing the config without restarting
tauri dev. Some runtime settings are only read at startup. Window size and title changes may require a full restart of the dev process, not just a hot reload.
Version Sync Warning:
The version field in tauri.conf.json and the version in src-tauri/Cargo.toml should match, or you can set the Tauri config’s version to a path like "../package.json" to keep them in sync. Mismatched versions can confuse update checks and bundle metadata.
What Comes Next
You now know what Tauri configuration is, why it sits at the center of your project, and how it connects the frontend and backend. The next sections break down the configuration file structure in detail:
- Configuration Files — A closer look at the individual files (
tauri.conf.json,Cargo.toml,package.json) and how they interact. - tauri.conf.json — A deep dive into the top‑level sections: product, build, app, bundle, and plugins.
- Window Configuration — Controlling window size, position, appearance, and platform‑specific behavior.
- Bundle Configuration — Packaging your app for distribution with icons, installers, and platform‑specific options.
- Resources, Sidecars, and Assets — Embedding additional files and binaries alongside your app.
- Security & Capabilities — Defining the permissions system that keeps your app safe.
- Configuration Best Practices — Organizing, securing, and optimizing your configuration for real‑world apps.
Turn the page to start exploring each section, beginning with a detailed breakdown of the configuration files themselves.