Skip to main content
The main process is the Node.js environment that orchestrates Flow Browser’s core functionality. It manages windows, tabs, sessions, and system integration.

Initialization Flow

The application starts in src/main/index.ts:1 with a carefully orchestrated initialization:
// 1. Check single instance lock
const gotTheLock = app.requestSingleInstanceLock();
if (!gotTheLock) {
  app.quit();
}

// 2. Set command-line switches
app.commandLine.appendSwitch("--disable-features", "FedCm");

// 3. Import main browser module
import("@/browser");
Source: src/main/index.ts:20 Once the lock is acquired, the browser module loads (src/main/browser.ts:1):
1

Load Controllers

Import all controllers with dependency orderingsrc/main/controllers/index.ts:1
2

Setup IPC Handlers

Register all IPC message handlerssrc/main/ipc/index.ts:1
3

Initialize Extensions

Load Chrome extension supportsrc/main/modules/extensions/main.ts
4

Start Persistence

Begin tab persistence flush intervalsrc/main/browser.ts:18
5

Create First Window

Show onboarding or restore previous sessionsrc/main/browser.ts:34

Core Controllers

Controllers are singleton classes managing specific domains. They use TypedEventEmitter for internal communication.

TabsController

Purpose: Manages all tab instances, lifecycle, grouping, and state. File: src/main/controllers/tabs-controller/index.ts:45
  • Tab Creation: createTab() - Creates Tab instances with WebContentsView
  • Tab Groups: Manages glance and split view groups
  • Active Tab Tracking: Per window-space active tab mapping
  • Lifecycle Management: Sleep, archive, destroy operations
  • Position Management: Tab ordering within spaces
class TabsController extends TypedEventEmitter<TabsControllerEvents> {
  public tabs: Map<number, Tab>;
  private tabManagers: Map<number, TabManagers>;
  
  // Per-tab managers
  public getTabManagers(tabId: number): TabManagers | undefined;
  
  // Tab creation
  public async createTab(
    windowId?: number,
    profileId?: string,
    spaceId?: string,
    webContentsViewOptions?: Electron.WebContentsViewConstructorOptions,
    tabCreationOptions: Partial<TabCreationOptions> = {}
  ): Promise<Tab>;
}
Key Maps:
  • tabs: Map<number, Tab> - All active tabs indexed by ID
  • windowActiveSpaceMap: Map<number, string> - Current space per window
  • spaceActiveTabMap: Map<WindowSpaceReference, Tab | TabGroup> - Active tab/group per window-space
  • tabGroups: Map<string, TabGroup> - All tab groups (glance, split)
Each Tab has three associated managers:
  • TabLifecycleManager - Sleep/wake, fullscreen, navigation state
  • TabLayoutManager - Show/hide, bounds calculation
  • TabBoundsController - Geometry and positioning
See src/main/controllers/tabs-controller/index.ts:243

WindowsController

Purpose: Manages all application windows and window types. File: src/main/controllers/windows-controller/index.ts:22
class WindowsController extends TypedEventEmitter<WindowsControllerEvents> {
  private windows: Map<number, BaseWindow>;
  
  // Window Type Managers
  public settings: WindowTypeManager<typeof SettingsWindow>;
  public onboarding: WindowTypeManager<typeof OnboardingWindow>;
  public browser: WindowTypeManager<typeof BrowserWindow>;
  public extensionPopup: WindowTypeManager<typeof ExtensionPopupWindow>;
}
BrowserWindow (src/main/controllers/windows-controller/types/browser.ts)
  • Main browser windows with tabs
  • Includes WebContentsViews for web pages
  • Portal component windows for omnibox, popups
  • Custom window controls integration
SettingsWindow (src/main/controllers/windows-controller/types/settings.ts)
  • Singleton settings/preferences window
  • Frameless with custom titlebar
OnboardingWindow (src/main/controllers/windows-controller/types/onboarding.ts)
  • First-run onboarding wizard
  • Singleton, shown once per installation
ExtensionPopupWindow (src/main/controllers/windows-controller/types/extension-popup.ts)
  • Extension popup windows
  • Managed by electron-chrome-extensions
Window Type Managers provide:
  • Type-safe window creation
  • Singleton enforcement (settings, onboarding)
  • Lifecycle management
  • Type-specific configurations

SessionsController

Purpose: Manages Electron sessions for different profiles. File: src/main/controllers/sessions-controller/index.ts:10
class SessionsController {
  private sessions: Map<string, Session>;
  
  // Get or create session for profile
  public get(profileId: string): Session;
  
  // Default session readiness
  public isDefaultSessionReady(): boolean;
  public whenDefaultSessionReady(): Promise<void>;
}
When creating a profile session (src/main/controllers/sessions-controller/index.ts:18):
  1. Create Session: session.fromPath(profilePath)
  2. Register Protocols: flow://, flow-external://, flow-internal://
  3. Setup Handlers: Permission handlers, certificate validation
  4. Register Preload: Inject preload scripts to all WebContents
  5. Intercept Rules: User-agent transformer, CORS bypass, PDF viewer
  6. Store Session: Cache in sessions Map
Default Session Setup:The default Electron session requires special handling for extensions. It must be ready before creating any browser windows.See src/main/controllers/sessions-controller/default-session/index.ts

SpacesController & ProfilesController

Purpose: Manage workspaces and user profiles. Files:
  • src/main/controllers/spaces-controller/index.ts
  • src/main/controllers/profiles-controller/index.ts
class SpacesController {
  // Get all spaces
  public async getAll(): Promise<SpaceData[]>;
  
  // Get spaces for a profile
  public async getFromProfile(profileId: string): Promise<SpaceData[]>;
  
  // Create new space
  public async create(profileId: string, name: string): Promise<SpaceData>;
  
  // Update space properties
  public async update(
    profileId: string,
    spaceId: string,
    data: Partial<SpaceData>
  ): Promise<void>;
}
Profiles have isolated:
  • Session storage
  • Cookies
  • Cache
  • Extensions
  • Settings

Tab Management Deep Dive

Tab Class

Each tab is an instance of the Tab class. File: src/main/controllers/tabs-controller/tab.ts
class Tab extends TypedEventEmitter<TabEvents> {
  public readonly id: number;
  public readonly uniqueId: string;
  public profileId: string;
  public spaceId: string;
  
  // WebContents
  public webContents: WebContents | null;
  private _webContentsView: WebContentsView | null;
  
  // State
  public visible: boolean;
  public asleep: boolean;
  public isPictureInPicture: boolean;
  public fullScreen: boolean;
  
  // Navigation
  public url: string;
  public title: string;
  public favicon: string | null;
  public isLoading: boolean;
  public canGoBack: boolean;
  public canGoForward: boolean;
}
Key Features:
  • Sleep Mode: Tabs can be put to sleep to save memory (src/main/controllers/tabs-controller/tab-lifecycle.ts)
  • Archive: Inactive tabs are archived after threshold
  • Tab Groups: Glance (stacked) and Split view groups
  • State Persistence: All state saved to SQLite

Tab Lifecycle

1

Creation

tabsController.createTab() creates Tab instance with WebContentsViewsrc/main/controllers/tabs-controller/index.ts:146
2

Awake State

Tab has active WebContentsView, receives events, renders in window
3

Sleep (Optional)

After inactivity threshold, destroy WebContentsView but keep statesrc/main/controllers/tabs-controller/tab-lifecycle.ts
4

Wake (Optional)

Recreate WebContentsView, restore navigation history
5

Archive

After longer inactivity, completely destroy tab (state persisted to DB)src/main/controllers/tabs-controller/index.ts:102
6

Restoration

Can restore archived tabs from persistence layer
Sleep/archive thresholds are configurable:
  • Sleep: After tab inactive for ~5 minutes
  • Archive: After tab invisible for ~30 minutes
See src/main/saving/tabs/index.ts

Data Persistence

Flow uses SQLite for all persistent data. Schema: src/main/saving/db/schema.ts

Tab Persistence

Manager: tabPersistenceManager (src/main/saving/tabs/index.ts)
class TabPersistenceManager {
  // Mark tab as dirty (needs saving)
  public markDirty(uniqueId: string, data: PersistedTabData): void;
  
  // Mark tab as removed
  public markRemoved(uniqueId: string): void;
  
  // Flush dirty tabs to database
  private async flushDirtyTabs(): Promise<void>;
  
  // Start periodic flush (every ~2s)
  public start(): void;
}
Flush Strategy:
  1. Tabs marked dirty when state changes
  2. Every 2 seconds, dirty tabs written to SQLite
  3. On app quit, final flush before database close
  4. On restore, tabs loaded from database
Recently closed tabs are tracked separately for “Reopen Closed Tab” functionality.See src/main/saving/tabs/recently-closed.ts

Extension System

Flow supports Chrome extensions via electron-chrome-extensions. File: src/main/modules/extensions/main.ts
  • Extensions loaded per profile (isolated between profiles)
  • Extension APIs provided by electron-chrome-extensions
  • Custom APIs can be added via extension handlers
  • Extensions stored in profile directory
  • Permissions managed through manifest parsing
// Extension management
import { extensionManagement } from '@/modules/extensions/management';

// Enable/disable extension
await extensionManagement.setEnabled(extensionId, enabled);

// Uninstall extension
await extensionManagement.uninstall(extensionId);

Application Lifecycle

Key lifecycle events managed in src/main/app/lifecycle.ts:
window-all-closed
  • On macOS: Keep app running
  • On Windows/Linux: Quit app
before-quit
  • Set quitController.isQuitting = true
  • Skip all IPC and persistence operations
  • Close database connection
activate (macOS)
  • If no windows, create new browser window
second-instance
  • Focus existing window
  • Process command-line URLs
Critical: During quit (quitController.isQuitting), all database operations and IPC handlers must short-circuit to prevent crashes from accessing closed database.See src/main/controllers/quit-controller/index.ts

Module System

Utility modules in src/main/modules/:
ModulePurpose
extensions/Chrome extension support
favicons.tsFavicon fetching and caching
icons.tsApp icon management
content-blocker.tsAd/tracker blocking
user-agent.tsUser-agent string handling
shortcuts.tsKeyboard shortcut management
logs.tsLogging infrastructure

Next Steps

Renderer Process

Learn about the React UI layer

IPC Communication

Understand main ↔ renderer messaging

Build docs developers (and LLMs) love