Application Configuration

How to set up the app object in tauri.conf.json to control windows, security, global APIs, and platform behavior in Tauri v2

The app configuration object is where you define how your Tauri application behaves at runtime. It controls the windows it creates, the security rules that protect your users, which APIs are available to your frontend, and a handful of OS-specific knobs. If the top-level fields like productName and identifier describe what your app is, the app object describes what it does while it is running.

This page focuses solely on the app section of tauri.conf.json. The top-level metadata (productName, version, identifier) is covered in Product Configuration, and the build object is covered in Build Configuration.

The Structure of the App Object

A minimal app object looks like this:

src-tauri/tauri.conf.json
{
  "app": {
    "windows": [],
    "security": {
      "capabilities": [],
      "assetProtocol": {
        "enable": false,
        "scope": []
      },
      "freezePrototype": false,
      "pattern": {
        "use": "brownfield"
      }
    },
    "withGlobalTauri": false,
    "enableGTKAppId": false,
    "macOSPrivateApi": false
  }
}

Every property is optional, and Tauri falls back to sensible defaults when you omit them. The rest of this page explains what each property does and when you would change it.

Configuring Application Windows

The windows array tells Tauri which windows to create when your app launches. Each entry is a window configuration object.

src-tauri/tauri.conf.json
{
  "app": {
    "windows": [
      {
        "title": "My Tauri App",
        "width": 1024,
        "height": 720,
        "resizable": true
      }
    ]
  }
}

If the array is empty, Tauri still opens a single window with default settings. Adding entries lets you set the title, size, decorations, and behavior of each window. Window configuration is rich enough that it deserves its own chapter — see Window Configuration for everything from positioning to always-on-top behavior.

One window is the default:

If you do not include a windows array, Tauri creates a single window with the title "Tauri App" and dimensions 800×600. Adding even an empty "windows": [] behaves the same way — it falls back to the default window unless you provide at least one entry.

Security Settings

The security object controls what your frontend code is allowed to do and how Tauri isolates it. This is the most important section of the app configuration for keeping your users safe — see Security & Capabilities. Every setting has a default that errs on the side of restriction.

Capabilities

Capabilities are the modern, fine-grained permission system in Tauri v2. The capabilities array lists capability identifiers that grant access to specific APIs. You define capabilities in separate files inside src-tauri/capabilities/, and you reference them here to activate them for your app.

src-tauri/tauri.conf.json
{
  "app": {
    "security": {
      "capabilities": ["default"]
    }
  }
}

This tells Tauri to load the capability defined in src-tauri/capabilities/default.json. A typical capability file grants permissions for window manipulation, path access, and core APIs. If you omit the capabilities field, your frontend will have no Tauri API access at all — button clicks that call invoke or window.__TAURI__ will silently do nothing.

Missing capabilities breaks all API calls:

If you have frontend code that uses @tauri-apps/api but the capabilities array is empty or missing, every call will fail. The error messages can be confusing — you may see TypeError: window.__TAURI__ is undefined in the browser console. Always ensure your capability files exist and are listed here.

Content Security Policy (CSP)

The csp field accepts a Content Security Policy string that restricts where your frontend can load resources from. If you set it to null, Tauri disables CSP entirely.

src-tauri/tauri.conf.json
{
  "app": {
    "security": {
      "csp": "default-src 'self'; script-src 'self' 'unsafe-inline'"
    }
  }
}

This policy allows scripts only from the same origin and inline scripts. If you need to load images from a remote CDN, you would add img-src 'self' https://cdn.example.com. Tauri applies this CSP to the webview that hosts your frontend. When csp is null, the webview has no restrictions, which is sometimes useful during development but should be tightened before distribution.

Null CSP is not a security boundary:

Setting "csp": null means your webview can load remote scripts and make arbitrary network requests. This is acceptable during development when you are iterating on a local server, but for production you should define a policy. A null CSP also makes you responsible for sanitizing any user-generated content your app displays.

Asset Protocol Scope

The assetProtocol object controls whether Tauri’s custom asset protocol is enabled and which paths it can serve. When enabled, your frontend can reference files using the asset:// scheme.

src-tauri/tauri.conf.json
{
  "app": {
    "security": {
      "assetProtocol": {
        "enable": true,
        "scope": ["**"]
      }
    }
  }
}

The scope uses glob patterns. "**" allows access to any file inside the app’s resource directories. You can restrict it to a specific folder, for example ["images/*"], to limit what the frontend can request. If you are not serving local assets to your frontend through custom protocols, leave this disabled.

Freezing the Prototype

The freezePrototype option prevents your frontend JavaScript from modifying built-in prototypes like Object.prototype or Array.prototype. It is false by default.

src-tauri/tauri.conf.json
{
  "app": {
    "security": {
      "freezePrototype": true
    }
  }
}

Enabling this hardens your app against certain supply-chain attacks — a malicious dependency that tries to tamper with prototypes will find them frozen. The tradeoff is that some older JavaScript libraries that rely on prototype modification will break. If all your dependencies are modern, turning this on is a good security practice.

Pattern — Brownfield vs. Isolation

The pattern object tells Tauri what security model to apply to the webview. The use field accepts "brownfield" (default) or "isolation".

src-tauri/tauri.conf.json
{
  "app": {
    "security": {
      "pattern": {
        "use": "brownfield"
      }
    }
  }
}

In brownfield mode, the Tauri APIs are injected directly into the frontend’s JavaScript context. This is the easiest to work with but means your frontend runs with full access to the Tauri runtime. In isolation mode, Tauri creates a separate hidden iframe that holds the Tauri API, and your frontend communicates with it through message passing. Isolation prevents malicious frontend code (for example, from an XSS vulnerability) from directly calling native APIs. For most projects, brownfield is fine; for applications that handle sensitive data or load untrusted content, isolation is the safer choice.

Isolation is worth the effort for sensitive apps:

If your app displays user-supplied HTML or connects to third-party services, switching to "isolation" adds a meaningful layer of defense. The mental model is simple: your frontend can only ask the isolated iframe to do things, and the iframe validates every request.

Exposing the Global Tauri API

The withGlobalTauri option, when set to true, makes the Tauri API available on the global window.__TAURI__ object. When false, the API is only available through the @tauri-apps/api package’s imports.

src-tauri/tauri.conf.json
{
  "app": {
    "withGlobalTauri": false
  }
}

Leaving this false is the recommended approach. It keeps your frontend code explicit — you import what you need — and tree-shaking can remove unused API modules from your bundle. The global object is a convenience for quick prototypes or for projects that do not use a module bundler. If you are using React with Vite, stick with false and import from @tauri-apps/api as usual.

Global API can bypass capability checks:

With withGlobalTauri: true, any script running in your webview can access window.__TAURI__ directly. In combination with a weak CSP, this makes it easier for injected scripts to call native APIs. Keep it off unless you have a specific reason.

Platform-Specific Settings

Two boolean flags let you tweak behavior on Linux and macOS without touching the platform-specific configuration files.

enableGTKAppId

On Linux systems that use GTK, setting enableGTKAppId to true causes Tauri to set the GTK application ID to your app’s identifier. This is required for some desktop integrations — for instance, the system might group windows by application ID in the taskbar. If your app’s windows appear as separate applications on Linux, enabling this often resolves the issue.

src-tauri/tauri.conf.json
{
  "app": {
    "enableGTKAppId": true
  }
}

macOSPrivateApi

Setting macOSPrivateApi to true enables two macOS-specific behaviors: it allows you to use the transparent background API (so your window can have a completely see-through background), and it sets the fullScreenEnabled preference to true. This flag is necessary if you want to render windows with rounded corners that blend into the desktop or build a widget-style app. It uses private macOS APIs, which means it might break with future macOS updates and should be tested thoroughly before distribution.

src-tauri/tauri.conf.json
{
  "app": {
    "macOSPrivateApi": true
  }
}

Private APIs are unsupported by Apple:

Applications that use private macOS APIs cannot be distributed through the Mac App Store. If you plan to submit to the App Store, leave macOSPrivateApi set to false. For direct distribution outside the store, it is acceptable but still carries a risk of breakage on OS updates.

Common Configuration Mistakes

The most frequent errors around the app configuration come from mixing Tauri v1 and v2 syntax. If you are migrating an older project, watch for these specifically.

Putting package or tauri keys in the root of the config file. These were top-level keys in Tauri v1. In v2, the root keys are productName, version, identifier, build, app, bundle, and plugins. A stray "package": {} will produce an error like Additional properties are not allowed ('package' was unexpected).

Using v1 build fields like devPath and distDir instead of devUrl and frontendDist. The build configuration changed entirely in v2. If you see errors about unexpected properties on the build object, check that you are using the correct field names.

Placing bundle inside app. The bundle object is a top-level configuration, not a child of app. This mistake is common because both relate to the application output. A misplaced bundle inside app will cause a validation error.

Missing or misnamed capability files. If you list "default" in the capabilities array but there is no src-tauri/capabilities/default.json, Tauri will not warn you during build — your app will simply launch with no API access. The frontend will fail at runtime with opaque errors.

A quick validation check:

After editing tauri.conf.json, run cargo tauri dev once to confirm it parses. Tauri’s CLI validates the config file early, and you will see clear error messages if any properties are misplaced or misspelled. This catches syntax errors before you waste time debugging runtime behavior.


The app configuration is where your Tauri project goes from "it compiles" to "it behaves correctly." The defaults are safe and cover the common case, but understanding each knob lets you lock down security, fine-tune window behavior, and adapt your app to the quirks of each operating system.