The Problem

Donut Browser is an open-source anti-detect browser designed for managing fully isolated browser profiles with advanced fingerprint spoofing, proxy/VPN support, and cloud synchronization. The codebase spans 426 files across three projects (src, src-tauri, donut-sync) with a React/Next.js frontend, Tauri backend, and Rust systems code, serving as a self-hostable profile management platform.

What This Does

The repository implements a Tauri-electron hybrid architecture where the Rust backend (src-tauri/) handles system-level operations—browser process management, fingerprint generation via camoufox, cookie and extension handling, and proxy/VPN configuration—while the TypeScript frontend (src/, donut-sync/) provides the user interface and API layer. The src-tauri/src/sync/engine.rs file serves as the central synchronization hub, defining 91 functions called from 35 other files and managing the register/clear/drop cancel lifecycle for profile sync operations. Profile data flows through src-tauri/src/profile/manager.rs (65 functions, atomic writes, directory resolution) and src-tauri/src/cookie_manager.rs (52 functions, Chrome key derivation and database operations). Network connectivity and proxy routing are handled by src-tauri/src/proxy_manager.rs (93 functions, outbound network calls, external command execution), while the API server entry point src-tauri/src/api_server.rs:355 exposes 48 reachable functions through the local API. The donut-sync/ subsystem (29 files, 15 code files) provides the sync service layer with its own controller, service, and module architecture, though it contains 971 repeated 6-line code blocks across 103 files, indicating significant duplication pressure.

How It Is Wired

Execution begins at src-tauri/src/main.rs:4 (the main entry point), which reaches 74 functions and is called by nothing else in the repo. From main, control flows through the Tauri event loop to src-tauri/src/api_server.rs:355 (start), which reaches 48 functions and serves as the primary API gateway. The run function in src-tauri/src/human_typing.rs:372 reaches 36 functions and handles the network path via socket.recv, representing the shortest path to an outbound network call. Key hub functions with wide blast radius include instance (called from 212 places), path (135 places), and is_empty (105 places). The most connected module is src/components/ui/ripple.tsx with 31 dependents and zero outgoing imports—modifying this file carries high-blast-radius risk. Three files exceed 800 code lines (donut-sync/src/sync/sync.service.ts, src-tauri/src/api_client.rs, src-tauri/src/api_server.rs), creating cognitive load for changes that ripple widely. Deep nesting (max depth 8) appears in src/components/multiple-selector.tsx, src/components/create-profile-dialog.tsx, and src/components/extension-management-dialog.tsx, making control flow hard to follow.

How To Use It

Setup: The project uses pnpm workspaces with a Tauri backend. Install dependencies with pnpm install from the root. The Tauri binary is built via pnpm tauri build (configured in package.json). Donut-sync sync service runs in a separate Docker environment defined by donut-sync/Dockerfile (base image node:22-alpine) and docker-compose.yml.

Configuration: Environment variables are defined in .env.example (root) and donut-sync/.env.example. Key vars include database connection strings and sync credentials. The Tauri config lives in src-tauri/Cargo.toml and src-tauri/tauri.conf.json.

Running it: Start the development server with pnpm dev (from scripts/dev.sh). The Tauri CLI handles the desktop binary. For the sync service specifically, use pnpm -C donut-sync dev or build the Docker container with docker-compose -f donut-sync/docker-compose.yml up.

Real-World Use

A security researcher needs to manage 50 isolated browser profiles for multi-account testing. They clone the repo, run pnpm dev, then use the UI to create profile groups, import cookies from Chrome via the cookie_manager.rs integration, and configure SOCKS5 proxies through proxy_manager.rs. The MCP server (mcp_server.rs, 85 functions) enables integration with automation tools like Claude for scripted profile provisioning. When a profile is launched, browser.rs resolves the Chromium executable path, applies fingerprint spoofing data from the camoufox data directory, and launches the isolated session. Sync across machines is triggered via the local API endpoint defined in api_server.rs, with optional E2E encryption using a user-provided password.

Code Health & Issues

  • [HIGH] Open a pull request instead of pushing to the default branch - .github/workflows/release.yml contains git push origin "$BRANCH", landing automated commits directly on the deploying branch with no test having run against the result. Push to a bot branch and open a pull request, or restrict push to tag refs.
  • [MEDIUM] Pin the container base image by digest - donut-sync/Dockerfile uses mutable node:22-alpine tag, meaning today's build and last month's contain different libc and a different CVE set with no record of which shipped. Use node:22-alpine@sha256:<digest> and enable Dependabot's docker ecosystem.
  • [MEDIUM] Set persist-credentials: false on checkout - .github/workflows/release.yml checkout step keeps the token in .git/config, so a malicious postinstall script reads a pushable credential without one ever being passed to it. Add with: persist-credentials: false and pass an explicit token only to the push step.
  • [LOW] Set timeout-minutes on workflow jobs - 4 workflows in .github/workflows/ declare no job timeout; a wedged step runs to the six-hour platform default, causing three runs to overlap behind the two-hourly schedule. Add timeout-minutes with a realistic bound to each job.
  • [LOW] Add repository convention files this project lacks - Missing .editorconfig, .gitattributes with text=auto eol=lf, and a formatter config causes inconsistent editor behavior across contributors.

The Bottom Line

This is a feature-rich anti-detect browser with solid Tauri/Rust systems code and a functional sync architecture, but the codebase shows significant cognitive load from oversized files (800+ lines), deep nesting, and pervasive code duplication that will slow feature work. The SDLC is mature (CI, tests, Docker, license present) but the release workflow pushes directly to the default branch without test gatekeeping, and the Docker base image is untagged. Best suited for teams needing a self-hostable profile manager who can tolerate refactoring the duplicated sync logic and addressing the nesting depth issues.