Getting Started
From zero to a native app running your Solid code in about three minutes (plus one coffee while the toolchain warms).
Prerequisites
- bun 1.2+ — runs the CLI, the bundler, and your tests
- Flutter 3.41+ — the rendering host (
flutter doctorshould be green for your targets) - Xcode for iOS/macOS, or an Android SDK + emulator for Android
Create an app
$ npm create skal my-app $ cd my-app
The scaffold is a complete, runnable project:
my-app/ ├── src/ │ ├── App.jsx # your Solid app — edit this │ └── index.jsx # entry: mounts <App/> on the bridge renderer ├── flutter-host/ # platform shells (android/ios/macos) + libskal ├── .maestro/smoke.yaml # E2E smoke test, ready to run └── package.json # dev / build / test scripts
Run it
$ npm i -g @skal/cli # once — or use `bun run dev:<target>` directly $ skal dev macos # fastest loop for UI work $ skal dev android # boots an emulator automatically if none is attached $ skal dev ios # iOS Simulator $ skal dev web # Solid → DOM at localhost:5173
skal dev builds the JS bundle and launches the platform host. Add --hot and the hot-reload server pushes every save under src/ straight into the running app — navigation and hot state survive.
Make it yours
Open src/App.jsx. It's plain SolidJS — signals, memos, effects, <For>, <Show> — with Skal's widget set instead of DOM tags:
import { createSignal } from 'solid-js'; import { Column, Text, Button } from 'skal'; export default function App() { const [name, setName] = createSignal('Skal'); return ( <Column padding={24} gap={16}> <Text label={`Hello, ${name()}`} fontSize={28} fontWeight={800} /> <Button label="Skål 🍻" onClick={() => setName('World')} /> </Column> ); }
When a signal changes, Solid updates exactly the widgets that read it — no virtual DOM, no reconciliation pass. The change crosses to Flutter as a handful of binary ops in shared memory. See Components for the full widget set.
Ship it
$ skal build android # release APK, JSC bytecode cache baked in $ skal build ios # release build for TestFlight $ skal build macos $ skal build web # static site bundle
Release builds compile your bundle to JavaScriptCore bytecode, so production cold starts skip the JS parser entirely — that's the 36 ms first-eval.
Where next
- Architecture — what actually happens between a signal and a pixel
- State & the Store — persistent state with the native store engine
- Wrapping pub.dev packages — camera, geolocation, anything native
- Hot reload & dev loop — sub-second reload, what state survives
- Testing — unit tests, the headless harness, Maestro E2E