Frontend Architectures
Mullvad VPN provides multiple frontend applications across different platforms, all communicating with the same core daemon. Each platform has unique requirements and communication patterns.Communication Mechanisms
Desktop: gRPC over Unix Domain Socket
Platforms: Linux, macOS, Windows (named pipe) The desktop Electron app and CLI communicate with the daemon via gRPC defined inmullvad-management-interface/proto/management_interface.proto.
- Bidirectional streaming for event subscriptions
- Multiple concurrent clients supported
- Connection-oriented (clients detect daemon restarts)
- Automatic reconnection handling in clients
Android: JNI (Java Native Interface)
Platform: Android On Android, the daemon runs in the same process as the VpnService, with the Kotlin/Java UI layer calling into Rust via JNI.- Synchronous JNI calls from Java to Rust for commands
- Callbacks from Rust to Java for events (via JNI)
- Daemon initialized in VpnService.onCreate()
- Tunnel file descriptor passed from Android VpnService to Rust
iOS: Custom Integration with WireGuard-Kit
Platform: iOS iOS uses a different architecture where the tunnel is managed by Apple’s WireGuard-kit, with Mullvad logic providing account management and relay selection.- No full daemon running; WireGuard-kit handles tunnel
- Mullvad Rust code provides relay selection and account logic
- Network extension runs in separate process from main app
- Uses iOS NEPacketTunnelProvider API
- Offline detection via NWPathMonitor
Frontend-Specific Architectures
Desktop Electron App
Location:desktop/packages/mullvad-vpn/
Architecture:
- React for UI rendering
- Redux for state management
- Electron IPC between renderer and main process
- Main process maintains persistent gRPC connection to daemon
- Automatic reconnection on daemon restart
- System tray integration for quick access
- Auto-update using Mullvad’s update system
- Main process subscribes to daemon event stream
- Events forwarded to renderer via Electron IPC
- Redux store updated with new state
- React components re-render
Android App
Location:android/
Architecture:
- VpnService.Builder API for creating VPN tunnel
- Always-on VPN support
- Split tunneling using Android app UIDs
- Per-app VPN configuration
- ConnectivityManager for offline detection
- Background service lifecycle management
- Notification requirement for foreground service
- Android VpnService.Builder creates tunnel interface
- Tunnel FD passed to Rust via JNI
- Rust daemon uses FD for WireGuard tunnel
- Traffic routed through VPN by Android system
iOS App
Location:ios/
Architecture:
- Separate process for network extension
- App Groups for shared data between app and extension
- WireGuard-kit provides tunnel implementation
- Mullvad Rust code compiled as static library
- NWPathMonitor for network reachability
- Keychain for secure credential storage
- Shared app group container for settings
- File-based communication for configuration
- XPC for limited IPC
CLI (Command-Line Interface)
Location:mullvad-cli/
Architecture:
- Complete feature parity with GUI
- Scriptable interface
- JSON output mode for programmatic use
- Same gRPC interface as desktop app
- Single command execution (not interactive)
Event Subscription Pattern
All frontends follow a similar pattern for receiving state updates:Desktop/CLI (gRPC)
Android (JNI Callbacks)
Platform-Specific Features
Desktop
- System tray integration
- Launch at startup
- Auto-updater
- Local network sharing settings
- Split tunneling (Linux, Windows, macOS)
Android
- Always-on VPN
- Per-app VPN
- Tile for quick connect
- Work profile support
- Split tunneling by app
iOS
- On-demand VPN rules
- VPN configuration profile
- Siri shortcuts
- Widget support
CLI
- Scriptable automation
- JSON output format
- Batch operations
- Server administration
Related Documentation
- Daemon Architecture - Daemon internals and actor system
- Tunnel State Machine - State management
- Architecture Overview - Overall system design