# What Is the Tabby Electron-Browser Architecture?

> Understand the Tabby Electron-browser architecture. Learn how its core-plugin pattern and abstract services enable desktop IPC and browser compatibility for a flexible terminal experience.

- Repository: [Eugene/tabby](https://github.com/Eugeny/tabby)
- Tags: architecture
- Published: 2026-03-03

---

**Tabby’s electron-browser architecture implements a core-plugin pattern where a platform-agnostic Angular core delegates native operations to abstract services, with concrete implementations provided by `tabby-electron` for desktop IPC integration and `tabby-web` for browser compatibility.**

Tabby (Eugeny/tabby) is a modern terminal emulator built with TypeScript and Angular that runs both as a desktop Electron application and as a pure web app. Its **electron-browser architecture** achieves this portability through strict separation between the UI logic and platform-specific APIs. The core application code remains identical across both environments, relying on Angular’s dependency injection to swap底层 implementations at runtime.

## Core-Plugin Architecture: The Platform-Agnostic Foundation

The architecture centers on `tabby-core`, a package containing the public API and Angular UI logic that is completely **platform-agnostic**. It defines abstract service interfaces without importing Electron or browser-specific APIs, enabling the same components to execute in either environment.

### Abstract Service Interfaces

Two critical abstractions enable platform isolation:

- **`HostAppService`** – Defines methods for host interaction such as `newWindow()`, `quit()`, `openExternal()`, and `selectFile()`【/cache/repos/github.com/Eugeny/tabby/master/tabby-core/src/api/hostApp.ts】. The UI layer injects this interface to perform native operations without knowing the underlying platform.

- **`PlatformService`** – Provides utilities for theme handling, clipboard access, and screen information【/cache/repos/github.com/Eugeny/tabby/master/tabby-core/src/api/platform.ts】.

### Platform Plugin Structure

Concrete implementations reside in separate platform packages:

| Platform | Package | Purpose |
|----------|---------|---------|
| **Desktop** | `tabby-electron` | Wraps Electron main-process and renderer-process APIs |
| **Web** | `tabby-web` | Implements browser-compatible stubs using standard web APIs |

## Electron Platform Implementation (tabby-electron)

The desktop implementation bridges the Angular renderer to Electron’s native APIs through an IPC (Inter-Process Communication) layer.

### ElectronService and Low-Level Wrappers

The **`ElectronService`** exposes raw Electron objects as injectable Angular services. Located at [`tabby-electron/src/services/electron.service.ts`](https://github.com/Eugeny/tabby/blob/main/tabby-electron/src/services/electron.service.ts), it provides typed access to `app`, `ipcRenderer`, `shell`, and other Electron modules【/cache/repos/github.com/Eugeny/tabby/master/tabby-electron/src/services/electron.service.ts】.

### ElectronHostAppService and IPC Integration

**`ElectronHostAppService`** implements the abstract `HostAppService` interface by delegating to `ElectronService`:

- `newWindow()` sends the `'app:new-window'` IPC message to the main process
- `showItemInFolder()` calls `electron.shell.showItemInFolder()`
- `quit()` invokes `electron.app.quit()`
- `relaunch()` uses `electron.app.relaunch()`【/cache/repos/github.com/Eugeny/tabby/master/tabby-electron/src/services/hostApp.service.ts】

The **main process** (entry point [`app/src/main.js`](https://github.com/Eugeny/tabby/blob/main/app/src/main.js)) creates the `BrowserWindow`, loads the Angular bundle, and sends bootstrap data via the `'start'` IPC channel. The **renderer process** receives this in [`app/src/entry.ts`](https://github.com/Eugeny/tabby/blob/main/app/src/entry.ts) via `ipcRenderer.once('start', …)` before bootstrapping the Angular module【/cache/repos/github.com/Eugeny/tabby/master/appsrc/entry.ts】.

## Web Platform Implementation (tabby-web)

For browser deployment, `tabby-web` provides stub implementations that replace Electron-specific functionality with web-standard equivalents or throw `NotImplemented` errors where impossible.

### WebHostApp Fallbacks

**`WebHostApp`** implements the same `HostAppService` interface using browser primitives:

- `relaunch()` calls `location.reload()`
- `quit()` closes the current window
- `newWindow()` throws an error because web pages cannot spawn native windows
- `openExternal()` falls back to `window.open()`【/cache/repos/github.com/Eugeny/tabby/master/tabby-web/src/services/hostApp.service.ts】

The `WebModule` registers these providers in [`tabby-web/src/index.ts`](https://github.com/Eugeny/tabby/blob/main/tabby-web/src/index.ts), ensuring Angular injects browser-compatible services when building for the web【/cache/repos/github.com/Eugeny/tabby/master/tabby-web/src/index.ts】.

## Runtime Integration and Bootstrap Flow

The electron-browser architecture relies on Angular’s dependency injection system to substitute implementations at runtime:

1. **Main Process Launch**: Electron’s main process ([`app/src/main.js`](https://github.com/Eugeny/tabby/blob/main/app/src/main.js)) initializes the native environment and creates a `BrowserWindow`.
2. **Renderer Bootstrap**: [`app/src/entry.ts`](https://github.com/Eugeny/tabby/blob/main/app/src/entry.ts) receives `BootstrapData` through the `'start'` IPC message, discovers plugins via `findPlugins()`, and bootstraps the root Angular module.
3. **Service Resolution**: Angular resolves `HostAppService` to `ElectronHostAppService` in desktop builds and `WebHostApp` in browser builds.
4. **Feature Isolation**: Platform-specific features (native dialogs, file system access) remain confined to their respective plugins, preventing the core from importing Electron directly.

## Cross-Platform Implementation Examples

The following examples demonstrate how the same UI code executes differently across platforms.

### Opening External URLs

This code works identically in Electron and browsers:

```typescript
import { HostAppService } from 'tabby-core';

constructor (private hostApp: HostAppService) {}

openDocs () {
    // Electron uses electron.shell.openExternal; browser uses window.open
    this.hostApp.openExternal('https://tabby.sh/docs/');
}

```

### Native File Dialogs (Electron Only)

File selection requires native APIs unavailable in browsers:

```typescript
import { HostAppService } from 'tabby-core';

async selectFile () {
    const files = await this.hostApp.selectFile({
        properties: ['openFile']
    });
    return files;
}

```

*In Electron, this delegates to `dialog.showOpenDialog` via `ElectronHostAppService`. In the browser, the method is not implemented.*

### Window Management

Creating new application windows uses IPC in Electron:

```typescript
import { HostAppService } from 'tabby-core';

createWindow () {
    // Electron: sends 'app:new-window' IPC; Web: throws NotImplemented
    this.hostApp.newWindow();
}

```

### Application Relaunch

Cross-platform restart logic adapts to the environment:

```typescript
import { HostAppService } from 'tabby-core';

restart () {
    // Electron: app.relaunch(); Browser: location.reload()
    this.hostApp.relaunch();
}

```

## Summary

- **Tabby’s electron-browser architecture** separates platform-agnostic UI logic (`tabby-core`) from native implementations via abstract services.
- **`HostAppService`** and **`PlatformService`** define the contract that enables the same Angular code to run on desktop and web.
- **`tabby-electron`** implements native capabilities through `ElectronService` and `ElectronHostAppService`, using IPC to communicate with the main process.
- **`tabby-web`** provides browser-compatible stubs that use standard web APIs where possible.
- **Dependency injection** automatically substitutes the correct platform implementation at bootstrap time, ensuring clean separation of concerns.

## Frequently Asked Questions

### How does Tabby handle native features like file dialogs in the browser version?

The web implementation throws `NotImplemented` for unsupported operations or provides limited fallbacks. For example, `selectFile()` is only available in the Electron build where `ElectronHostAppService` can access `dialog.showOpenDialog`. Browser users must use HTML file inputs directly, as the web platform cannot access the native file system without user interaction through specific web APIs.

### What is the role of the main process in Tabby's Electron architecture?

The main process ([`app/src/main.js`](https://github.com/Eugeny/tabby/blob/main/app/src/main.js)) manages native resources by creating `BrowserWindow` instances, handling system events, and exposing capabilities to the renderer via IPC. It sends initial `BootstrapData` to the Angular app through the `'start'` channel before the UI initializes in [`app/src/entry.ts`](https://github.com/Eugeny/tabby/blob/main/app/src/entry.ts), effectively bridging the Electron container with the Angular application.

### Can plugins access Electron APIs directly?

No. Plugins interact only with the abstract services defined in `tabby-core`, such as `HostAppService`. Direct Electron access is encapsulated in [`tabby-electron/src/services/electron.service.ts`](https://github.com/Eugeny/tabby/blob/main/tabby-electron/src/services/electron.service.ts). This design ensures plugins remain compatible with both desktop and web builds unless they explicitly depend on platform-specific features, maintaining the integrity of the electron-browser architecture.

### How does Tabby achieve code sharing between the desktop and web versions?

The Angular UI layer imports only from `tabby-core`, never from Electron or browser-specific modules. At build time, the Angular compiler includes either `tabby-electron` or `tabby-web` providers based on the target platform, injecting the correct implementation of `HostAppService` and `PlatformService` throughout the application via Angular’s dependency injection system.