API Reference

March 16, 2026 · View on GitHub

This document provides a comprehensive reference for the @zubridge/electron API.

Backend (Main Process) APIs

Bridge APIs

createCoreBridge(stateManager, options?)

Creates a core bridge between the main process and renderer processes, using any state manager that implements the StateManager interface. This is useful for creating custom bridges with state management libraries not directly supported by Zubridge.

Parameters:
  • stateManager: Implementation of the StateManager<State> interface
  • options?: Optional CoreBridgeOptions configuration object (see CoreBridgeOptions for details)
Returns:

A CoreBridge object with:

  • subscribe(windows): Function to subscribe additional windows to the state updates. Returns an object with an unsubscribe method.
  • unsubscribe(windows?): Function to unsubscribe windows from updates. When called without arguments, unsubscribes all windows.
  • destroy(): Function to clean up resources used by the bridge.
Example:
// `src/main/bridge.ts`
import { app, BrowserWindow } from 'electron';
import { createCoreBridge } from '@zubridge/electron/main';
import { myStateManager } from './state-manager';

const mainWindow = new BrowserWindow({
  /* options */
});

// Create bridge with default settings
const bridge = createCoreBridge(myStateManager);

// Or create with custom options
const bridgeWithOptions = createCoreBridge(myStateManager, {
  serialization: {
    maxDepth: 5, // Limit state serialization depth
  },
  onBridgeDestroy: async () => {
    console.log('Bridge destroyed');
  },
});

// Subscribe windows
const subscription = bridge.subscribe([mainWindow]);

// Unsubscribe when quitting
app.on('quit', bridge.unsubscribe);

createZustandBridge(store, options?)

Creates a bridge between a Zustand store in the main process and renderer processes. This is the recommended way to integrate a Zustand store with Electron's IPC system.

Parameters:
  • store: The Zustand store to bridge
  • options?: Optional configuration object that accepts both Zustand-specific options and all CoreBridgeOptions
    • Zustand-specific:
      • handlers: Optional object containing store handler functions
      • reducer: Optional root reducer function for Redux-style state management
    • CoreBridgeOptions: All options from CoreBridgeOptions are also supported:
      • serialization: Serialization configuration (e.g., maxDepth)
      • resourceManagement: Resource cleanup configuration
      • onBridgeDestroy: Lifecycle hook called before bridge cleanup
      • middleware: ⚠️ Experimental - Optional middleware for logging and debugging (not yet released)
Returns:

A ZustandBridge object with:

  • subscribe(windows): Function to subscribe additional windows to the store updates. Returns an object with an unsubscribe method.
  • unsubscribe(windows?): Function to unsubscribe windows from the store. When called without arguments, unsubscribes all windows.
  • dispatch: Function to dispatch actions to the store.
  • destroy(): Function to clean up resources used by the bridge.
Example:
// `src/main/bridge.ts`
import { app, BrowserWindow } from 'electron';
import { createZustandBridge } from '@zubridge/electron/main';
import { store } from './store';

const mainWindow = new BrowserWindow({
  /* options */
});

// Create bridge with default settings
const bridge = createZustandBridge(store);

// Subscribe windows to receive state updates
const { unsubscribe } = bridge.subscribe([mainWindow]);

// Using with handlers option
const bridgeWithHandlers = createZustandBridge(store, {
  handlers: {
    CUSTOM_ACTION: (payload) => {
      console.log('Custom action received:', payload);
      store.setState((state) => ({ ...state, customValue: payload }));
    },
  },
});

// Using with reducer option
const bridgeWithReducer = createZustandBridge(store, {
  reducer: (state, action) => {
    switch (action.type) {
      case 'SET_VALUE':
        return { ...state, value: action.payload };
      default:
        return state;
    }
  },
});

// Using with CoreBridgeOptions
const bridgeWithOptions = createZustandBridge(store, {
  serialization: {
    maxDepth: 5, // Limit state serialization depth
  },
  resourceManagement: {
    cleanupIntervalMs: 300000, // Cleanup every 5 minutes
  },
  onBridgeDestroy: async () => {
    console.log('Saving state before shutdown...');
    await saveState(store.getState());
  },
});

// Dispatch actions from the main process
bridge.dispatch('INCREMENT');

// Unsubscribe when quitting
app.on('quit', unsubscribe);

createReduxBridge(store, options?)

Creates a bridge between a Redux store in the main process and renderer processes. This is the recommended way to integrate a Redux store with Electron's IPC system.

Parameters:
  • store: The Redux store to bridge
  • options?: Optional configuration object that accepts both Redux-specific options and all CoreBridgeOptions
    • Redux-specific:
      • handlers: Optional object containing action handler functions
    • CoreBridgeOptions: All options from CoreBridgeOptions are also supported:
      • serialization: Serialization configuration (e.g., maxDepth)
      • resourceManagement: Resource cleanup configuration
      • onBridgeDestroy: Lifecycle hook called before bridge cleanup
      • middleware: ⚠️ Experimental - Optional middleware for logging and debugging (not yet released)
Returns:

A ReduxBridge object with:

  • subscribe(windows): Function to subscribe additional windows to the store updates. Returns an object with an unsubscribe method.
  • unsubscribe(windows?): Function to unsubscribe windows from the store. When called without arguments, unsubscribes all windows.
  • dispatch: Function to dispatch actions to the store.
  • destroy(): Function to clean up resources used by the bridge.
Example:
// `src/main/bridge.ts`
import { app, BrowserWindow } from 'electron';
import { createReduxBridge } from '@zubridge/electron/main';
import { store } from './store';

const mainWindow = new BrowserWindow({
  /* options */
});

// Create bridge with default settings
const bridge = createReduxBridge(store);

// Subscribe windows to receive state updates
const { unsubscribe } = bridge.subscribe([mainWindow]);

// Using with CoreBridgeOptions
const bridgeWithOptions = createReduxBridge(store, {
  serialization: {
    maxDepth: 7, // Limit state serialization depth
  },
  resourceManagement: {
    enablePeriodicCleanup: true,
    cleanupIntervalMs: 1200000, // increase cleanup interval
  },
  onBridgeDestroy: async () => {
    console.log('Redux bridge shutting down');
    await persistState(store.getState());
  },
});

// Dispatch actions from the main process
bridge.dispatch({ type: 'INCREMENT' });

// Unsubscribe when quitting
app.on('quit', unsubscribe);

mainZustandBridge(store, windows, options?) (Deprecated)

Deprecated: This is now an alias for createZustandBridge and uses the new IPC channels. Please migrate to createZustandBridge.

Parameters and returns:

Same as createZustandBridge.

Dispatch APIs

createDispatch(store, options?)

Creates a dispatch function that can be used in the main process to dispatch actions to the store. This function supports both Zustand and Redux stores.

Parameters:
  • store: Either a Zustand store (StoreApi<State>) or Redux store (Store<State>)
  • options?: Optional configuration object
    • For Zustand stores: can include handlers or reducer options
    • For Redux stores: can include Redux-specific integration options
Returns:

A Dispatch<S> function that can dispatch actions to the store. This dispatch function supports:

  • String action types with optional payload: dispatch('ACTION', payload?)
  • Action objects with optional options: dispatch({ type, payload }, options?)
  • Thunk functions with optional options: dispatch(thunkFn, options?)
Example:
// `src/main/bridge.ts`
import { createDispatch } from '@zubridge/electron/main';
import { store } from './store';

// Create dispatch function
export const dispatch = createDispatch(store);

// Use the dispatch function
dispatch('INCREMENT');

// Dispatch with a payload
dispatch('SET_VALUE', 42);

// Dispatch an action object
dispatch({ type: 'SET_VALUE', payload: 42 });

// Dispatch a thunk function
dispatch((getState, dispatch) => {
  const currentState = getState();
  if (currentState.counter < 10) {
    dispatch('INCREMENT');
  }
});
Internal API: createDispatch with StateManager

There's also an internal overload that accepts a state manager directly, but this is primarily for internal use by bridge implementations.

Frontend (Renderer Process) APIs

Preload Script APIs

preloadBridge(options?)

Creates handlers for the renderer process to interact with the main process through the backend contract.

Parameters:
  • options?: Optional PreloadOptions configuration object
    • enableBatching?: boolean — Enable action batching (default: true)
    • batching?: Partial<BatchingConfig> — Batching configuration (see BatchingConfig)
    • maxQueueSize?: number — Maximum pending actions in the queue (default: 100)
    • actionCompletionTimeoutMs?: number — Timeout for action completion in ms (default: 30000, Linux: 60000)
Returns:

A PreloadZustandBridgeReturn object with:

  • handlers: The Handlers<State> object to expose to the renderer process
  • initialized: Whether the bridge initialized successfully
  • getBatchStats(): Returns current BatchStats, or null if batching is disabled
Example:
// `src/preload/index.ts`
import { contextBridge } from 'electron';
import { preloadBridge } from '@zubridge/electron/preload';

const { handlers, getBatchStats } = preloadBridge({
  enableBatching: true,
  batching: {
    windowMs: 16,
    maxBatchSize: 50,
  },
});

// Expose the handlers to the renderer process
contextBridge.exposeInMainWorld('zubridge', handlers);

preloadZustandBridge() (Deprecated)

Deprecated: This is now an alias for preloadBridge and uses the new IPC channels. Please migrate to preloadBridge.

Returns:

Same as preloadBridge.

Renderer Process Hooks

createUseStore<State>(customHandlers?)

Function that creates a hook to access the store state in the renderer process.

Parameters:
  • customHandlers: Optional custom handlers to use instead of window.zubridge
  • State: Type parameter representing your application state
Returns:

A hook that can be used to select state from the store.

Example:
// `src/renderer/hooks/useStore.ts`
import { createUseStore } from '@zubridge/electron';
import type { State } from '../../features';

export const useStore = createUseStore<State>();

// `src/renderer/components/Counter.tsx`
import { useStore } from '../hooks/useStore';

function Counter() {
  const counter = useStore((state) => state.counter);
  return <div>{counter}</div>;
}

useDispatch<State>(customHandlers?)

Hook to dispatch actions to the store from the renderer process.

Parameters:
  • customHandlers: Optional custom handlers to use instead of window.zubridge
  • State: Type parameter representing your application state
  • ActionTypes: Optional generic type parameter for typed action objects
Returns:

A dispatch function that can be used to send actions to the main process.

Example:
// `src/renderer/components/Counter.tsx`
import { useDispatch } from '@zubridge/electron';
import type { State } from '../../features';

function Counter() {
  const dispatch = useDispatch<State>();

  // Dispatch a string action
  const handleIncrement = () => dispatch('INCREMENT');

  // Dispatch an action with payload
  const handleSetCounter = (value) => dispatch('SET_COUNTER', value);

  // Dispatch an action object
  const handleCustomIncrement = (amount) => dispatch({
    type: 'INCREMENT_BY',
    payload: amount
  });

  // Dispatch with typed actions
  const typedDispatch = useDispatch<State, { 'SET_COUNTER': number }>();
  const handleTypedSetCounter = (value: number) => typedDispatch({
    type: 'SET_COUNTER',
    payload: value // Type checked to be a number
  });

  // Dispatch a thunk for complex logic
  const handleFetchAndUpdate = () => dispatch(async (getState, dispatch) => {
    const response = await fetch('/api/counter');
    const data = await response.json();
    dispatch('SET_COUNTER', data.value);
  });

  // Dispatch with immediate execution, bypassing all queues
  const handleUrgentAction = () => dispatch({ type: 'URGENT_ACTION' }, {
    immediate: true
  });

  // Dispatch with selective subscription keys
  const handlePrivateAction = () => dispatch({ type: 'PRIVATE_UPDATE', payload: { data: 'secret' } }, {
    keys: ['admin', 'private']
  });

  return (
    <div>
      <button onClick={handleIncrement}>+1</button>
      <button onClick={() => handleSetCounter(0)}>Reset</button>
      <button onClick={() => handleCustomIncrement(5)}>+5</button>
      <button onClick={() => handleTypedSetCounter(10)}>Set to 10 (Typed)</button>
      <button onClick={handleFetchAndUpdate}>Fetch</button>
      <button onClick={handleUrgentAction}>Urgent Action</button>
      <button onClick={handlePrivateAction}>Private Action</button>
    </div>
  );
}

Type Definitions and Interfaces

StateManager<State>

Interface that defines the contract for state managers used with the bridge. Any state management solution can be integrated with the bridge system by implementing this interface.

interface StateManager<State> {
  getState: () => State;
  subscribe: (listener: (state: State) => void) => () => void;
  processAction: (action: Action) => void;
}

CoreBridge

Interface for the bridge created by createCoreBridge.

interface CoreBridge extends BaseBridge {
  subscribe: (wrappers: WebContentsWrapper[]) => { unsubscribe: () => void };
  unsubscribe: (wrappers?: WebContentsWrapper[]) => void;
  destroy: () => void;
}

ZustandBridge

Interface for the bridge created by createZustandBridge.

interface ZustandBridge extends BackendBridge {
  subscribe: (windows: WrapperOrWebContents[]) => { unsubscribe: () => void };
  unsubscribe: (windows?: WrapperOrWebContents[]) => void;
  dispatch: Dispatch<S>;
  destroy: () => void;
}

ReduxBridge

Interface for the bridge created by createReduxBridge.

interface ReduxBridge extends BackendBridge {
  subscribe: (windows: WrapperOrWebContents[]) => { unsubscribe: () => void };
  unsubscribe: (windows?: WrapperOrWebContents[]) => void;
  dispatch: Dispatch<S>;
  destroy: () => void;
}

BaseBridge

Base interface that all bridge implementations extend.

interface BaseBridge {
  unsubscribe: (...args: any[]) => void;
}

Action

Represents a Redux-style action with a type and optional payload.

type Action<T extends string = string> = {
  type: T;
  payload: unknown;
};

Thunk<State>

Represents a thunk function for handling asynchronous logic.

type Thunk<State> = (getState: StoreApi<State>['getState'], dispatch: Dispatch<State>) => void;

Dispatch<S>

The dispatch function type. Uses overloads to provide a clean 2-argument interface for all dispatch patterns:

type Dispatch<S> = {
  // Action object with optional options
  (action: Action, options?: DispatchOptions): Promise<unknown>;
  // String action with optional payload (use action object form for options)
  (action: string, payload?: unknown): Promise<unknown>;
  // Thunk with optional options
  (action: Thunk<S>, options?: DispatchOptions): Promise<unknown>;
};

To pass DispatchOptions with an action, use the action object form:

// String dispatch — payload only, no options
dispatch('INCREMENT');
dispatch('SET_VALUE', 42);

// Action object dispatch — supports options
dispatch({ type: 'URGENT_ACTION', payload: 42 }, { immediate: true });
dispatch({ type: 'ADMIN_UPDATE' }, { keys: ['admin'] });

// Thunk dispatch — supports options
dispatch(myThunk, { immediate: true });

DispatchOptions

Options that can be passed to dispatch functions to control execution behavior.

type DispatchOptions = {
  keys?: string[];                  // Selective subscription keys
  bypassAccessControl?: boolean;    // Skip access control checks
  immediate?: boolean;              // Execute immediately, bypassing all queues
  batch?: boolean;                  // Enable batching for thunk actions
};

These options allow for advanced control over action dispatch:

  • keys: When provided, only subscribers with matching keys will receive state updates
  • bypassAccessControl: Allows actions to bypass normal access control restrictions
  • immediate: Allows actions to execute immediately, bypassing the batch window, action queue, and concurrency controls
  • batch: When true, enables batching for thunk actions. By default, thunk actions use direct dispatch to avoid deadlocks. Set this to true to opt into batching for reduced IPC overhead.

ThunkDispatch

Extended dispatch function available inside thunks, with batch support.

interface ThunkDispatch<S = AnyState> {
  // Standard dispatch
  (action: Action): Promise<void>;
  (action: Action, options: DispatchOptions): Promise<void>;
  
  // Dispatch with batching enabled (shorthand for dispatch(action, { batch: true }))
  batch(action: Action, options?: Omit<DispatchOptions, 'batch'>): Promise<void>;
  
  // Flush pending batched actions immediately
  flush(): Promise<FlushResult>;
}

Usage inside thunks:

const myThunk = async (getState, dispatch) => {
  // Direct dispatch (default)
  await dispatch({ type: 'A' });
  
  // Batched dispatch
  void dispatch.batch({ type: 'B' });
  
  // Flush and wait for completion
  const result = await dispatch.flush();
};

FlushResult

Result returned by dispatch.flush() when flushing pending batched actions.

interface FlushResult {
  /** Unique identifier for the batch that was sent */
  batchId: string;
  /** Number of actions that were sent in the batch */
  actionsSent: number;
  /** IDs of the actions that were sent */
  actionIds: string[];
}

Example:

const result = await dispatch.flush();
console.log(`Batch ${result.batchId} sent ${result.actionsSent} actions`);

BatchingConfig

Configuration for the action batcher, passed via preloadBridge({ batching: { ... } }).

interface BatchingConfig {
  /** Batch window in milliseconds. Actions within this window are grouped. Default: 16 */
  windowMs: number;
  /** Maximum actions per batch before forcing a flush. Default: 50 */
  maxBatchSize: number;
  /** Priority at or above which an action triggers an immediate flush. Default: 80 */
  priorityFlushThreshold: number;
  /** Timeout (ms) for batch/dispatch acknowledgments from the main process. Default: 30000 (Linux: 60000) */
  ackTimeoutMs: number;
}

All fields are optional when passed to preloadBridge — unset fields use the defaults shown above.

BatchStats

Snapshot of the batcher's current state, returned by getBatchStats().

interface BatchStats {
  /** Total batches sent since initialization */
  totalBatches: number;
  /** Total actions sent across all batches */
  totalActions: number;
  /** Average actions per batch (0 if no batches sent) */
  averageBatchSize: number;
  /** Number of actions currently queued awaiting flush */
  currentQueueSize: number;
  /** Whether a flush is currently in progress */
  isFlushing: boolean;
  /** Number of actions rejected (e.g., queue overflow, post-destroy enqueue) */
  rejectedActions: number;
  /** Hard queue limit (actions beyond this are rejected) */
  queueLimit: number;
}

CoreBridgeOptions

Configuration options for the core bridge created with createCoreBridge.

interface CoreBridgeOptions {
  // Middleware - **⚠️ Experimental** (not yet released)
  middleware?: ZubridgeMiddleware;

  // Lifecycle hooks
  onBridgeDestroy?: () => Promise<void> | void;

  // Resource management
  resourceManagement?: {
    enablePeriodicCleanup?: boolean;    // Enable periodic cleanup (default: true)
    cleanupIntervalMs?: number;         // Cleanup interval in ms (default: 600000 = 10 minutes)
    maxSubscriptionManagers?: number;   // Max managers before forcing cleanup (default: 1000)
  };

  // Serialization
  serialization?: {
    maxDepth?: number;                  // Maximum depth for state serialization (default: 10)
  };
}

Serialization:

  • maxDepth: Controls how deep the state serialization will traverse object hierarchies. This prevents stack overflow errors and controls payload size when dealing with deeply nested state. The default is 10 levels. When the maximum depth is exceeded, the value is replaced with a string indicating truncation.

    // Example: Limit serialization to 5 levels deep
    const bridge = createCoreBridge(stateManager, {
      serialization: {
        maxDepth: 5
      }
    });
    

Resource Management:

  • enablePeriodicCleanup: Automatically clean up subscription managers for destroyed windows (default: true)
  • cleanupIntervalMs: How often to run cleanup in milliseconds (default: 600000 = 10 minutes)
  • maxSubscriptionManagers: Force cleanup when this many managers exist (default: 1000)

Middleware:

  • middleware: ⚠️ Experimental - Zubridge middleware for tracking actions and state updates. The @zubridge/middleware package is not yet released and will be rewritten in the UniFFI rewrite. This API may change.

Lifecycle Hooks:

  • onBridgeDestroy: Called before cleanup when bridge.destroy() is invoked. This allows you to access final state or perform coordinated shutdown tasks before resources are cleaned up.

    const bridge = createCoreBridge(stateManager, {
      onBridgeDestroy: async () => {
        // Save final state before cleanup
        const finalState = stateManager.getState();
        await saveStateToFile(finalState);
    
        // Perform any cleanup tasks
        console.log('Bridge is shutting down');
      }
    });
    

ZustandOptions<State>

Configuration options specific to the Zustand bridge. When passed to createZustandBridge, these can be combined with all CoreBridgeOptions.

type ZustandOptions<State extends AnyState> = {
  handlers?: Record<string, Handler>;
  reducer?: RootReducer<State>;
};

Note: createZustandBridge accepts ZustandOptions<State> & CoreBridgeOptions, meaning you can use any combination of Zustand-specific options and core bridge options.

ReduxOptions<State>

Configuration options specific to the Redux bridge. When passed to createReduxBridge, these can be combined with all CoreBridgeOptions.

type ReduxOptions<State extends AnyState> = {
  handlers?: Record<string, Handler>;
};

Note: createReduxBridge accepts ReduxOptions<State> & CoreBridgeOptions, meaning you can use any combination of Redux-specific options and core bridge options.

WebContentsWrapper

Represents any Electron object that has WebContents. This includes BrowserWindow, BrowserView, and WebContentsView.

type WrapperOrWebContents = WebContents | { webContents: WebContents; isDestroyed?: () => boolean };

Handlers<State>

Interface for the handlers exposed to the renderer process.

interface Handlers<State extends AnyState> extends BaseHandler<State> {
  getState(): Promise<State>;
  subscribe(callback: (newState: State) => void): () => void;
}
  • Advanced Usage - Multi-window, selective subscriptions, and dispatch options
  • Validation - Action validation rules, limits, and security
  • Performance - Action batching and priority system
  • Thunks - Async action handling and thunk lifecycle