FlutterFever Studio
Back to packages

Zeytin Local Storage Flutter package guide

A lightweight, type‑safe local database for Flutter apps, offering seamless sync with server‑side Zeytin instances.

Install command
Copy and run in your Flutter project
flutter pub add zeytin_local_storage

When to use Zeytin Local Storage

Zeytin Local Storage is a Flutter‑first library that brings a simple, performant, and type‑safe key‑value store to mobile, desktop, and web platforms. Built on top of the native storage engines of each platform (SQLite on Android/iOS, IndexedDB on web, and file‑based storage on desktop), it abstracts away the boilerplate of serialization, migration, and concurrency, letting developers focus on business logic. The package follows the same data model used by the Zeytin server, which means you can write a single data schema and reuse it both locally and remotely, reducing duplication and the risk of mismatched types.

When to choose Zeytin Local Storage? It shines in apps that need offline‑first capabilities, such as note‑taking, task management, or e‑commerce carts, where users expect their data to persist across sessions and network interruptions. Because the API mirrors the server‑side SDK, you can implement a transparent sync layer that pushes local changes to the cloud when connectivity is restored, without rewriting data models. The library also supports custom migrations, allowing you to evolve your schema safely as your app grows.

From an architectural standpoint, Zeytin Local Storage fits neatly into the data layer of a clean‑architecture or MVVM setup. It can act as the concrete implementation of a repository interface, while higher layers (use‑cases, view‑models, or BLoC) remain agnostic of the storage details. The package exposes a reactive `Stream` API for query results, making it compatible with state‑management solutions that rely on streams, such as Riverpod, Provider, or BLoC. This reactivity also enables UI widgets to rebuild automatically when underlying data changes, providing a smooth user experience.

Getting started is straightforward. After adding the dependency with `flutter pub add zeytin_local_storage`, you initialize the storage in your `main` function, optionally providing a custom directory for desktop or web. The library offers a fluent builder for defining tables, indexes, and relationships, and it automatically generates type‑safe getters and setters based on your model classes. For most projects, a few lines of code are enough to open a database, insert a record, and listen for updates. The documentation includes a step‑by‑step guide for setting up sync with a remote Zeytin server, but the core local functionality works out of the box without any backend configuration.

Production‑grade considerations include handling database encryption, managing migration scripts, and monitoring storage size. Zeytin Local Storage supports optional AES‑256 encryption for sensitive data, and its migration API lets you write incremental version upgrades that run safely on app start. The package also provides utilities to compact the database and purge stale entries, which is useful for long‑running apps that accumulate large amounts of data. Developers should test migration paths on real devices and consider fallback strategies for corrupted databases, such as automatic backup restoration.

For beginners, the library offers a concise example that demonstrates creating a `Todo` model, inserting a task, and reacting to changes in a Flutter widget. The API is intentionally minimalistic: you work with plain Dart objects, and the library handles serialization behind the scenes. This lowers the learning curve compared to raw SQLite or Hive, while still delivering comparable performance. Whether you are building a hobby project or a production‑grade enterprise app, Zeytin Local Storage gives you a reliable foundation for local persistence and effortless cloud sync.

offline‑first note taking
shopping cart persistence
user preferences and settings
caching API responses
temporary data for wizard flows

Pros

  • type‑safe API
  • single source of truth for local and remote
  • built‑in encryption
  • reactive query streams
  • cross‑platform support

Watch outs

  • requires manual migration scripts for schema changes
  • no built‑in UI editor
  • sync logic must be implemented by the developer

Setup notes

1. Run `flutter pub add zeytin_local_storage` in your project root. 2. Import the package: `import 'package:zeytin_local_storage/zeytin_local_storage.dart';` 3. Initialize the database early, e.g., in `main()`: ```dart await ZeytinLocalStorage.initialize( dbName: 'my_app.db', version: 1, ); ``` 4. Define your data models and register them with the storage builder. 5. (Optional) Enable encryption by providing an `encryptionKey` during initialization. 6. For web or desktop, ensure the appropriate storage permissions are granted.

Supports Flutter 3.0+ on Android, iOS, macOS, Windows, Linux, and Web. Requires Dart 2.17 or newer. On iOS, the database file is stored in the app's Documents directory; on Android, it uses the app's internal storage. Web uses IndexedDB, which may have size limits depending on the browser. Desktop platforms require file system access; ensure the app has write permissions on the target directory.

```dart
import 'package:flutter/material.dart';
import 'package:zeytin_local_storage/zeytin_local_storage.dart';

// Define a simple model
class Todo extends ZeytinModel {
  final String id;
  final String title;
  final bool completed;

  Todo({required this.id, required this.title, this.completed = false});

  @override
  Map<String, dynamic> toMap() => {
        'id': id,
        'title': title,
        'completed': completed ? 1 : 0,
      };

  factory Todo.fromMap(Map<String, dynamic> map) => Todo(
        id: map['id'] as String,
        title: map['title'] as String,
        completed: (map['completed'] as int) == 1,
      );
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await ZeytinLocalStorage.initialize(dbName: 'todos.db', version: 1);
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: const Text('Zeytin Todos')),
        body: const TodoList(),
        floatingActionButton: FloatingActionButton(
          onPressed: () async {
            final newTodo = Todo(id: UniqueKey().toString(), title: 'New task');
            await ZeytinLocalStorage.instance.insert(newTodo);
          },
          child: const Icon(Icons.add),
        ),
      ),
    );
  }
}

class TodoList extends StatelessWidget {
  const TodoList({super.key});

  @override
  Widget build(BuildContext context) {
    return StreamBuilder<List<Todo>>(
      stream: ZeytinLocalStorage.instance.watch<Todo>(),
      builder: (context, snapshot) {
        final todos = snapshot.data ?? [];
        return ListView.builder(
          itemCount: todos.length,
          itemBuilder: (context, index) {
            final todo = todos[index];
            return ListTile(
              title: Text(todo.title),
              trailing: Checkbox(
                value: todo.completed,
                onChanged: (value) async {
                  final updated = Todo(
                    id: todo.id,
                    title: todo.title,
                    completed: value ?? false,
                  );
                  await ZeytinLocalStorage.instance.update(updated);
                },
              ),
            );
          },
        );
      },
    );
  }
}
```

Official package resources