Introduction to tauri.conf.json
The purpose, structure, and core concepts behind the main Tauri configuration file, including format options, platform-specific merging, and validation.
The tauri.conf.json file is the single source of truth that tells Tauri how to assemble and run your application. It sits inside the src-tauri directory — see where it lives in the project — and controls everything from the window title to which frontend dev server to connect to, how the final bundle gets packaged, and what permissions your app has. If you have worked with package.json or Cargo.toml, think of this as the orchestration manifest that bridges the Rust backend and your React + Vite frontend.
Where the File Lives
Every Tauri project generated with create-tauri-app places the configuration file at a fixed path relative to the project root:
src-tauri/tauri.conf.json
The src-tauri directory is the Rust workspace for your app’s backend. The Tauri CLI reads this file during tauri dev and tauri build to understand your project’s shape. You never need to move it, and you should never delete it—without it, Tauri cannot start.
JSON Schema Support:
Adding a "$schema" field at the top of the file points to the official JSON schema and gives you autocompletion, inline documentation, and validation inside editors like VS Code. For Tauri v2, the schema path is typically "../node_modules/@tauri-apps/cli/schema.json" when installed via npm, or you can reference the canonical URL.
Configuration Hierarchy
The configuration object is organized into a handful of top-level keys. Understanding what each one does is the first step before customizing anything deeper.
| Key | Purpose |
|---|---|
productName | The human-readable name of your app, used in window titles and bundle metadata. |
version | A semver version string, or a path to a package.json from which the version will be read. |
identifier | A unique reverse-domain identifier (e.g. com.mycompany.myapp). This is mandatory and must be unique per application. |
build | Controls how Tauri locates and builds your frontend: the dev server URL, the directory of built static files, and any commands to run before dev or build. |
app | Runtime behavior: window definitions, security settings (CSP, capabilities), tray icons, and global Tauri API access. |
bundle | Packaging configuration: which installers to produce, icons, file associations, and platform-specific signing settings. |
plugins | Configuration for Tauri plugins such as the updater, deep-link, file system, and shell. Each plugin’s options live here. |
The only field that is strictly required for every project is identifier. If you omit it, the CLI will refuse to build. All other top-level fields have sensible defaults or can be empty objects, but you will almost always need to configure build and at least one window in app.windows.
Missing Identifier:
Tauri v2 will throw an error during tauri build if identifier is missing. This field is embedded in system-level metadata like macOS bundle IDs and Windows app user model IDs, and changing it later can break OS integrations. Choose something unique and stable from the start.
Here is a minimal, working configuration for a React + Vite project that you could run immediately:
{
"productName": "my-tauri-app",
"version": "0.1.0",
"identifier": "com.example.my-tauri-app",
"build": {
"beforeDevCommand": "npm run dev",
"devUrl": "http://localhost:5173",
"frontendDist": "../dist"
},
"app": {
"windows": [
{
"title": "My Tauri 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"
]
}
}
The build section links Tauri’s development and production workflows to Vite’s default port and output folder. When you run tauri dev, the CLI first executes npm run dev (which starts the Vite dev server on localhost:5173), then opens a webview pointing to that address. When you run tauri build, it runs npm run build, collects the static files from ../dist (relative to src-tauri), and bundles them into the final application binary. The app.windows array defines a single window with a custom title. The bundle object marks the app as ready to package, requests all platform targets, and specifies the icon set that the bundler will use.
First Launch:
If after running npm run tauri dev your app window appears with the title you set and the Vite dev server works, your configuration is structurally correct. The Tauri CLI validates the file against the official schema before starting, so a clean launch confirms you have no top-level structure issues.
Supported File Formats
JSON is the default, but Tauri v2 can also read TOML and JSON5 if you enable the appropriate Cargo features. The underlying configuration model is identical; only the syntax changes.
{
"productName": "my-app",
"version": "0.1.0",
"build": {
"devUrl": "http://localhost:5173",
"frontendDist": "../dist"
}
}
JSON5 support works similarly with a config-json5 feature flag. TOML and JSON5 both allow comments, which is useful for documenting non-obvious choices directly in the file. Regardless of the format, Tauri will deserialize the same configuration struct, so no feature works differently across formats.
Platform-Specific Configuration Merging
You can provide overrides for Linux, Windows, macOS, Android, or iOS by creating files named tauri.{platform}.conf.json next to your main config. Tauri merges them using the JSON Merge Patch specification (RFC 7396). This allows you to, for example, set a different window size on macOS without duplicating the entire configuration.
Imagine your base config declares a window width of 800 pixels. You want the macOS version to open at 1024 pixels instead. You would create tauri.macos.conf.json:
{
"app": {
"windows": [
{
"width": 1024
}
]
}
}
When you run tauri build, Tauri resolves the configuration by applying the macOS patch on top of tauri.conf.json. The resulting merged object will have width 1024 on macOS and 800 everywhere else. The merge is deep, so you can override plugin settings, bundle resources, or the app identifier per platform without repeating the unchanged sections.
Merge Replaces Entire Values:
RFC 7396 merging replaces entire objects and arrays. If your base config has "resources": ["./shared-assets"] and your Linux override sets "resources": ["./linux-assets"], the final resources array will contain only "./linux-assets". It will not combine the two arrays. If you need both, you must list all desired entries in the platform-specific file.
Extending Configuration at Build Time
The --config flag on tauri dev and tauri build lets you supply additional JSON to be merged into the final configuration at runtime. This is ideal for creating beta or nightly builds that need a different product name, identifier, or bundle settings without maintaining separate config files.
You can pass the extension as a raw JSON string or as a file path:
npm run tauri build -- --config src-tauri/tauri.beta.conf.json
The file tauri.beta.conf.json might contain only the fields you want to override:
{
"productName": "My App Beta",
"identifier": "com.example.myapp.beta"
}
This produces a completely separate application identity, allowing you to install the beta version alongside the stable release. The merge follows the same RFC 7396 rules as platform-specific overrides.
JSON Schema Validation
Tauri ships with a JSON schema that defines every allowed field, their types, and default values. When you set the "$schema" property in your config file, your editor uses that schema to provide real-time validation, autocomplete suggestions, and documentation popups. The CLI also validates against this schema before executing any command, catching errors like outdated field names before they cause a build failure.
For npm-managed projects, the schema is typically located at:
"$schema": "../node_modules/@tauri-apps/cli/schema.json"
You can also use the raw GitHub-hosted URL for the version you are targeting, but the local path is faster and works offline.
Where Other Configuration Files Fit
tauri.conf.json is not the only configuration file in a Tauri project. It lives alongside Cargo.toml (Rust dependencies and metadata) and capability files in src-tauri/capabilities/ that define fine-grained permissions. The version specified in the Tauri config can be a path like "../package.json", which tells Tauri to read the version from your frontend’s package.json instead of duplicating it. Similarly, the app name can be pulled from your Cargo.toml package name if productName is omitted, but explicitly setting it is clearer.
Capability files are separate because they govern what your frontend JavaScript can access—like reading files, opening shell commands, or showing dialog windows. The app.security.capabilities array in tauri.conf.json references these capability files, but the permission definitions themselves live outside the main config.
Common Configuration Mistakes
The most frequent errors come from migrating a v1 config to v2 or copying examples from outdated tutorials. Tauri v2 renamed several fields:
| v1 Field | v2 Equivalent |
|---|---|
build.devPath | build.devUrl |
build.distDir | build.frontendDist |
tauri.bundle.identifier | Top-level identifier |
tauri.allowlist | Capability-based permissions |
If you see an error like Additional properties are not allowed ('devPath', 'distDir' were unexpected), you are using v1 field names in a v2 project. The fix is to rename them to their v2 equivalents and ensure @tauri-apps/cli is updated to the latest v2 version.
Stale CLI Version:
Running an old @tauri-apps/cli version (e.g., a v2 beta or v1) while your config follows the latest v2 structure will produce misleading validation errors. Run npx tauri --version to verify you have a recent v2 release. If not, update with npm install -D @tauri-apps/cli@latest.
Another subtle mistake is placing bundle or plugin settings inside the app object. The top-level structure is fixed; bundle, plugins, build, and app must all be siblings. Nesting them incorrectly will cause the schema validation to fail with "Additional properties are not allowed" messages.
Finally, forgetting to set the frontendDist path correctly is a silent build killer. The path is relative to the src-tauri directory, not the project root. If your Vite config outputs to a folder named dist at the project root, then "frontendDist": "../dist" is correct. If you output to build, adjust accordingly.
Summary
You now have a mental map of the tauri.conf.json landscape: its required and optional top-level fields, the ways you can format it, how platform-specific overrides merge, and what validation looks like. The biggest insight to carry forward is that the configuration is not a static file but a layered system—base config, platform overrides, and CLI extensions combine to form the final settings that Tauri uses.