# Data flow — electron/electron

> Canonical page: https://codevetter.com/unpack/electron/data-flow

# Data flow — electron/electron

Scanned commit 56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f (2026-09-22). Generated by codevetter codevetter 1.12.0 on 2026-09-22.

App code enters through a package.json discovered in resources/{app.asar,app,default_app.asar}; the browser process creates a Node environment, loads the bundled browser init script which in turn loads the app's main entry. Renderer↔browser communication rides a mojo interface (mojom::ElectronApiIPC) into a C++ dispatch layer that emits events on the JS ipcMain/ipcMainInternal objects; the reverse direction emits on ipcRenderer via a hidden 'ipcNative' context binding. Network data flows through Chromium URL loader factories, with protocol.handle() bridging Fetch-API Request/Response objects and net.fetch routing through the session's network context. Preload scripts are pushed to the renderer ahead of navigation in startup data rather than fetched by sync IPC.
- App discovery: LoadAppPackage() reads package.json from resources/app.asar, then resources/app, then resources/default_app.asar (only app.asar when the only_load_app_from_asar fuse is on), applies name/productName/version/desktopName, and returns {path, main, esm, v8Flags}. — [shell/browser/app_package.cc#L86-L134](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/app_package.cc#L86-L134)
- PostEarlyInitialization() stashes the AppPackage as a v8 private value 'appPackage' on the Node context global; lib/browser/init.ts retrieves it via getHiddenValue, calls app.setAppPath, then loads the entry with Module._load (CJS) or runEntryPointWithESMLoader (ESM, when type=module or .mjs). — [shell/browser/electron_browser_main_parts.cc#L349-L365](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L349-L365) [lib/browser/init.ts#L62-L121](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/init.ts#L62-L121)
- node_bindings_->JoinAppCode() blocks browser startup until init.ts signals process.appCodeLoaded(), which init.ts invokes after the main module loads (or after the ESM loader settles); this is what synchronizes Chromium startup with the app's JS. — [shell/browser/electron_browser_main_parts.cc#L378-L382](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_browser_main_parts.cc#L378-L382) [lib/browser/init.ts#L95-L120](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/init.ts#L95-L120)
- Renderer→main IPC: the mojom::ElectronApiIPC associated interface delivers Message/Invoke/MessageSync/ReceivePostMessage/MessageHost to ElectronApiIPCHandlerImpl, which resolves the Session from the RenderFrameHost's BrowserContext, builds an api::IpcMainEvent, and calls ipc_dispatch::Message/Invoke which emit on the JS objects registered via electron_browser_ipc_dispatch.setup({ipcMain, ipcMainInternal}). — [shell/browser/electron_api_ipc_handler_impl.cc#L48-L128](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L48-L128) [shell/browser/electron_api_ipc_handler_impl.cc#L152-L196](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/electron_api_ipc_handler_impl.cc#L152-L196) [lib/browser/ipc-dispatch.ts#L1-L7](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-dispatch.ts#L1-L7) [shell/common/api/api.mojom](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/api/api.mojom)
- ipcMain.handle registrations live in IpcMainImpl._invokeHandlers (a Map keyed by channel) which throws on duplicate handlers; handleOnce wraps handle + removeHandler. — [lib/browser/ipc-main-impl.ts#L5-L35](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/ipc-main-impl.ts#L5-L35)
- Main→renderer IPC: EmitIPCEvent in electron_ipc_native.cc looks up a hidden 'ipcNative' private binding on the v8 context (set by the renderer IPC setup), wraps {sender, ports} into an event object, and emits the channel on ipcRenderer or ipcRendererInternal inside a node::CallbackScope when a Node env exists. — [shell/renderer/electron_ipc_native.cc#L21-L36](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_ipc_native.cc#L21-L36) [shell/renderer/electron_ipc_native.cc#L40-L99](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_ipc_native.cc#L40-L99)
- Internal control messages ride reserved channels in the IPC_MESSAGES const enum (e.g. BROWSER_PRELOAD_ERROR re-emitted as 'preload-error' on webContents, BROWSER_GET_PROCESS_MEMORY_INFO returning the calling frame's own renderer pid stats) handled by lib/browser/rpc-server.ts. — [lib/common/ipc-messages.ts#L1-L14](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/ipc-messages.ts#L1-L14) [lib/browser/rpc-server.ts#L4-L14](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/rpc-server.ts#L4-L14)
- Preload flow: the browser pushes preload paths into RendererStartupData ahead of navigation (WebContents::MaybeSendRendererStartupData); ElectronRendererClient::DidCreateScriptContext creates a per-frame Node environment, defers document loading (LoaderFreezeMode::kStrict), and lib/renderer/init.ts loads CJS preloads via Module._load and .mjs preloads via runEntryPointWithESMLoader, then calls appCodeLoaded which triggers UndeferLoad. — [shell/renderer/electron_renderer_client.cc#L133-L204](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_renderer_client.cc#L133-L204) [shell/renderer/electron_renderer_client.cc#L128-L131](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/renderer/electron_renderer_client.cc#L128-L131) [lib/renderer/init.ts#L145-L180](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/renderer/init.ts#L145-L180)
- protocol.handle() converts the native ProtocolRequest into a WHATWG Request — rebuilding uploadData (rawData/file/stream/blob chunk types, blob data pulled via session.defaultSession.getBlobData) into a ReadableStream body — then converts the handler's Response back, with a fast path (relayUntouchedFetch) that hands an untouched net.fetch URL loader straight to Chromium instead of streaming through JS. — [lib/browser/api/protocol.ts#L58-L106](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L58-L106) [lib/browser/api/protocol.ts#L127-L150](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L127-L150) [lib/browser/api/protocol.ts#L175-L198](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/protocol.ts#L175-L198)
- net.fetch/session.fetch go through fetchWithSession in net-fetch.ts into Chromium's network stack under the session's NetworkContext (shell/browser/net/), so requests share the session's cookies, proxy and cache. — [lib/browser/api/net.ts#L16-L18](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/net.ts#L16-L18) [lib/browser/api/session.ts#L41-L43](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/session.ts#L41-L43) [lib/browser/api/net-fetch.ts](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/api/net-fetch.ts) [shell/browser/net/network_context_service.cc](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/browser/net/network_context_service.cc)
- Node module resolution is fenced: lib/node/init.ts overrides Module._nodeModulePaths so modules inside process.resourcesPath can only resolve node_modules inside the app, and patches child_process.fork to set ELECTRON_RUN_AS_NODE=1 (refusing outright when the runAsNode fuse is off). — [lib/node/init.ts#L6-L41](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L6-L41) [lib/node/init.ts#L77-L93](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/node/init.ts#L77-L93)
- The uv loop is demand-driven: lib/common/init.ts wraps process.nextTick, setImmediate, setTimeout and setInterval to call process.activateUvLoop() (bound to ElectronBindings::ActivateUVLoop, which uv_async_sends to OnCallNextTick) so Node callbacks fire even though Chromium owns the main loop. — [lib/common/init.ts#L8-L61](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/init.ts#L8-L61) [shell/common/api/electron_bindings.cc#L90-L111](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/shell/common/api/electron_bindings.cc#L90-L111)
- Guest <webview> data flow: a renderer frame registers the element, the browser's guest-view-manager maps guestInstanceId→GuestInstance (embedder WebContents + embedderFrame), and only the creating frame may drive the guest through GUEST_VIEW_MANAGER_* IPCs; webPreferences are parsed from the 'webpreferences' attribute string with security options force-inherited from the embedder. — [lib/browser/guest-view-manager.ts#L15-L30](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/guest-view-manager.ts#L15-L30) [lib/browser/guest-view-manager.ts#L32-L75](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/browser/guest-view-manager.ts#L32-L75) [lib/common/ipc-messages.ts#L7-L11](https://github.com/electron/electron/blob/56f681cfe08e1c6bf02cfad2807ff1c47ae13d4f/lib/common/ipc-messages.ts#L7-L11)

Every claim links to its cited files at the pinned commit. Citations identify source evidence; they do not establish runtime correctness. Independent CodeVetter scan — not reviewed by upstream maintainers.

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
