supabase_easy 0.0.6
supabase_easy: ^0.0.6 copied to clipboard
Supabase wrapper for Flutter that cuts Auth, CRUD, real-time, and Storage boilerplate by 60–70%. Type-safe, zero config, single import.
supabase_easy #
A thin, type-safe Flutter wrapper around supabase_flutter that cuts Auth, CRUD, real-time, and Storage boilerplate by 60–70% — without hiding any power.
Why supabase_easy? #
Without supabase_easy |
With supabase_easy |
|---|---|
Repeated Supabase.instance.client.from(...) |
todoRepo.getAll() |
Manual PostgrestException catching everywhere |
One EasyException type across all APIs |
Writing select, insert, update, delete, .single() every time |
9 ready-made repository methods |
| Re-implementing count, bulk-delete, search | count(), deleteMany(), updateWhere() built-in |
| Hand-rolling auth try/catch blocks | EasyAuth.signIn / signOut / signInWithOtp etc. |
Features #
- Single import —
import 'package:supabase_easy/supabase_easy.dart' EasyAuth— email/password, OAuth, magic-link/OTP, password reset, session refreshEasyRepository<T>— generic type-safe CRUD, bulk ops, search, pagination, real-time streamsEasyStorage— upload (File or bytes), download, delete, signed URLs, image transformsEasyException— one exception type wrappingPostgrestException,AuthException,StorageException- Full DartDoc on every public API
Screenshots #
| Login & Signup | Task Management |
|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
Getting Started #
1. Add dependency #
dependencies:
supabase_easy: ^0.0.6
2. Supabase project checklist #
- Create a project at supabase.com.
- Create your tables and enable Row Level Security (RLS).
- Copy your Project URL and Anon Key from Settings › API.
Security tip: Never hardcode credentials. Pass them at build time:
flutter run \ --dart-define=SUPABASE_URL=https://xyz.supabase.co \ --dart-define=SUPABASE_ANON_KEY=your_anon_key
3. Initialise (once, in main()) #
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await SupabaseEasy.initialize(
url: const String.fromEnvironment('SUPABASE_URL'),
anonKey: const String.fromEnvironment('SUPABASE_ANON_KEY'),
);
runApp(const MyApp());
}
Usage #
EasyAuth #
// Email + password
await EasyAuth.signUp(email: 'user@example.com', password: 'secret');
await EasyAuth.signIn(email: 'user@example.com', password: 'secret');
await EasyAuth.signOut();
// Magic link / OTP
await EasyAuth.signInWithOtp(email: 'user@example.com');
await EasyAuth.verifyOtp(email: 'user@example.com', token: '123456');
// OAuth (Google, GitHub, …)
await EasyAuth.signInWithOAuth(OAuthProvider.google);
// Helpers
print(EasyAuth.isSignedIn); // bool
print(EasyAuth.currentUser?.id); // String?
// React to auth changes
StreamBuilder<AuthState>(
stream: EasyAuth.onAuthStateChange,
builder: (context, snapshot) { ... },
);
EasyRepository #
Define a model:
class Todo extends EasyModel {
@override final String id;
final String title;
final bool isDone;
Todo({required this.id, required this.title, this.isDone = false});
@override
Map<String, dynamic> toJson() =>
{'id': id, 'title': title, 'is_done': isDone};
factory Todo.fromJson(Map<String, dynamic> json) => Todo(
id: json['id'] as String,
title: json['title'] as String,
isDone: json['is_done'] as bool? ?? false,
);
}
Use the repository:
final repo = EasyRepository<Todo>(
tableName: 'todos',
fromJson: Todo.fromJson,
);
// --- Read ---
final all = await repo.getAll();
final done = await repo.getAll(filter: {'is_done': true});
final paged = await repo.getAll(orderBy: 'created_at', limit: 20, from: 0, to: 19);
final search = await repo.getAll(searchColumn: 'title', searchQuery: 'milk');
final single = await repo.getById('some-uuid'); // returns null if missing
final total = await repo.count();
// --- Write ---
final created = await repo.create(Todo(id: 'uuid', title: 'Buy milk'));
final updated = await repo.update(created.copyWith(isDone: true));
final upserted = await repo.upsert(todo);
// Bulk operations
await repo.createMany([todo1, todo2]);
await repo.deleteMany(['id-1', 'id-2']);
await repo.updateWhere(
filter: {'is_done': true},
data: {'archived': true},
);
await repo.delete('some-uuid');
// --- Real-time ---
StreamBuilder<List<Todo>>(
stream: repo.stream(primaryKey: ['id'], orderBy: 'created_at'),
builder: (context, snapshot) {
final todos = snapshot.data ?? [];
return ListView.builder(...);
},
);
EasyStorage #
// Upload
await EasyStorage.upload(
bucketId: 'avatars',
path: 'user_123.png',
file: File('/path/to/image.png'), // from dart:io
// bytes: imageBytes, // or raw Uint8List
options: const FileOptions(upsert: true),
);
// Public URL (with optional image transform)
final url = EasyStorage.getPublicUrl(
bucketId: 'avatars',
path: 'user_123.png',
transform: TransformOptions(width: 200, height: 200),
);
// Signed URL for private buckets
final signed = await EasyStorage.createSignedUrl(
bucketId: 'private-docs',
path: 'report.pdf',
expiresIn: 3600, // 1 hour
);
// Download / delete / list / move / copy
final bytes = await EasyStorage.download(bucketId: 'avatars', path: 'user_123.png');
await EasyStorage.delete(bucketId: 'avatars', paths: ['user_123.png']);
final files = await EasyStorage.list(bucketId: 'avatars', path: 'subfolder/');
Error handling #
Every method throws EasyException — one type for all Supabase errors:
try {
await EasyAuth.signIn(email: email, password: password);
} on EasyException catch (e) {
print(e.message); // human-readable
print(e.cause); // original AuthException / PostgrestException / etc.
}
OAuth & Storage setup #
OAuth (Google, GitHub, …)
- Go to Auth › Providers and enable desired providers.
- Add your deep-link URL (e.g.
io.supabase.flutter://callback) to Auth › URL Configuration › Redirect URLs. - Follow the Supabase social login guide for Android/iOS deep-link config.
Storage buckets
- Create buckets in Storage › Buckets.
- Add RLS policies:
- Public read:
Allow SELECT for everyone - Authenticated upload:
Allow INSERT for authenticated users
- Public read:
- Mark a bucket Public for
getPublicUrlto work without a signed URL.
API reference #
| Class | Key members |
|---|---|
SupabaseEasy |
initialize(), isInitialized |
EasyAuth |
signUp, signIn, signOut, signInWithOAuth, signInWithOtp, verifyOtp, resetPassword, updateUser, refreshSession, currentUser, isSignedIn, onAuthStateChange |
EasyRepository<T> |
getAll, getById, count, create, createMany, update, updateWhere, upsert, delete, deleteMany, stream |
EasyStorage |
upload, download, delete, getPublicUrl, createSignedUrl, list, move, copy, bucket |
EasyException |
message, cause |
Example app #
See the example/ folder for a full Todo app — auth, CRUD, and real-time all wired up.
License #
MIT — see LICENSE.




