# Extension points — tauri-apps/tauri

> Canonical page: https://codevetter.com/unpack/tauri/extension-points

# Extension points — tauri-apps/tauri

Scanned commit 745b9a48aeb6e7f48d70adf3d043e6203de5bac6 (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

Tauri is designed for extension at several layers: Rust commands registered through `generate_handler!`/`#[command]`, full plugins implementing the `Plugin` trait (with the companion `tauri-plugin` build crate emitting permissions, global API scripts and mobile glue), custom URI scheme protocols, Builder lifecycle hooks (setup, page-load, menu/tray/window/webview events, channel interceptor), custom `Assets` providers, a swappable `Runtime` trait, capability/permission JSON+TOML files composing ACLs, `State` injection for shared data, and JS-side extension via `Channel`, `Resource` and the `__TAURI_TO_IPC_KEY__` serialization hook.
- The `Plugin<R>` trait is the primary extension interface: implementors provide `name()` plus optional `initialize`, `initialization_script`/`initialization_script_2`, `window_created`, `webview_created`, `on_navigation` (veto navigation), `on_page_load`, `on_event` and a cleanup hook. — [crates/tauri/src/plugin.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/plugin.rs)
- Plugins are attached via `Builder::plugin`/`AppHandle::plugin`/`plugin_boxed` and stored in `PluginStore`; commands addressed as `plugin:<name>|<command>` are routed to the plugin's invoke handler by `run_plugin_invoke_handler`. — [crates/tauri/src/app.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/app.rs) [crates/tauri/src/webview/mod.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/webview/mod.rs)
- App commands are registered with `#[tauri::command]` fns collected by `tauri::generate_handler![...]` into the `InvokeHandler` passed to `Builder::invoke_handler` — the command table macro lives in tauri-macros/src/command (wrapper.rs + handler.rs). — [crates/tauri-macros/src/command/wrapper.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-macros/src/command/wrapper.rs) [crates/tauri-macros/src/command/handler.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-macros/src/command/handler.rs) [examples/api/src-tauri/src/cmd.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/examples/api/src-tauri/src/cmd.rs)
- Plugin build-time integration: `tauri_plugin::build::Builder::new(commands)` accepts `global_scope_schema`, `global_api_script_path`, `android_path`, `ios_path` and emits artifacts (permissions, api scripts, mobile code) consumed by tauri-build/context_codegen via OUT_DIR files. — [crates/tauri-plugin/src/build/mod.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-plugin/src/build/mod.rs) [crates/tauri-codegen/src/context.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-codegen/src/context.rs)
- Custom URI scheme protocols plug in through `UriSchemeProtocol` handlers registered on the WebviewManager (`register_uri_scheme_protocol`), with `UriSchemeContext`/`UriSchemeResponder` exposed for async responses. — [crates/tauri/src/manager/webview.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/manager/webview.rs) [crates/tauri/src/app.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/app.rs)
- Builder hooks are extension points: `setup`, `on_page_load`, `on_menu_event`, `on_tray_icon_event`, `on_window_event`, `on_webview_event`, `invoke_system` and `channel_interceptor` all accept user closures stored on the Builder struct. — [crates/tauri/src/app.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/app.rs)
- The `Assets<R>` trait abstracts asset retrieval (`get`, `iter`, `csp_hashes`); ContextData accepts a custom `assets` Expr so embedders can replace EmbeddedAssets entirely. — [crates/tauri/src/lib.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/lib.rs) [crates/tauri-codegen/src/context.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-codegen/src/context.rs)
- The `Runtime`/`RuntimeHandle` traits (wrapping tauri-runtime) let apps swap the webview backend; `Builder` is generic over `R: Runtime` and `wry` is just the default via `default_runtime` macro. — [crates/tauri/src/lib.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/lib.rs) [crates/tauri-runtime/src/lib.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-runtime/src/lib.rs)
- ACL extension: apps declare capabilities JSON (and plugin permission TOML via `define_permissions`) that `get_capabilities` + `Resolved::resolve` merge at codegen time; `dynamic-acl` additionally permits runtime `add_capability`. — [crates/tauri-codegen/src/context.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-codegen/src/context.rs) [crates/tauri-utils/src/acl/capability.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-utils/src/acl/capability.rs) [crates/tauri-utils/src/acl/resolved.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-utils/src/acl/resolved.rs)
- Shared state plugs into commands through `app.manage(...)` (StateManager) and the `State<'_, T>` command arg extractor; resources use `ResourceTable` with rid handles exposed to JS as the `Resource` class. — [crates/tauri/src/state.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/state.rs) [crates/tauri/src/resources/mod.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/src/resources/mod.rs) [packages/api/src/core.ts](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/packages/api/src/core.ts)
- The CLI itself is extensible by adding a `Commands` variant + module in crates/tauri-cli/src, and `tauri plugin init/new` scaffolds new plugins from crates/tauri-cli/templates. — [crates/tauri-cli/src/lib.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-cli/src/lib.rs) [crates/tauri-cli/src/plugin/mod.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-cli/src/plugin/mod.rs) [crates/tauri-cli/templates/app/src-tauri/src/main.rs](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri-cli/templates/app/src-tauri/src/main.rs)
- JS-side custom serialization: any object implementing `[SERIALIZE_TO_IPC_FN]` (`__TAURI_TO_IPC_KEY__`) controls its IPC representation — the mechanism `Channel` uses to serialize itself as `__CHANNEL__:<id>`. — [packages/api/src/core.ts](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/packages/api/src/core.ts) [crates/tauri/scripts/process-ipc-message-fn.js](https://github.com/tauri-apps/tauri/blob/745b9a48aeb6e7f48d70adf3d043e6203de5bac6/crates/tauri/scripts/process-ipc-message-fn.js)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
