Desktop Cross Platform — Cheat Sheet

Tags: desktop, electron, tauri, flutter, cross-platform, ipc, c-sharp, rust

Level: intermediate

TL;DR: Trade-offs, architecture, and security across Electron, Tauri, Flutter Desktop, and .NET MAUI/Avalonia for multi-platform delivery.

Key concepts

Electron bundles Chromium and Node.js; guarantees consistent UI but has high RAM footprint and binary size.

Tauri uses native OS webviews (WebKitGTK, WebView2, WebKit) with a Rust backend; minimal memory and tiny bundles.

Flutter Desktop compiles Dart to native machine code; uses Impeller/Skia to render directly to canvas.

Avalonia and .NET MAUI offer native runtime execution via .NET; Avalonia renders its own controls directly.

IPC architecture requires strict asynchronous message passing between untrusted UI frontends and native system backends.

Packaging varies per OS: MSIX/NSIS on Windows, DMG/AppBundle on macOS, AppImage/deb/rpm on Linux.

Code signing is mandatory for production distribution: Apple Notarization on macOS, Authenticode with SmartScreen on Windows.

Auto-updating requires platform-specific handlers: Squirrel, Sparkle, or native framework auto-updaters with signed manifests.

Native capabilities (tray, global shortcuts, file system, hardware) require OS-level permission handling and background threads.

Sandboxing isolates renderer processes from native system APIs to limit exploit blast radius.

Typical questions and ready answers

Q: How do you decide between Electron and Tauri for a new desktop application?R: I pick Electron if I need absolute UI rendering consistency across Linux/Windows/macOS or heavy Node.js libraries. I choose Tauri when bundle size, idle memory usage, and Rust-level security/performance are critical requirements.

Q: What is the standard security model for Electron applications?R: I always disable nodeIntegration, enable contextIsolation, and expose only minimal, validated APIs via contextBridge in a preload script. I enforce CSP headers and validate navigation and new window requests.

Q: How do you handle cross-platform file paths and storage locations?R: I never hardcode path delimiters or directory names; I use standard OS path resolvers to target proper app data directories like AppData on Windows, Library/Application Support on macOS, and XDG directories on Linux.

Q: How do you keep the desktop UI responsive during CPU-heavy tasks?R: I offload heavy computations to background threads or worker processes, keeping the UI renderer thread purely dedicated to event handling and paint updates, synchronizing results via asynchronous IPC channels.

Pitfalls and common mistakes

Enabling nodeIntegration: true in Electron renderers, allowing remote code execution via XSS.

In Tauri, assuming webview behavior is uniform; CSS and JavaScript engine quirks differ between WebKit (macOS/Linux) and WebView2 (Windows).

Blocking the main UI thread with synchronous file I/O or long-running IPC calls.

Overlooking macOS code notarization requirements, resulting in Gatekeeper blocking the application at launch.

Hardcoding slash styles or case sensitivity assumptions across Windows and Unix file systems.

Missing high-DPI handling or fractional scaling glitches on heterogeneous multi-monitor setups.

Neglecting auto-updater signature verification, exposing clients to man-in-the-middle binary tampering.

Snippets and commandsTypeScript

// Electron secure preload script
import { contextBridge, ipcRenderer } from 'electron';

contextBridge.exposeInMainWorld('api', {
  readConfig: () => ipcRenderer.invoke('app:read-config'),
  onLogMessage: (callback: (msg: string) => void) => {
    const handler = (_: unknown, value: string) => callback(value);
    ipcRenderer.on('app:log', handler);
    return () => ipcRenderer.removeListener('app:log', handler);
  }
});

Rust

// Tauri invoke handler with state
#[tauri::command]
async fn execute_task(input: String) -> Result<String, String> {
    tokio::task::spawn_blocking(move || {
        // Run heavy task off the main thread
        Ok(format!("Processed: {}", input))
    })
    .await
    .map_err(|e| e.to_string())?
}

Bash

# Packaging and signing verification
# macOS notarization check
xcrun notarytool submit app.dmg --keychain-profile "AC_PASSWORD" --wait

# Windows Authenticode verify
signtool verify /pa /v /debug app.exe

To review

[ ] Context isolation and IPC validation schemas in webview architectures

[ ] Platform-specific native menus, tray icons, and window styling nuances

[ ] Code signing pipelines with hardware tokens and remote KMS signing

[ ] Delta-update packaging mechanics and update rollback policies

Jarvis Interviews
Jarvis