Application configuration
Own desktop configuration, compose Expo projects, and preserve native identity.
Experimental source documentation
These guides describe the current source checkout. The published preview predates the recent API changes. See release status before choosing an SDK.
Spark-owned projects
Edit desktop.config.json; generated app.json is Expo's transport configuration. Universal projects use a generated app.config.js resolver. Retain the generated stable projectId: it scopes storage and runtime identity across app renames and builds.
{
"$schema": "./node_modules/@legendapp/spark/schema.json",
"projectId": "f478dff4-f9a1-4ff2-8096-64df89e1c470",
"name": "MyApp",
"version": "0.0.1",
"platforms": ["macos"],
"window": {
"size": { "width": 1000, "height": 700 },
"minSize": { "width": 500, "height": 300 },
"restoreBounds": true
},
"macos": { "bundleIdentifier": "com.example.myapp" }
}Sizes are outer-frame logical dimensions. AppKit-specific chrome is grouped under window.macos, including titleBar.trafficLights and backgroundMaterial. Portable defaults stay in window; native startup behavior stays in macos.lifecycle.
Spark owns identity, windows, document associations, update signing, helper bundles, and desktop lifecycle policy. Expo settings/plugins go in expo or expoByPlatform.<target>. Custom native settings may require an app-specific binary.
@legendapp/spark/config exports typed configuration/readers. toExpo validates untrusted Spark JSON. The schema supports editor checks; runtime validation also checks target, size, helper-path, and update relationships.
Existing Expo apps
From a prepared local SDK checkout:
npm run spark -- add desktop --project /absolute/path/to/ExistingExpoAppThe integration checks the installed Expo 54.0.37, React Native 0.81.6, and React 19.1.4 baseline before editing. Upgrading an incompatible app is separate work. It preserves the entry point, source, existing mobile/web scripts, and mobile native projects. Existing desktop script names are preserved, using spark:macos/spark:windows when needed.
Expo remains the source for app name/version and shared settings. The sidecar declares extends: "expo", stable identity, desktop platforms, and desktop options. withSparkExpo from /expo-config composes the existing config; ordinary Expo commands retain their mobile/web meaning. Spark commands select the desktop/shared session environment automatically.
Review generated integration files and run the app's existing checks. Automatic config composition has restrictions on export shapes, module format, and Metro/native config filenames. Existing desktop projects need explicit host composition. See the integration guide; preserving an Expo Router entry does not establish desktop Router support.
Metro and native discovery
Retain the generated wrappers and apply application customizations through them. For a Spark-owned project:
// metro.config.js
const { metroConfig } = require('@legendapp/spark/metro');
module.exports = metroConfig(__dirname);// react-native.config.js
module.exports = require('@legendapp/spark/native').nativeConfig(__dirname);For an existing Expo project, compose its configuration:
const { getDefaultConfig, withSparkMetro } = require('@legendapp/spark/metro');
const config = getDefaultConfig(__dirname);
module.exports = withSparkMetro(config);withSparkNative(existingConfig, __dirname) preserves app assets and native settings. withSparkMetro accepts asynchronous wrappers as well. /expo-metro and /universal were removed; use /metro.
Native lifecycle
The standard Spark AppDelegate owns React bootstrap and app event dispatch. macos.lifecycle.mainWindow can configure initial visibility, close behavior, and reopen policy. Native packages can opt into startup plugins and asynchronous quit handlers without replacing the app delegate. Link/include a plugin that must survive production pruning.
A hidden main window keeps the runtime alive; it does not make the app menu-bar-only. Runtime close/quit guards and document coordination own asynchronous application decisions. See native lifecycle and configuration details.