🚧 Glyx is pre-release software. APIs may change before v1.0. Get started →
Documentation
Migration
From Electron

Migrating from Electron

Glyx targets Electron developers directly. This guide maps Electron concepts and APIs to their Glyx equivalents.

You don't need to rewrite your entire app at once. Glyx supports a side-by-side migration — run both apps from the same codebase during transition.

What changes

ElectronGlyxNotes
BrowserWindowglyxWindowSimilar API, no main/renderer split
ipcMain / ipcRendererNot neededNo process boundary
contextBridgeNot neededJS runs in the same process as native APIs
shell.openExternal()glyxWindow.openExternal(url) (requires shell)Opens http/https/mailto in the OS browser
dialog.showOpenDialog()dialog.openFile()
electron-storedb (SQLite) or @glyx-dev/storeMore powerful, SQL
node-fetchglobal fetch()
require('fs')fs from glyx
Notificationnotification
clipboardclipboard (text only)Images not yet supported
nativeTheme@glyx-dev/design useTheme()System dark mode detection
safeStoragecredentials or @glyx-dev/keychainOS keychain
autoUpdaterupdaterGitHub Releases for full binary updates; a self-hosted JSON manifest works too for JS-only hot patches
TraytraySystem tray icon with a native context menu
⚠️

There's no app.getPath()-style directory-lookup API today — no JS call returns the app's data/config/cache directory paths.

The big difference: no process split

Electron has a main process and renderer processes. IPC is required to cross the boundary. Glyx has one process — your React code and native APIs run together:

// Electron — renderer process, needs IPC
window.electron.ipcRenderer.invoke('read-file', path)
 
// Glyx — direct call, no IPC
const content = await fs.readText(path)

This eliminates the entire preload.js / contextBridge pattern.

Window management

// Electron
const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 1200, height: 800 })
win.loadFile('index.html')
 
// Glyx — glyx.config.ts
window: {
  width: 1200,
  height: 800,
}

Multiple windows:

// Glyx
import { glyxWindow } from '@glyx-dev/react'
 
async function openPreferences() {
  const win = await glyxWindow.create({
    title:  'Preferences',
    width:  600,
    height: 500,
  })
  // Pass initial data — the new window runs the same app bundle from
  // scratch, so it decides what to render itself (e.g. from this message
  // or from its own routing state), not from a `component` prop.
  win.send(JSON.stringify({ screen: 'preferences' }))
}

There's no component/loadFile-style prop — create() always opens a new window running your full app bundle from the top. Use win.send() + the child window's own message handling (or routing) to decide what it renders, instead of pointing create() at a specific component.

File dialogs

// Electron
const { dialog } = require('electron')
const result = await dialog.showOpenDialog({ properties: ['openFile'] })
const filePath = result.filePaths[0]
 
// Glyx
import { dialog } from '@glyx-dev/react'
const filePath = await dialog.openFile()

Storing data

// Electron + electron-store
const Store = require('electron-store')
const store = new Store()
store.set('theme', 'dark')
const theme = store.get('theme')
 
// Glyx — use db directly (both calls are async)
await db.run("INSERT OR REPLACE INTO settings VALUES ('theme', 'dark')")
const rows = await db.query("SELECT value FROM settings WHERE key = 'theme'")
const theme = rows[0]?.value

Or use @glyx-dev/store for a React-hook-based key-value store:

import { createStore } from '@glyx-dev/store'
 
const useSettings = createStore('settings', { theme: 'dark' })
 
// In a component:
const { state, set } = useSettings()
set({ theme: 'light' })

Menu bar / tray

Tray icons are supported via the tray API (requires the tray capability):

import { tray } from '@glyx-dev/react'
 
const id = tray.create(iconRgbaBytes, 16, 16, 'My App', [
  { id: 'show', label: 'Show Window' },
  { id: '',     separator: true },
  { id: 'quit', label: 'Quit' },
])

See the tray API reference for menu items, event polling, and the full example.

⚠️

There's no glyxWindow.show()/.focus() to bring a window to the foreground — those methods don't exist. The closest available primitive is glyxWindow.setMinimized(false), which un-minimizes but doesn't guarantee raising above other windows on every OS.

React migration

If your Electron app already uses React, migration is mostly:

  1. Replace react-dom rendering with render
  2. Replace DOM-dependent libraries with Glyx equivalents
  3. Replace window, document, localStorage with Glyx APIs
  4. Remove IPC code — call native APIs directly
  5. Replace electron-* packages with glyx equivalents
// Before (Electron + React DOM)
import ReactDOM from 'react-dom/client'
ReactDOM.createRoot(document.getElementById('root')!).render(<App />)
 
// After (Glyx)
import { render } from '@glyx-dev/react'
render(<App />)

What doesn't migrate

  • Browser DevTools extensions — use CDP via glyx dev --inspect instead
  • <webview> tag — Glyx has its own <WebView> component (native OS WebView2/WKWebView/WebKitGTK), gated by the webview capability, for the specific case of embedding real web content (an OAuth page, a third-party embed) — it's opt-in and separate from Glyx's own GPU-rendered UI, not a drop-in replacement for <webview>'s full API
  • Node.js require() — use the Glyx binding equivalents
  • Electron-specific npm packages (electron-updater, electron-builder) — replaced by glyx