assetProtocol must be enabled to serve files to WebView
To serve files from disk into the WebView through the asset custom protocol, you must set enable to true and define a scope in app.security.assetProtocol in tauri.conf.json. Paths resolved at runtime must match that scope, or the WebView will refuse the load with an error such as 'asset protocol not configured to allow the path'.
assetProtocol scope uses FsScope type
assetProtocol.scope uses the same FsScope type as filesystem-related configuration elsewhere. It can be either a JSON array of allowed glob patterns, or a JSON object with allow, optional deny, and optional requireLiteralLeadingDot fields.
Asset protocol scope supports base directory variables
Patterns in assetProtocol.scope may start with base directory variables such as $HOME, $CACHE, $APPCACHE, $APPDATA, and $RESOURCE. These variables expand to the appropriate paths on each platform.
Absolute paths must match scope patterns on asset protocol
Paths resolved when loading assets are usually absolute (on Linux, often under /home/...). A pattern like ['*/**'] typically does not match those paths because it does not line up with a leading / or a base-directory variable. Prefer patterns such as $HOME/**/* or /home/username/**/* that mirror the resolved path.
Array form of assetProtocol scope
Example of array form for assetProtocol scope with only an allow list: {"app": {"security": {"assetProtocol": {"enable": true, "scope": ["$APPCACHE/**/*", "$RESOURCE/**/*"]}}}}. With array form you cannot set requireLiteralLeadingDot; use object form for that.
Object form of assetProtocol scope with allow and deny
Example of object form with allow and deny rules: {"app": {"security": {"assetProtocol": {"enable": true, "scope": {"allow": ["$APPCACHE/**/*"], "deny": ["$APPCACHE/**/secrets/**"]}}}}}. The deny takes precedence over allow when both match.
Unix requireLiteralLeadingDot default behavior
On Unix, requireLiteralLeadingDot defaults to true. Then wildcard tokens such as *, ?, **, and [...] do not match a path component that starts with . (dotfiles and dot-directories such as .cache or .ssh). A pattern like $HOME/** can allow /home/user/Documents/file.png but not /home/user/.cache/myapp/preview.png, because .cache is a dot-prefixed component. A pattern that names the segment literally (for example $HOME/.cache/myapp/**) does match.
Set requireLiteralLeadingDot false to match dotfiles with globs
To allow dot-prefixed components under a broad glob pattern in assetProtocol scope, set requireLiteralLeadingDot to false on the object scope form. Example: {"app": {"security": {"assetProtocol": {"enable": true, "scope": {"requireLiteralLeadingDot": false, "allow": ["$HOME/**/*"]}}}}}. This widens what the WebView can load; review carefully.
Prefer **/* over bare ** in asset protocol patterns
For globs that should match files under a tree in assetProtocol scope, prefer **/* (and variants like $DIR/**/*) rather than bare **. Bare ** is easy to misuse when you intend 'everything under this directory recursively.' This is consistent with other Tauri path examples.
Highly permissive assetProtocol configuration example
A maintainer-suggested highly permissive configuration for broadest access with dot-prefixed segments: {"app": {"security": {"assetProtocol": {"enable": true, "scope": {"requireLiteralLeadingDot": false, "allow": ["**/*"]}}}}}. This is not a default recommendation and increases exposure of hidden and sensitive files.
Asset protocol scope recommendation: prefer narrow directories
Prefer narrow directories like $APPCACHE, $RESOURCE, or a single app subfolder under $HOME instead of broad $HOME/**/* or **/* unless you have a strong reason and understand the security tradeoffs.
Static vs dynamic asset protocol scope
Entries in tauri.conf.json describe static allow/deny patterns for assetProtocol. They do not replace runtime workflows where the user picks arbitrary folders or files (for example with the dialog plugin). Those paths may need to be persisted across restarts using the persisted-scope plugin.
Use persisted-scope plugin to allow dynamic asset protocol paths
To persist asset/protocol-related scope with the persisted-scope plugin, enable its protocol-asset Cargo feature in src-tauri/Cargo.toml: tauri-plugin-persisted-scope = { version = "2", features = ["protocol-asset"] }. Register tauri_plugin_fs before tauri_plugin_persisted_scope as described in the plugin guide.
Asset protocol troubleshooting: dot-directory paths blocked on Unix
If asset protocol works for normal folders but not under .cache or .config directories, on Unix the default requireLiteralLeadingDot behavior is the cause. Solution: use a literal .segment in the pattern, or set requireLiteralLeadingDot to false in the object scope form. See tauri#13788 for concrete examples.
Asset protocol troubleshooting: broad ** pattern never matches
If a scope like ['*/**'] seems to never match on Linux, resolved paths are absolute. Use $... variables, a leading /, or another pattern that matches the real path instead of relative globs.
Asset protocol troubleshooting: user-picked folder still blocked after restart
If a user picked a folder at runtime and it is still blocked after restart, you may need the persisted-scope plugin with the protocol-asset feature, not only tauri.conf.json entries.
Asset protocol scope configuration moved
The tauri.allowlist.protocol.assetScope configuration moved to app.security.assetProtocol.scope.
Asset scope configuration moved in Tauri 2.0
In Tauri 1.0, asset scope was configured at 'tauri > allowlist > protocol > assetScope'. In Tauri 2.0, it has been moved to 'tauri > security > assetProtocol > scope'.
$APPLOCALDATA/** glob pattern for recursive folder access
The pattern $APPLOCALDATA/** in a scope allows recursive access to the complete $APPLOCALDATA folder, including all subdirectories and files.