🚧 VeloxKit is pre-release software. APIs may change before v1.0. Get started →
Documentation
Packages
@velox/store

@velox/store Stable

Persistent reactive state backed by SQLite. In-memory reads are instant; writes survive app restarts.

Requires capability: "db"

Install

npm install @velox/store

Setup

Call initStore() once at app startup before any components render:

// src/main.ts
import { createApp } from 'veloxkit'
import { initStore } from '@velox/store'
import App from './App'
 
async function start() {
  await initStore()
  createApp({ component: App })
}
 
start()

Define a store

// src/stores/settings.ts
import { createStore } from '@velox/store'
 
export const useSettings = createStore('settings', {
  theme:         'dark',
  fontSize:      14,
  notifications: true,
})

createStore(namespace, defaults) returns a React hook. The namespace is the SQLite partition key — use a unique string per store. The defaults object also determines which keys are valid.

Use in components

import { useSettings } from '../stores/settings'
import { Switch, Text, View } from 'veloxkit'
 
function SettingsScreen() {
  const { state, set, hydrated } = useSettings()
 
  if (!hydrated) return null   // waiting for SQLite read on first mount
 
  return (
    <View style={{ padding: 24, gap: 16 }}>
      <Switch
        value={state.notifications}
        onValueChange={(v) => set('notifications', v)}
        label="Push notifications"
      />
      <Text>Font size: {state.fontSize}</Text>
    </View>
  )
}

API

initStore()

await initStore()

Creates the velox_store SQLite table if it doesn't exist. Idempotent — safe to call multiple times.

createStore(namespace, defaults)

const useMyStore = createStore('my-namespace', { key: defaultValue, ... })

Returns a React hook. Multiple calls with the same namespace return the same hook instance (singleton).

Hook return value

const { state, set, setMany, reset, hydrated } = useMyStore()
FieldTypeDescription
statetypeof defaultsCurrent state (in-memory, instant)
set(key, value)voidUpdate a single key synchronously; persists async
setMany(patch)voidUpdate multiple keys at once
reset()Promise<void>Restore defaults and delete all persisted values
hydratedbooleanfalse until first SQLite read completes

set updates in-memory state synchronously, triggering an immediate re-render. The SQLite write is async and fire-and-forget.

TypeScript

const useSettings = createStore('settings', {
  theme:    'dark' as 'dark' | 'light',
  fontSize: 14,
})
 
// typeof state inferred from defaults:
// { theme: 'dark' | 'light', fontSize: number }

Multiple stores

export const useSettings = createStore('settings', { theme: 'dark', fontSize: 14 })
export const useEditor   = createStore('editor',   { wordWrap: true, tabSize: 2 })
export const useSync     = createStore('sync',     { lastSync: 0, enabled: false })

Each namespace is independent — they share the same SQLite table but different partition keys.