supabase-offline-sync — community supabase-offline-sync, Steps-to-recovery, community, ide skills

v1.0.0

About this Skill

Perfect for Mobile App Agents needing seamless offline data synchronization with Supabase and SQLite Implement offline-first sync between Expo SQLite and Supabase with queue-based reconciliation. Use when building offline-first mobile apps, syncing local SQLite with cloud PostgreSQL, handling conflic

RipKDR RipKDR
[0]
[0]
Updated: 3/11/2026

Killer-Skills Review

Decision support comes first. Repository text comes second.

Reference-Only Page Review Score: 7/11

This page remains useful for operators, but Killer-Skills treats it as reference material instead of a primary organic landing page.

Original recommendation layer Concrete use-case guidance Explicit limitations and caution Locale and body language aligned
Review Score
7/11
Quality Score
33
Canonical Locale
en
Detected Body Locale
en

Perfect for Mobile App Agents needing seamless offline data synchronization with Supabase and SQLite Implement offline-first sync between Expo SQLite and Supabase with queue-based reconciliation. Use when building offline-first mobile apps, syncing local SQLite with cloud PostgreSQL, handling conflic

Core Value

Empowers agents to build offline-first Expo apps with a queue-based sync architecture, utilizing SQLite for local storage and Supabase for cloud synchronization, ensuring reliable data consistency across online and offline modes

Ideal Agent Persona

Perfect for Mobile App Agents needing seamless offline data synchronization with Supabase and SQLite

Capabilities Granted for supabase-offline-sync

Implementing offline data caching for mobile apps
Synchronizing local SQLite databases with Supabase in the background
Handling retry mechanisms for failed sync operations

! Prerequisites & Limits

  • Requires Supabase and SQLite integration
  • Expo app environment necessary
  • Queue-based sync architecture may introduce additional complexity

Why this page is reference-only

  • - The underlying skill quality score is below the review floor.

Source Boundary

The section below is imported from the upstream repository and should be treated as secondary evidence. Use the Killer-Skills review above as the primary layer for fit, risk, and installation decisions.

After The Review

Decide The Next Action Before You Keep Reading Repository Material

Killer-Skills should not stop at opening repository instructions. It should help you decide whether to install this skill, when to cross-check against trusted collections, and when to move into workflow rollout.

Labs Demo

Browser Sandbox Environment

⚡️ Ready to unleash?

Experience this Agent in a zero-setup browser environment powered by WebContainers. No installation required.

Boot Container Sandbox

FAQ & Installation Steps

These questions and steps mirror the structured data on this page for better search understanding.

? Frequently Asked Questions

What is supabase-offline-sync?

Perfect for Mobile App Agents needing seamless offline data synchronization with Supabase and SQLite Implement offline-first sync between Expo SQLite and Supabase with queue-based reconciliation. Use when building offline-first mobile apps, syncing local SQLite with cloud PostgreSQL, handling conflic

How do I install supabase-offline-sync?

Run the command: npx killer-skills add RipKDR/Steps-to-recovery/supabase-offline-sync. It works with Cursor, Windsurf, VS Code, Claude Code, and 19+ other IDEs.

What are the use cases for supabase-offline-sync?

Key use cases include: Implementing offline data caching for mobile apps, Synchronizing local SQLite databases with Supabase in the background, Handling retry mechanisms for failed sync operations.

Which IDEs are compatible with supabase-offline-sync?

This skill is compatible with Cursor, Windsurf, VS Code, Trae, Claude Code, OpenClaw, Aider, Codex, OpenCode, Goose, Cline, Roo Code, Kiro, Augment Code, Continue, GitHub Copilot, Sourcegraph Cody, and Amazon Q Developer. Use the Killer-Skills CLI for universal one-command installation.

Are there any limitations for supabase-offline-sync?

Requires Supabase and SQLite integration. Expo app environment necessary. Queue-based sync architecture may introduce additional complexity.

How To Install

  1. 1. Open your terminal

    Open the terminal or command line in your project directory.

  2. 2. Run the install command

    Run: npx killer-skills add RipKDR/Steps-to-recovery/supabase-offline-sync. The CLI will automatically detect your IDE or AI agent and configure the skill.

  3. 3. Start using the skill

    The skill is now active. Your AI agent can use supabase-offline-sync immediately in the current project.

! Reference-Only Mode

This page remains useful for installation and reference, but Killer-Skills no longer treats it as a primary indexable landing page. Read the review above before relying on the upstream repository instructions.

Upstream Repository Material

The section below is imported from the upstream repository and should be treated as secondary evidence. Use the Killer-Skills review above as the primary layer for fit, risk, and installation decisions.

Upstream Source

supabase-offline-sync

Install supabase-offline-sync, an AI agent skill for AI agent workflows and automation. Review the use cases, limitations, and setup path before rollout.

SKILL.md
Readonly
Upstream Repository Material
The section below is imported from the upstream repository and should be treated as secondary evidence. Use the Killer-Skills review above as the primary layer for fit, risk, and installation decisions.
Supporting Evidence

Supabase Offline-First Sync

Queue-based sync architecture for offline-first Expo apps using SQLite and Supabase.

Architecture Overview

Local Write → SQLite → Sync Queue → Background Worker → Supabase
                              ↑____________↓ (retry on failure)

Database Schema

Sync Queue Table

sql
1CREATE TABLE sync_queue ( 2 id INTEGER PRIMARY KEY AUTOINCREMENT, 3 table_name TEXT NOT NULL, 4 record_id TEXT NOT NULL, 5 operation TEXT NOT NULL CHECK (operation IN ('INSERT', 'UPDATE', 'DELETE')), 6 data TEXT, -- JSON string for INSERT/UPDATE 7 retry_count INTEGER DEFAULT 0, 8 error_message TEXT, 9 created_at INTEGER NOT NULL, 10 processed_at INTEGER 11); 12 13CREATE INDEX idx_sync_queue_created ON sync_queue(created_at); 14CREATE INDEX idx_sync_queue_processed ON sync_queue(processed_at) WHERE processed_at IS NULL;

Core Implementation

1. Queue Operations

typescript
1interface SyncQueueItem { 2 id?: number; 3 table_name: string; 4 record_id: string; 5 operation: 'INSERT' | 'UPDATE' | 'DELETE'; 6 data?: string; 7 retry_count: number; 8 created_at: number; 9} 10 11async function enqueueSync( 12 db: SQLiteDatabase, 13 table: string, 14 recordId: string, 15 operation: 'INSERT' | 'UPDATE' | 'DELETE', 16 data?: object, 17): Promise<void> { 18 await db.runAsync( 19 `INSERT INTO sync_queue (table_name, record_id, operation, data, retry_count, created_at) 20 VALUES (?, ?, ?, ?, 0, ?)`, 21 table, 22 recordId, 23 operation, 24 data ? JSON.stringify(data) : null, 25 Date.now(), 26 ); 27}

2. Process Queue

typescript
1async function processSyncQueue(db: SQLiteDatabase, supabase: SupabaseClient): Promise<void> { 2 const pending = await db.getAllAsync<SyncQueueItem>( 3 `SELECT * FROM sync_queue 4 WHERE processed_at IS NULL AND retry_count < 5 5 ORDER BY created_at ASC 6 LIMIT 50`, 7 ); 8 9 // Process DELETEs first to avoid FK conflicts 10 const deletes = pending.filter((p) => p.operation === 'DELETE'); 11 const others = pending.filter((p) => p.operation !== 'DELETE'); 12 13 for (const item of [...deletes, ...others]) { 14 try { 15 await processQueueItem(db, supabase, item); 16 } catch (error) { 17 await markFailed(db, item.id!, error.message); 18 } 19 } 20}

3. Process Individual Item

typescript
1async function processQueueItem( 2 db: SQLiteDatabase, 3 supabase: SupabaseClient, 4 item: SyncQueueItem, 5): Promise<void> { 6 const { error } = await supabase.from(item.table_name).upsert( 7 { 8 id: item.record_id, 9 ...(item.data ? JSON.parse(item.data) : {}), 10 updated_at: new Date().toISOString(), 11 }, 12 { onConflict: 'id' }, 13 ); 14 15 if (error) throw error; 16 17 // Mark as processed 18 await db.runAsync('UPDATE sync_queue SET processed_at = ? WHERE id = ?', Date.now(), item.id); 19}

React Integration

Sync Context Provider

typescript
1export function SyncProvider({ children }: { children: React.ReactNode }) { 2 const { db } = useDatabase(); 3 const { supabase } = useSupabase(); 4 const netInfo = useNetInfo(); 5 6 useEffect(() => { 7 if (!db || !supabase || !netInfo.isConnected) return; 8 9 // Sync on connection restore 10 const interval = setInterval(() => { 11 processSyncQueue(db, supabase); 12 }, 30000); // Every 30 seconds 13 14 return () => clearInterval(interval); 15 }, [db, supabase, netInfo.isConnected]); 16 17 return children; 18}

Optimistic Updates Pattern

typescript
1function useCreateJournal() { 2 const queryClient = useQueryClient(); 3 const { db } = useDatabase(); 4 5 return useMutation({ 6 mutationFn: async (entry: JournalEntry) => { 7 // 1. Save locally 8 await db.runAsync( 9 'INSERT INTO journal (id, encrypted_body, created_at) VALUES (?, ?, ?)', 10 entry.id, 11 await encryptContent(entry.content), 12 entry.created_at, 13 ); 14 15 // 2. Queue for sync 16 await enqueueSync(db, 'journal', entry.id, 'INSERT', entry); 17 18 return entry; 19 }, 20 onSuccess: () => { 21 queryClient.invalidateQueries({ queryKey: ['journal'] }); 22 }, 23 }); 24}

Conflict Resolution

Last-write-wins with server timestamp:

typescript
1async function resolveConflict(local: JournalEntry, remote: JournalEntry): Promise<JournalEntry> { 2 const localTime = new Date(local.updated_at).getTime(); 3 const remoteTime = new Date(remote.updated_at).getTime(); 4 5 return remoteTime > localTime ? remote : local; 6}

Background Sync (Expo)

typescript
1import * as BackgroundFetch from 'expo-background-fetch'; 2import * as TaskManager from 'expo-task-manager'; 3 4const SYNC_TASK = 'background-sync'; 5 6TaskManager.defineTask(SYNC_TASK, async () => { 7 const db = await openDatabase(); 8 const supabase = createClient(); 9 10 try { 11 await processSyncQueue(db, supabase); 12 return BackgroundFetch.BackgroundFetchResult.NewData; 13 } catch { 14 return BackgroundFetch.BackgroundFetchResult.Failed; 15 } 16}); 17 18async function registerBackgroundSync() { 19 await BackgroundFetch.registerTaskAsync(SYNC_TASK, { 20 minimumInterval: 15 * 60, // 15 minutes 21 stopOnTerminate: false, 22 startOnBoot: true, 23 }); 24}

Retry Strategy

Exponential backoff for failed items:

typescript
1async function markFailed(db: SQLiteDatabase, queueId: number, error: string): Promise<void> { 2 await db.runAsync( 3 `UPDATE sync_queue 4 SET retry_count = retry_count + 1, 5 error_message = ?, 6 created_at = ? -- Delay retry 7 WHERE id = ?`, 8 error, 9 Date.now() + Math.pow(2, retry_count) * 60000, // Exponential backoff 10 queueId, 11 ); 12}

Best Practices

  1. Process DELETEs first - Avoids foreign key constraint errors
  2. Batch operations - Process 50 items at a time
  3. Encrypt before sync - Never send plaintext sensitive data
  4. User-scoped sync - Always filter by user_id in Supabase RLS
  5. Retry limit - Max 5 retries before manual intervention
  6. Conflict timestamps - Use updated_at for last-write-wins

Related Skills

Looking for an alternative to supabase-offline-sync or another community skill for your workflow? Explore these related open-source skills.

View All

openclaw-release-maintainer

Logo of openclaw
openclaw

Your own personal AI assistant. Any OS. Any Platform. The lobster way. 🦞

333.8k
0
AI

widget-generator

Logo of f
f

Generate customizable widget plugins for the prompts.chat feed system

149.6k
0
AI

flags

Logo of vercel
vercel

The React Framework

138.4k
0
Browser

pr-review

Logo of pytorch
pytorch

Tensors and Dynamic neural networks in Python with strong GPU acceleration

98.6k
0
Developer