🚧 Glyx is pre-release software. APIs may change before v1.0. Get started →
Documentation
Configuration
glyx.config.ts

glyx.config.ts

The single configuration file for your Glyx app. Lives at the project root and is executed by the CLI at build/dev time to produce a resolved JSON config.

import { defineConfig } from '@glyx-dev/config'
 
export default defineConfig({
  // ... all fields
})

defineConfig prints the resolved config as JSON to stdout when the file is executed. The CLI reads this output — do not add side effects to glyx.config.ts.


name

name?: string

Machine-readable app identifier. No spaces — use hyphens (e.g. 'my-notes').

Used by glyx build and glyx package as:

  • The output binary filename (my-notes.exe, my-notes.app)
  • The installer slug (my-notes-1.0.0-Setup.exe)
  • The macOS bundle ID prefix (com.glyx.my-notes)

This is the canonical name source. When name is set here, Glyx ignores Cargo.toml and package.json names for packaging purposes. If omitted, the CLI falls back to Cargo.toml name (native projects) or package.json name (JS-only).

name is intentionally separate from window.titlename is the machine slug (no spaces), window.title is the human-readable string shown in the title bar and can be anything.


version

version?: string

App version string, e.g. '1.2.0'. Exposed at runtime via updater.getVersion() and embedded in installer metadata.


engine

engine?: 'v8' | 'quickjs'

JsRuntime backend. Mutually exclusive — a build links exactly one; picking one drops the other's dependency from the binary entirely, it's not a runtime toggle.

  • 'v8' (default) — full-featured, larger binary (~58 MB floor on desktop). Supports the V8 snapshot fast-start path (glyx build --mode snapshot).
  • 'quickjs' — no JIT, ~3x smaller binary (a "Hello World" build measures ~20 MB vs. ~60 MB for the same app on V8). No snapshot fast-start — QuickJS has no equivalent mechanism, so --mode snapshot still runs but the snapshot step is a no-op for startup time. Better suited to size-constrained or mobile targets; noticeably slower than V8 for JS-heavy workloads (list-heavy UI reconciliation in particular).
export default defineConfig({
  engine: 'quickjs',
})

Read by glyx build/glyx dev/glyx runtime to select the --features v8 or --features quickjs build of glyx-runner (or, for native Rust projects, of your own crate). Omit to use the default ('v8').


app

Installer and store metadata. Used by glyx package when generating NSIS (Windows), DMG (macOS), and AppImage (Linux) installers.

app?: {
  publisher?:   string   // Company or author name shown in installer and OS app listings
  description?: string   // Short description of the app
  website?:     string   // App website URL, e.g. 'https://myapp.com'
  license?:     string   // Path to a license file, e.g. 'LICENSE.txt' — copied into the install directory
}

icon

icon?: string

Path to a PNG icon (512×512 or 1024×1024 recommended). Used as the window icon and in installers.


locales

locales?: string[]

ICU locale data to bundle. Controls which locales Intl.* and toLocaleString() format correctly — numbers, dates, times, currency, and plurals.

Defaults to ['en'] if omitted. Declare every locale your UI uses, and Glyx trims the bundled icudtl.dat down to just those locales at build time, keeping packaged apps light:

locales: ['en', 'de', 'ja'],

Locales you don't list still work, but they fall back to the root/English formatting data rather than their own locale-specific rules. Add a locale and rebuild to pick it up.

Locale data is trimmed during glyx build / glyx dev, not embedded in full. See the ICU data integration guide for how trimming works and how to verify the resulting icudtl.dat.


window

Controls the initial window appearance and rendering backend.

window?: {
  title?:       string
  width?:       number         // Default: 1280
  height?:      number         // Default: 800
  startupMode?: 'windowed' | 'maximized' | 'fullscreen'
  decorations?: boolean        // OS title bar (default: true). false = frameless window
  resizable?:   boolean        // User can resize the window (default: true). false = fixed size
  background?:  string         // GPU clear color before first JS frame: '#rrggbb' or '#rrggbbaa'
  renderMode?:  'auto' | 'gpu' | 'cpu' | 'skia' | 'direct2d'  // Rendering backend (default: 'auto')
  maxJsHeapMb?: number         // V8 heap cap in MB, 24–512 (default: auto — see below)
  preventDuplicateWindows?: boolean  // glyxWindow.create with an open title focuses it instead (default: false)
}

window.background

The GPU clear color shown before the first React frame renders. Match this to your app's root background color to eliminate the white flash on startup.

window: {
  background: '#1e1e2e',   // matches dark root background
}

window.decorations

Set to false for a frameless window with a custom title bar.

window: {
  decorations: false,
}

window.resizable

Set to false to lock the window at its configured width × height — no drag-to-resize, and maximize is disabled. Useful for fixed-layout tools like a calculator or a compact utility panel.

window: {
  width:      320,
  height:     480,
  resizable:  false,
}

window.renderMode

Controls the rendering backend:

ValueDescription
'auto'Pick per machine (default): TinySkia on integrated/no GPU, Vello on discrete GPUs
'skia'TinySkia CPU rasterizer + OS software present — no wgpu at all, ~35 MB RSS
'gpu'Vello GPU compute via wgpu (best visual quality for heavy 2D scenes, requires DX12/Metal/Vulkan)
'direct2d'Windows-only, experimental. OS/driver-managed Direct2D — GPU-accelerated output with TinySkia-like flat memory behavior, never selected by 'auto'. Falls back to 'skia' with a warning on non-Windows. See Rendering Backends.
'cpu'Vello's CPU fallback path — not recommended. It inherits Vello's scene-buffer memory cost without the GPU throughput that cost is meant to buy, landing worse on both memory and speed than 'skia'. Only useful where Vello's feature set is required but no GPU is available.

TinySkia can also be forced at runtime via the GLYX_CPU_RENDER=1 environment variable. Useful for CI, testing, or devices without a supported GPU. Canvas3D upgrades a TinySkia window to the wgpu present path automatically on first use (and releases it again after 60 s of 3D inactivity); Direct2D windows don't yet support this upgrade — Canvas3D content is skipped there (see the Direct2D section below).

See Rendering Backends for the full memory story.

window.maxJsHeapMb

Controls the maximum V8 JavaScript heap size. When omitted, Glyx auto-calculates based on the compiled bundle size:

ModeFormulaFloor
Productionbundle_size_mb × 1224 MB
Dev (glyx dev)same formula32 MB (higher floor for HMR churn)

The cap is always bounded to 512 MB maximum. Use an explicit value when the auto floor is too tight (e.g. a large dependency graph at small bundle size) or too generous (memory-constrained targets).

window: {
  maxJsHeapMb: 64,  // explicit cap — overrides auto-calculation
}

The cap prevents V8 from speculatively reserving the OS default (~1.5 GB). It does not pre-allocate that memory — V8 starts at 2 MB and grows on demand up to the cap.

window.preventDuplicateWindows

When true, glyxWindow.create({ title }) for a title that is already open focuses the existing window (restoring it if minimized) and resolves with its handle, instead of opening a twin. Child windows with distinct titles are never affected; per-call allowDuplicate: true or an explicit key give fine-grained control. See the window API.

window: {
  preventDuplicateWindows: true,
}

capabilities

Declares which system APIs your app can access. All capabilities are opt-in — undeclared APIs throw at runtime.

capabilities?: {
  // File system
  fs?:           { read?: string[]; write?: string[]; delete?: string[] }
 
  // Network
  network?:      { allow?: string[] }      // origin allowlist
 
  // Environment variables
  env?:          { allow?: string[] }      // variable name allowlist
 
  // Deep linking
  deeplink?:     { scheme: string; singleInstance?: boolean }
 
  // Simple toggles
  db?:           boolean    // SQLite
  dialog?:       boolean    // file/folder picker dialogs
  clipboard?:    boolean    // read/write clipboard
  notification?: boolean    // desktop notifications
  tray?: boolean             // system tray icons
  battery?:      boolean    // battery status
  usb?:          boolean    // USB device enumeration
  shell?:        boolean    // open external URLs via openExternal (shell.exec planned)
  mdns?:         boolean    // mDNS service discovery
  system?:       boolean    // OS info, displays, memory
  power?:        boolean    // sleep/wake events
  storage?:      boolean    // app data directory access
  gamepads?:     boolean    // gamepad/controller input
  globalShortcuts?: boolean // OS-level keyboard shortcuts
  credentials?:  boolean    // OS keychain (DPAPI/Keychain/Secret Service)
  audio?:        boolean    // audio playback
  video?:        boolean    // video playback
  camera?:       boolean    // camera capture
  microphone?:   boolean    // microphone recording
  ai?:           boolean    // local AI (embed, generate, transcribe)
  hid?:          boolean    // HID device access
  updater?:      boolean    // auto-updater
  crash?:        boolean    // crash reporting
}

File system scoping

Paths use glob patterns relative to the app's working directory:

capabilities: {
  fs: {
    read:   ['**'],             // read anywhere
    write:  ['documents/**'],   // write only under documents/
    delete: ['documents/trash/**'], // delete only under trash/
  },
}

delete is optional. When omitted it falls back to the write globs. Set it to [] to allow writes but deny all deletion.

Deep linking

capabilities: {
  deeplink: {
    scheme:          'myapp',  // handles myapp:// URLs
    singleInstance:  true,     // focus existing window instead of opening a new one
  },
}

dev

Build settings used by glyx dev and glyx build.

dev?: {
  entry?:  string    // JS entry point (default: 'src/app.jsx')
  output?: string    // Compiled bundle path (default: 'dist/app.js')
  watch?:  string[]  // Directories to watch for HMR (default: ['src'])
}

The CLI bundles entryoutput on file changes. The output file is loaded by the Glyx runtime at startup.

dist/ is gitignored by default in new projects. Commit your source but not the compiled bundle. Native projects use ui/app.jsx as the entry — override dev.entry accordingly.


splash

Optional splash screen shown during JS startup.

splash?: {
  image?:      string   // Path to a PNG image, centered on the splash background
  background?: string   // Hex color, e.g. '#1e1e2e'. Defaults to black
  minimumMs?:  number   // Minimum display time before hideSplash() takes effect
  imageScale?: number   // Max fraction of the smaller window dimension `image` may fill (default 0.5)
}

imageScale matters more than it looks. A full-bleed source image (an app icon with no transparent margin, for example) will otherwise scale up to fill nearly the entire window under the default fit-to-bounds behavior, visually swallowing background — it'll read as "a giant icon crammed into the window," not a small centered logo. The default (0.5) caps the image at half the smaller window dimension regardless of the source image's own shape. Raise it toward 1.0 only for an image intentionally designed as a full splash background.

Call glyxWindow.hideSplash() from JS when your app is ready:

import { glyxWindow } from '@glyx-dev/react'
 
// After your data loads:
glyxWindow.hideSplash()

A 30-second safety timeout auto-hides the splash if hideSplash() is never called.


updater

Target GitHub repo for the auto-updater's updater.check()/updater.update(). Requires capabilities.updater: true too — this block is app metadata (where to check), the capability flag is the permission gate (whether checking is allowed at all).

updater?: {
  owner:   string   // GitHub organization or username
  repo:    string   // Repository name
  binName: string   // Release asset filename prefix — matches `{binName}-{platform}`,
                     // exactly what `glyx package` produces
}
glyx.config.json
{
  "capabilities": { "updater": true },
  "updater": {
    "owner":   "acme-inc",
    "repo":    "my-app",
    "binName": "my-app"
  }
}

Read once at startup from glyx.config.json — not baked into the binary at compile time. Without this block, updater.check()/updater.update() reject with "Update origin not configured" regardless of the updater capability. See the updater API reference for the full signing/trust model.


plugins

JS plugin extensions. Each plugin's exported async functions become callable via backend.<name>.<fn>() from JS.

plugins?: Array<{
  entry:          string    // Path to the plugin JS entry point (bundled at startup)
  name?:          string    // Optional namespace prefix for the plugin's commands
  capabilities?:  string[]  // Capabilities the plugin requires
}>
plugins: [
  { entry: 'plugins/storage.js', name: 'storage' },
  { entry: 'plugins/analytics.js', name: 'analytics' },
]

See JS Plugins for how to write a plugin.


packageManager

packageManager?: 'npm' | 'pnpm' | 'yarn' | 'bun'

Override the package manager used by the CLI for installs, scripts, and bundling. When omitted, the CLI auto-detects from the lockfile. See Package manager support.


Full example

import { defineConfig } from '@glyx-dev/config'
 
export default defineConfig({
  name:    'my-notes',
  version: '1.0.0',
  // engine: 'quickjs',  // uncomment for a smaller, no-JIT build (default: 'v8')
 
  app: {
    publisher:   'Acme Corp',
    description: 'A fast, native notes app.',
    website:     'https://myapp.com',
    license:     'LICENSE.txt',
  },
 
  icon: 'assets/icon.png',
 
  locales: ['en'],
 
  window: {
    title:       'My Notes',
    width:       1200,
    height:      800,
    startupMode: 'windowed',
    background:  '#171923',
    decorations: true,
    resizable:   true,
    renderMode:  'auto',
    // maxJsHeapMb: 64,   // uncomment to override the auto-calculated heap cap
  },
 
  capabilities: {
    fs:           { read: ['**'], write: ['documents/**'], delete: ['documents/trash/**'] },
    network:      { allow: ['https://api.myservice.com'] },
    db:           true,
    dialog:       true,
    clipboard:    true,
    notification: true,
    credentials:  true,
    crash:        true,
    deeplink:     { scheme: 'mynotes', singleInstance: true },
  },
 
  dev: {
    entry:  'src/app.jsx',
    output: 'dist/app.js',
    watch:  ['src'],
  },
 
  splash: {
    background: '#171923',
    minimumMs:  800,
  },
})