# Understanding the escrcpy Monorepo Structure: A Deep Dive into the pnpm + Turborepo Architecture

> Explore the escrcpy monorepo structure powered by pnpm and Turborepo. Understand how Electron UI, workspace packages, and docs are organized for efficient development.

- Repository: [viarotel-org/escrcpy](https://github.com/viarotel-org/escrcpy)
- Tags: deep-dive
- Published: 2026-09-10

---

**escrcpy** is organized as a **pnpm + Turborepo** monorepo that separates the Electron UI, reusable workspace packages, and documentation into distinct directories orchestrated by [`turbo.json`](https://github.com/viarotel-org/escrcpy/blob/main/turbo.json).

The **escrcpy** repository (viarotel-org/escrcpy) serves as a modern Android screen mirroring application built on Electron. Its monorepo structure enables independent development of the scrcpy protocol stack, device management utilities, and the main desktop interface while maintaining tight integration through shared workspace tooling.

## Top-Level Directory Layout

The repository root contains three primary directories that define the architecture:

- **`desktop/`** – The Electron application housing both main-process logic and renderer windows.
- **`packages/`** – Reusable libraries including the scrcpy protocol implementation, IPC layers, and device control modules.
- **`docs/`** – VitePress-powered documentation supporting multiple languages.

Additional directories like `scripts/` and `configs/` contain build and CI utilities, while [`pnpm-workspace.yaml`](https://github.com/viarotel-org/escrcpy/blob/main/pnpm-workspace.yaml) defines the workspace boundaries.

## The Desktop Application Layer

The `desktop/` directory contains the complete Electron application, split between the main Node.js process and renderer windows built with Vite.

### Main Process Entry Point

The application's lifecycle begins at [`desktop/electron/main.js`](https://github.com/viarotel-org/escrcpy/blob/main/desktop/electron/main.js). This file bootstraps the Electron environment using the plugin-based architecture provided by **@escrcpy/electron-setup**.

According to the source code, the main process loads plugins from **@escrcpy/electron-setup** and initializes the application window manager. This modular approach allows features to be registered dynamically rather than hard-coding them in the main entry file.

### Renderer Windows Configuration

Unlike standard Electron apps with a single window, escrcpy manages multiple distinct renderer contexts. The [`desktop/vite.config.js`](https://github.com/viarotel-org/escrcpy/blob/main/desktop/vite.config.js) defines separate Vite build entries for each window type:

- `main` – Primary interface
- `control` – Device control panel
- `explorer` – File management
- `copilot` – AI assistance features
- `terminal` – Shell access
- `automation` – Scripting interface
- `mirror` – Screen mirroring view

Each entry point compiles independently while sharing common dependencies through the workspace configuration.

## Workspace Packages Architecture

The `packages/` directory contains six core libraries that implement the business logic independently from the Electron shell.

### Core Electron Infrastructure

**`electron-setup/`** provides the foundational plugin and window management primitives. The core API resides in [`packages/electron-setup/main/index.ts`](https://github.com/viarotel-org/escrcpy/blob/main/packages/electron-setup/main/index.ts), exposing a `window` API for registering main-process modules. This abstraction layer allows the desktop application to instantiate and manage windows without directly coupling to Electron APIs.

**`electron-ipcx/`** implements a function-friendly IPC contract between the main and renderer processes. It exposes `ipcxRenderer` and `ipcxMain` utilities used by the preload layer, replacing raw `ipcMain`/`ipcRenderer` calls with type-safe function invocations.

### Scrcpy Protocol Implementation

**`wscrcpy/`** is a self-contained Vue + TypeScript module that implements the complete scrcpy protocol stack. It exports two distinct APIs:

1. **Renderer-facing API** – `Wscrcpy` component and composables for the UI layer.
2. **Main-process API** – ByteBridge factory accessible via `@escrcpy/wscrcpy/main`.

This separation allows the protocol logic to remain agnostic of the Electron context while providing optimized entry points for each process type.

### Device Control & Utilities

**`madb/`** implements an MCP (Model Context Protocol) server for AI-agent Android device control via ADB/Yadb interfaces.

**`adbx/`** serves as an injected `adbkit` layer that prefers **yadb** when available on the host device, providing enhanced performance over standard ADB connections.

**`shared/`** contains platform-neutral utilities for device handling, networking, and mathematical operations used across all packages. The export hub resides at [`packages/shared/src/index.ts`](https://github.com/viarotel-org/escrcpy/blob/main/packages/shared/src/index.ts).

## Build System and Task Orchestration

The monorepo leverages **Turborepo** (configured in [`turbo.json`](https://github.com/viarotel-org/escrcpy/blob/main/turbo.json)) to orchestrate builds and development commands across packages, while `pnpm` resolves workspace dependencies through [`pnpm-workspace.yaml`](https://github.com/viarotel-org/escrcpy/blob/main/pnpm-workspace.yaml).

Common development workflows include:

```bash

# Install all workspace dependencies

corepack enable pnpm && pnpm install

# Start the development environment (Turbo launches the Electron Vite server on port 1535)

pnpm dev

# Run type-check only for the wscrcpy package

pnpm --filter @escrcpy/wscrcpy typecheck

# Build the whole app for the current platform

pnpm build

# Sync i18n keys after editing locale JSON files

pnpm lang-sync

```

The `--filter` flag allows targeted operations on specific workspace packages without building the entire tree, significantly improving iteration speed during development.

## Key Entry Points and File References

| File | Description |
|------|-------------|
| [`desktop/electron/main.js`](https://github.com/viarotel-org/escrcpy/blob/main/desktop/electron/main.js) | Main-process entry point; loads plugins from **@escrcpy/electron-setup**. |
| [`desktop/vite.config.js`](https://github.com/viarotel-org/escrcpy/blob/main/desktop/vite.config.js) | Vite configuration defining multiple renderer windows. |
| [`packages/electron-setup/main/index.ts`](https://github.com/viarotel-org/escrcpy/blob/main/packages/electron-setup/main/index.ts) | Core API for registering application modules and windows. |
| [`packages/electron-ipcx/README.md`](https://github.com/viarotel-org/escrcpy/blob/main/packages/electron-ipcx/README.md) | Documentation of the IPC contract between renderer and main processes. |
| `packages/wscrcpy/` | Vue/TS scrcpy protocol implementation with dual-process API. |
| [`packages/shared/src/index.ts`](https://github.com/viarotel-org/escrcpy/blob/main/packages/shared/src/index.ts) | Export hub for platform-neutral utilities. |
| [`docs/en/guide/started.md`](https://github.com/viarotel-org/escrcpy/blob/main/docs/en/guide/started.md) | User-facing getting started guide. |

## Summary

- escrcpy uses a **pnpm + Turborepo** architecture to separate concerns between the Electron shell and business logic.
- The `desktop/` directory contains the main process entry at [`desktop/electron/main.js`](https://github.com/viarotel-org/escrcpy/blob/main/desktop/electron/main.js) and multi-window Vite configuration.
- Six workspace packages in `packages/` handle IPC, protocol implementation, and device control, with `wscrcpy` being the core scrcpy stack.
- **Turborepo** orchestrates builds through [`turbo.json`](https://github.com/viarotel-org/escrcpy/blob/main/turbo.json), while `pnpm` workspaces manage dependency linking.
- Development commands like `pnpm --filter @escrcpy/wscrcpy typecheck` enable targeted package operations.

## Frequently Asked Questions

### What build tools does escrcpy use for its monorepo structure?

escrcpy uses **pnpm** for package management and **Turborepo** for task orchestration. The [`pnpm-workspace.yaml`](https://github.com/viarotel-org/escrcpy/blob/main/pnpm-workspace.yaml) file defines the workspace boundaries (including `desktop/` and `packages/*`), while [`turbo.json`](https://github.com/viarotel-org/escrcpy/blob/main/turbo.json) configures the build pipeline and task dependencies. This combination enables efficient caching and parallel execution across the Electron application and workspace libraries.

### How does the desktop application handle multiple renderer windows?

The application defines multiple entry points in [`desktop/vite.config.js`](https://github.com/viarotel-org/escrcpy/blob/main/desktop/vite.config.js), specifying separate builds for windows like `main`, `control`, `explorer`, `copilot`, `terminal`, `automation`, and `mirror`. Each window operates as an independent Vite entry point while sharing common dependencies through the workspace configuration, allowing specialized UI contexts without code duplication.

### What is the purpose of the wscrcpy package in the monorepo?

**`wscrcpy`** is a self-contained Vue + TypeScript module that implements the complete scrcpy protocol stack for Android screen mirroring. It provides a renderer-facing API with the `Wscrcpy` component and composables for the UI, plus a main-process ByteBridge factory accessible via `@escrcpy/wscrcpy/main`. This dual-export pattern keeps the protocol logic decoupled from Electron specifics while offering optimized APIs for each process type.

### How do I run commands for a specific workspace package?

Use the `pnpm --filter` flag followed by the package name as defined in its [`package.json`](https://github.com/viarotel-org/escrcpy/blob/main/package.json). For example, `pnpm --filter @escrcpy/wscrcpy typecheck` runs the type-checking script only for the wscrcpy package. This filtering capability allows developers to lint, test, or build individual packages without waiting for the entire monorepo to process, significantly improving development velocity.