JS Plugins
JS plugins let you move backend-style logic out of React components and into dedicated JavaScript modules. Each exported async function becomes callable from app code as backend.<name>.<fn>().
Use JS plugins when you want a clean backend boundary without introducing Rust code.
JS plugins run inside the same Glyx JavaScript runtime as your app. They are great for orchestration and business logic, but they are not a security boundary.
JS plugins work on both engines — V8 (default) and QuickJS
(engine: "quickjs" in glyx.config) — including hot-reload during
glyx dev. Editing a plugin file re-registers its exports live on either
engine; no window restart needed.
When to use JS plugins
Use a JS plugin when you want to:
- Keep SQL, file workflows, or sync logic out of UI components
- Expose app-specific service functions through
backend.* - Reuse existing Glyx JS APIs like
db,fs,dialog, orstorage - Iterate quickly without adding a Rust build step
If you need native OS APIs, C/C++ bindings, or performance-critical code, see Native Extensions.
Scaffold a plugin
glyx generate plugin notesThis creates a plugin file such as:
src/plugins/notes.plugin.jsThe CLI also prints the plugins config snippet you need to add to glyx.config.ts or glyx.config.json.
Register the plugin
import { defineConfig } from '@glyx-dev/config'
export default defineConfig({
capabilities: { db: true },
plugins: [
{ entry: 'src/plugins/notes.plugin.js', name: 'notes' }
]
})entry: path to the plugin entry filename: namespace used from the app, such asbackend.notes.getAll()
See the full config reference at glyx.config.ts.
Write the plugin
import { db } from '@glyx-dev/react'
await db.open('app.db')
export async function getAll() {
return db.query('SELECT * FROM notes ORDER BY updated_at DESC')
}
export async function create(args) {
const { lastInsertId } = await db.run(
'INSERT INTO notes (title) VALUES (?)',
[args.title]
)
return { id: lastInsertId }
}Plugins usually:
- import built-in framework APIs from
@glyx-dev/react - export async functions
- return plain JSON-serializable values
Call from app code
import { backend } from '@glyx-dev/react'
const notes = await backend.notes.getAll()
await backend.notes.create({ title: 'New note' })At runtime:
- the plugin entry is bundled at startup
- each exported function is registered under the configured namespace
backend.notes.getAll()dispatches to the plugin'sgetAll()export
What plugins can access
JS plugins can call the same JavaScript-side framework APIs your app uses, including things like:
dbfsdialogstorageclipboard
Make sure the required capabilities are enabled in glyx.config.ts.
Plugin capabilities
Each plugin can declare the capabilities it requires. Glyx validates these at load time — the plugin is rejected if the app has not declared the same capability:
plugins: [
{
entry: 'src/plugins/notes.plugin.js',
name: 'notes',
capabilities: ['db', 'fs'], // must also appear in top-level capabilities
}
]This isn't a hard startup failure — a misconfigured plugin is silently
excluded from registration, with an error logged (not printed to the
console the app user sees). The app keeps running; backend.notes.getAll
simply won't exist, and calling it throws a plain "not a function" error
at the call site rather than a clear message pointing at the missing
capability. Watch the log output after adding a plugin capability to
confirm it actually registered.
An unknown capability name, or one the plugin declares but the app hasn't
enabled in capabilities, is never silently granted — the plugin is
dropped instead, so this is a fail-closed check, just not a loud one. This
still lets you audit which plugins require which permissions at a glance.
Hot reload in dev mode
During glyx dev, the CLI watches each plugin's entry file. When you save the file, the CLI:
- Re-bundles the plugin with Bun
- Re-evaluates the plugin IIFE in the running JS runtime (V8 or QuickJS)
- Replaces the registered
backend.<name>.*commands in place
No restart needed — changes to a plugin are live in under a second.
JS Plugins vs Native Extensions
Choose JS plugins for:
- app-specific workflows
- SQL helpers
- file orchestration
- business logic that benefits from fast iteration
Choose Native Extensions for:
- native OS integration
- heavy file processing
- C/C++ library bindings
- performance-critical work
If the feature feels like part of your app, start with a JS plugin. If it feels like part of the runtime, move it to a Native Extension.