@syncraft-labs/vue

Vue 3 composables for Syncraft Labs - local-first state synchronization.
5,082
Install
npm install @syncraft-labs/vue
Latest Version:0.7.1
Vue:3
License:MIT
Last Updated:Oct 21, 2026
Links: GitHub  ·  npm
Maintainer: denislistiadi

@syncraft-labs/vue

The official Vue 3 bindings for Syncraft Labs - local-first state synchronization.


Purpose

@syncraft-labs/vue provides the useSync composable for Vue 3. It gives your Vue components instant optimistic writes, durable IndexedDB persistence, automatic background outbox sync, and cross-tab synchronization.

Built with Vue 3's shallowRef to safely integrate with proxy draft objects, preventing unnecessary deep reactivity proxying overhead while keeping your UI instantly synced. It relies on createSyncraft() plugin registration via provide/inject for complete store isolation in Nuxt 3 and SSR environments.

Installation

# npm
npm install @syncraft-labs/core @syncraft-labs/vue

# yarn
yarn add @syncraft-labs/core @syncraft-labs/vue

# pnpm
pnpm add @syncraft-labs/core @syncraft-labs/vue

Peer dependencies: Vue ≥ 3.3.0

Documentation

The Syncraft Labs documentation is available at syncraft-labs.web.id.

Basic Usage

Mount the createSyncraft() plugin in your root application (crucial for Nuxt 3 SSR request isolation), then consume state anywhere using useSync.

// main.ts - Install plugin for app-level store isolation
import { createApp } from "vue";
import { createSyncraft } from "@syncraft-labs/vue";
import App from "./App.vue";

const app = createApp(App);
app.use(createSyncraft());
app.mount("#app");
<!-- App.vue -->
<script setup lang="ts">
import { useSync } from "@syncraft-labs/vue";

interface TodoState {
  todos: Array<{ id: string; text: string; done: boolean }>;
}

const { data, update, isHydrating, isOffline, error } = useSync<TodoState>(
  "todos",
  { initialState: { todos: [] } }
);

function addTodo() {
  update((draft) => {
    draft.todos.push({
      id: crypto.randomUUID(),
      text: "New todo",
      done: false,
    });
  });
}
</script>

<template>
  <p v-if="isHydrating">Loading from cache...</p>

  <div v-else>
    <p v-if="isOffline">You're offline - changes saved locally</p>
    <p v-if="error">Error: {{ error.message }}</p>

    <button @click="addTodo">Add Todo</button>

    <ul>
      <li v-for="t in data?.todos" :key="t.id">
        {{ t.text }}
      </li>
    </ul>
  </div>
</template>

Remote Sync (Background Pushing)

Inject your API calls into the useSync options. Syncraft automatically queues mutations offline and drains the outbox using exponential backoff when connectivity is available.

<script setup lang="ts">
import { useSync } from "@syncraft-labs/vue";

const { data, update, refetch, isSyncing } = useSync<TodoState>("todos", {
  initialState: { todos: [] },

  // Fetch initial data (called once if DB is empty)
  fetcher: () => fetch("/api/todos").then((r) => r.json()),

  // Push pending mutations to your backend
  pusher: async (entries) => {
    await fetch("/api/sync", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(entries),
    });
  },

  // Polling interval in ms (default: 5000)
  syncInterval: 3000,
});
</script>

<template>
  <button @click="refetch" :disabled="isSyncing">
    {{ isSyncing ? "Syncing..." : "Refresh" }}
  </button>
</template>

Performance & Optimization

Selector-based Reactivity: Prevent over-rendering by passing a selector function. The composable will only trigger reactivity if the selected slice of data changes (using shallowRef internally).

const { data: doneTodos } = useSync("todos", {
  selector: (state) => state?.todos.filter((t) => t.done),
});

Developer Tools

Syncraft Labs exposes a global object window.__SYNCRAFT_DEVTOOLS__ in the browser. You can inspect all active local stores via window.__SYNCRAFT_DEVTOOLS__.stores.

API Reference

Export Type Description
createSyncraft() Plugin Vue plugin guaranteeing app-level store registry isolation across SSR requests
useSync<T>(key, options) Composable Primary Vue 3 composable returning reactive shallowRef state and updater
destroyStore(key) Function Destroys an active store instance by storage key
UseSyncOptions<T> Interface Configuration options (initialState?, fetcher?, pusher?, syncInterval?, selector?, onSyncStart?, onSyncSuccess?, onSyncError?, onRollback?, maxOutboxSize?, overflowStrategy?, onOverflow?, storageMode?, idField?)
UseSyncReturn<T> Interface Return values (data, update, refetch, isHydrating, isSyncing, isOffline, error)

License

MIT © Denis Listiadi

Related Packages

@vingy/vuebugger

Vue devtools plugin to debug anything.

15,686 8
@ozjsey/vue-write-behind

Write-behind cache for Vue 3 — local state stays authoritative, the server's rep...

1,216 0
@db-state/vue

Tiny reactive Vue 3 client for db-state: typed tables, listRef / idsRef / countR...

3,795 1
@laboverwire/stitch

Reactive state synchronization library bridging an in-memory store, IndexedDB pe...

1,156 2

Version History

Version Released License
0.7.1 MIT
0.7.0 MIT
0.6.0 MIT
0.5.0 MIT
0.4.2 MIT