synclayer 0.2.0-beta.6 copy "synclayer: ^0.2.0-beta.6" to clipboard
synclayer: ^0.2.0-beta.6 copied to clipboard

A local-first sync SDK for Flutter with offline support, automatic conflict resolution, and real-time synchronization.

SyncLayer #

pub package

Build offline-first Flutter apps in minutes — Production-grade sync engine with automatic background synchronization and conflict resolution.

Works with REST APIs, Firebase, Supabase, Appwrite, or any custom backend.

⚠️ BETA VERSION - Ready for testing. APIs are stable but may evolve based on feedback. See changelog.


Why SyncLayer? #

Your users expect apps to work offline. But building sync is hard:

❌ Manual queue management
❌ Conflict resolution logic
❌ Network retry handling
❌ Version tracking

SyncLayer handles all of this for you.

// That's it. Your app now works offline.
await SyncLayer.init(
  SyncConfig(
    baseUrl: 'https://api.example.com',
    collections: ['todos'],
  ),
);

// Save works instantly (local-first)
await SyncLayer.collection('todos').save({
  'text': 'Buy groceries',
  'done': false,
});

// Auto-syncs in background when online
// Handles conflicts automatically
// Retries on failure

What You Get #

🚀 Local-First - Writes happen instantly to local storage
🔄 Auto-Sync - Background sync every 5 minutes (configurable)
📡 Offline Queue - Operations sync automatically when online
⚔️ Conflict Resolution - Last-write-wins, server-wins, or client-wins
🔌 Backend Agnostic - Works with REST, Firebase, Supabase, or custom backends
📦 Batch Operations - Save/delete multiple documents efficiently
👀 Reactive - Watch collections for real-time UI updates


Supported Backends #

Works With #

  • REST APIs (built-in adapter)
  • Firebase Firestore (copy adapter from GitHub)
  • Supabase (copy adapter from GitHub)
  • Appwrite (copy adapter from GitHub)
  • Custom backends (implement SyncBackendAdapter)

⚠️ Note: Platform adapters (Firebase, Supabase, Appwrite) are NOT in the pub.dev package.
You must copy them from the GitHub repository into your project.

Why? To keep the package lightweight and avoid forcing optional dependencies on all users.

📖 Setup guide: Platform Adapters Guide


Quick Start #

1. Add dependency #

dependencies:
  synclayer: ^0.2.0-beta.1

2. Initialize #

Option A: REST API (default)

import 'package:synclayer/synclayer.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  await SyncLayer.init(
    SyncConfig(
      baseUrl: 'https://api.example.com',
      syncInterval: Duration(minutes: 5),
      collections: ['todos', 'users'],
    ),
  );
  
  runApp(MyApp());
}

Option B: Firebase, Supabase, or Appwrite

⚠️ Important: Platform adapters are NOT included in the pub.dev package. You must copy them from GitHub.

Quick Install (Windows PowerShell):

# Create adapters folder
New-Item -ItemType Directory -Force -Path lib\adapters

# Download Firebase adapter
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/hostspicaindia/synclayer/main/lib/adapters/firebase_adapter.dart" -OutFile "lib\adapters\firebase_adapter.dart"

Or manually:

  1. Go to GitHub adapters folder
  2. Copy the adapter file (e.g., firebase_adapter.dart)
  3. Paste into your project at lib/adapters/firebase_adapter.dart

Then use it:

// 1. Add platform package to pubspec.yaml
dependencies:
  synclayer: ^0.2.0-beta.1
  cloud_firestore: ^5.7.0  # For Firebase

// 2. Import the adapter you copied
import 'adapters/firebase_adapter.dart';

// 3. Initialize
await Firebase.initializeApp();
await SyncLayer.init(
  SyncConfig(
    customBackendAdapter: FirebaseAdapter(
      firestore: FirebaseFirestore.instance,
    ),
    collections: ['todos'],
  ),
);

📖 Full setup guide: Platform Adapters Guide

3. Use it #

// Save (works offline)
final id = await SyncLayer.collection('todos').save({
  'text': 'Buy milk',
  'done': false,
});

// Get
final todo = await SyncLayer.collection('todos').get(id);

// Update (same as save with id)
await SyncLayer.collection('todos').save({
  'text': 'Buy milk',
  'done': true,
}, id: id);

// Delete
await SyncLayer.collection('todos').delete(id);

// Watch for changes (reactive UI)
StreamBuilder(
  stream: SyncLayer.collection('todos').watch(),
  builder: (context, snapshot) {
    final todos = snapshot.data ?? [];
    return ListView.builder(
      itemCount: todos.length,
      itemBuilder: (context, i) => Text(todos[i]['text']),
    );
  },
);

How It Works #

┌─────────────┐
│  Your App   │
└──────┬──────┘
       │ save()
       ▼
┌─────────────┐     ┌──────────────┐
│   SyncLayer │────▶│ Local Storage│  (Instant)
│             │     │    (Isar)    │
└──────┬──────┘     └──────────────┘
       │
       │ (Background)
       ▼
┌─────────────┐     ┌──────────────┐
│ Sync Engine │────▶│   Backend    │  (Auto-sync)
│   + Queue   │     │     API      │
└─────────────┘     └──────────────┘

Architecture:

  • SyncLayer - Main API (what you use)
  • Collections - Data abstraction (like tables)
  • SyncEngine - Background processor (handles sync)
  • Queue Manager - Retry logic and ordering
  • Conflict Resolver - Handles conflicts automatically

Example App #

See the Todo App example for a complete working app with:

  • Offline editing
  • Auto-sync when online
  • Conflict resolution
  • Real-time UI updates

Backend Integration #

SyncLayer works with any backend. You need two endpoints:

// Push: Receive changes from client
POST /sync/{collection}
Body: { recordId, data, version, updatedAt }

// Pull: Send changes to client
GET /sync/{collection}?since={timestamp}
Response: [{ recordId, data, version, updatedAt }]

See backend example for a complete Node.js implementation.


Advanced Features #

Batch Operations #

// Save multiple
await SyncLayer.collection('todos').saveAll([
  {'text': 'Task 1'},
  {'text': 'Task 2'},
  {'text': 'Task 3'},
]);

// Delete multiple
await SyncLayer.collection('todos').deleteAll([id1, id2, id3]);

Manual Sync #

// Trigger sync immediately (e.g., pull-to-refresh)
await SyncLayer.syncNow();

Conflict Resolution #

await SyncLayer.init(
  SyncConfig(
    baseUrl: 'https://api.example.com',
    conflictStrategy: ConflictStrategy.lastWriteWins, // Default
    // or: ConflictStrategy.serverWins
    // or: ConflictStrategy.clientWins
  ),
);

Event Monitoring #

SyncLayerCore.instance.syncEngine.events.listen((event) {
  switch (event.type) {
    case SyncEventType.syncStarted:
      print('Sync started');
      break;
    case SyncEventType.syncCompleted:
      print('Sync completed');
      break;
    case SyncEventType.conflictDetected:
      print('Conflict in ${event.collectionName}');
      break;
  }
});

Known Limitations #

This is an alpha release. Known issues:

  • ⚠️ Pull sync requires explicit collections configuration
  • ⚠️ Example backend uses in-memory storage (not production-ready)
  • ⚠️ Limited production testing (2 of 10 validation tests completed)
  • ⚠️ Basic error handling and retry logic
  • ⚠️ No built-in authentication or encryption

See CHANGELOG for details.


Roadmap #

  • ❌ Complete production validation tests
  • ❌ Persistent backend example
  • ❌ Custom conflict resolvers
  • ❌ Encryption support
  • ❌ WebSocket support for real-time sync
  • ❌ Firebase/Supabase adapters
  • ❌ Pagination for large datasets

vs Other Solutions #

Feature SyncLayer Drift Firebase Supabase
Offline-first
Backend agnostic
Auto-sync
Conflict resolution
Queue management
Custom backend

SyncLayer = Drift's offline-first + Firebase's auto-sync + Your own backend


Contributing #

Issues and PRs welcome! See CONTRIBUTING.md.


License #

MIT License - see LICENSE file.


Support #


Made with ❤️ by Hostspica

9
likes
160
points
103
downloads

Publisher

verified publisherhostspica.com

Weekly Downloads

A local-first sync SDK for Flutter with offline support, automatic conflict resolution, and real-time synchronization.

Homepage
Repository (GitHub)
View/report issues
Contributing

Documentation

Documentation
API reference

License

MIT (license)

Dependencies

appwrite, cloud_firestore, connectivity_plus, dio, flutter, isar, isar_flutter_libs, path_provider, supabase_flutter, uuid

More

Packages that depend on synclayer