FlutterFever Studio
Back to packages

Supabase Flutter package guide

Flutter SDK for Supabase, providing auth, realtime, storage and edge functions in a single, idiomatic package.

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

When to use Supabase Flutter

Supabase Flutter is a first‑party Dart SDK that brings the full power of Supabase’s open‑source backend to Flutter applications. It wraps Supabase’s RESTful API, realtime WebSocket layer, authentication flow and storage bucket handling into a set of type‑safe, Flutter‑friendly classes. By handling token refresh, session persistence, and error mapping internally, the package lets developers focus on UI and business logic rather than low‑level HTTP plumbing. Whether you are building a simple to‑do list or a complex SaaS product, Supabase Flutter provides the building blocks for secure, real‑time, and scalable back‑ends without managing your own server infrastructure.

The package shines when you need a backend‑as‑a‑service solution that mirrors the developer experience of Firebase but with an open‑source PostgreSQL core. It integrates seamlessly with Flutter’s reactive widget tree: you can listen to realtime changes via streams, fetch data with async/await, and manage authentication state with simple listeners. In a typical clean architecture, Supabase Flutter lives in the data layer, exposing repositories that return domain models. This separation makes it easy to swap out the backend for testing or future migration while keeping UI code untouched. The SDK also supports edge functions, allowing you to invoke server‑side logic directly from the client, which is ideal for tasks like payment processing or custom validation.

Getting started is straightforward. After adding the dependency, you initialise the client with your Supabase URL and anon/public key, usually in the app’s entry point. The client persists the session using Flutter’s secure storage, automatically refreshing JWTs before they expire. From there, you can call `supabase.auth.signInWithPassword`, `supabase.from('todos').select()`, or `supabase.storage.from('avatars').upload()` with just a few lines of code. The SDK’s built‑in error handling surfaces Supabase‑specific error codes, making debugging easier. For state management, you can pair the streams with Provider, Riverpod, Bloc, or any other pattern you prefer, giving you full flexibility in how you architect your app.

When moving to production, consider a few cautions. First, enable Row Level Security (RLS) policies in your Supabase project to protect data; the SDK respects these policies but does not enforce them for you. Second, monitor realtime subscription limits and clean up listeners to avoid memory leaks, especially on long‑running apps. Third, store your service role key securely on a server‑side component; never embed it in the client bundle. Finally, test token refresh flows on both iOS and Android, as background execution can affect the timing of JWT renewal. Following these best practices ensures a robust, secure experience for end users.

For beginners, Supabase Flutter offers a low‑code path to common app features: user sign‑up/sign‑in, password reset, email verification, and social logins are all one‑liner calls. Real‑time lists, chat rooms, or collaborative documents can be built by subscribing to a table’s changes and rebuilding widgets on each update. File uploads and downloads are handled through the storage API, which integrates with Flutter’s image picker and file picker packages. In short, the SDK removes the heavy lifting of backend integration, letting new Flutter developers ship production‑grade apps faster while still giving seasoned engineers the control they need for complex scenarios.

user authentication and session management
real‑time collaborative lists or chat
file uploads and media storage
server‑side business logic via edge functions
quick MVPs with a managed PostgreSQL backend

Pros

  • open‑source and self‑hostable
  • type‑safe Dart API
  • single SDK for auth, realtime, storage, functions
  • good documentation and community examples
  • cross‑platform support

Watch outs

  • relies on external Supabase service unless self‑hosted
  • advanced RLS policies require backend knowledge
  • real‑time subscription limits on free tier

Setup notes

1. Add the dependency: `flutter pub add supabase_flutter` 2. Run `flutter pub get` to fetch the package. 3. Initialise the client early, e.g., in `main()`: ```dart await Supabase.initialize( url: 'https://your-project.supabase.co', anonKey: 'public-anon-key', ); ``` 4. Optionally configure secure storage for session persistence. 5. Import with `import 'package:supabase_flutter/supabase_flutter.dart';` and start using `Supabase.instance.client`.

Supports Flutter 3.0+ and Dart 2.19+. Works on iOS, Android, Web, macOS, Linux and Windows. Requires a minimum iOS deployment target of 12.0 and Android API level 21. The package depends on `supabase` core SDK, so keep both packages in sync when upgrading.

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

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Supabase.initialize(
    url: 'https://xyz.supabase.co',
    anonKey: 'public-anon-key',
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: const TodoPage(),
    );
  }
}

class TodoPage extends StatefulWidget {
  const TodoPage({super.key});
  @override
  State<TodoPage> createState() => _TodoPageState();
}

class _TodoPageState extends State<TodoPage> {
  final supabase = Supabase.instance.client;
  final _controller = TextEditingController();

  Stream<List<dynamic>> get _todos => supabase
      .from('todos')
      .stream(['id'])
      .order('created_at');

  Future<void> _addTodo() async {
    final text = _controller.text.trim();
    if (text.isEmpty) return;
    await supabase.from('todos').insert({'task': text});
    _controller.clear();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Supabase Todos')),
      body: Column(
        children: [
          Expanded(
            child: StreamBuilder<List<dynamic>>(
              stream: _todos,
              builder: (context, snapshot) {
                if (!snapshot.hasData) return const Center(child: CircularProgressIndicator());
                final todos = snapshot.data!;
                return ListView.builder(
                  itemCount: todos.length,
                  itemBuilder: (context, i) => ListTile(title: Text(todos[i]['task'])),
                );
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: Row(
              children: [
                Expanded(child: TextField(controller: _controller, decoration: const InputDecoration(hintText: 'New task'))),
                IconButton(icon: const Icon(Icons.send), onPressed: _addTodo),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
```

Official package resources