Upgrade to supabase-flutter v1

supabase-flutter focuses on improving the developer experience and making it easier to use. This guide will help you upgrade from supabase-flutter v0 to v1.

Upgrade the client library#

Update the package in your pubspec.yaml file.

1supabase_flutter: ^1.0.0

Error handling#

The way supabase-flutter throws error has changed in v1. In v0, errors were returned as a response. In v1, errors are thrown as exceptions. This makes it more intuitive as a Flutter developer to handle errors.

1final res = await supabase.from('my_table').select().execute();
2final error = res.error;
3if (error != null) {
4  // handle error
6final data = res.data;

Auth classes / methods#

Usage of SupabaseAuthState and SupabaseAuthRequiredState classes#

In v0, SupabaseAuthState and SupabaseAuthRequiredState were required to handle automatic token refresh and to listen to auth state change. In v1, SupabaseAuthState and SupabaseAuthRequiredState are deprecated, and token refresh will happen automatically just by initializing Supabase. onAuthStateChange can be used to action on auth state change.

1await Supabase.initialize(
2  url: 'SUPABASE_URL',
3  anonKey: 'SUPABASE_ANON_KEY',
7class AuthState<T extends StatefulWidget> extends SupabaseAuthState<T> {
8  ...
13class AuthRequiredState<T extends StatefulWidget> extends SupabaseAuthState<T> {
14  ...

Listening to auth state change#

onAuthStateChange now returns a Stream.

1final authSubscription = supabase.auth.onAuthStateChange((event, session) {
2  // handle auth state change
5// Unsubscribe when no longer needed

Sign in with email and password#

The signIn() method has been deprecated in favor of more explicit method signatures to help with type hinting. Previously it was difficult for developers to know what they were missing (e.g., a lot of developers didn't realize they could use passwordless magic links).

1await supabase.auth.signIn(email: email, password: password);
1await supabase.auth.signIn(email: email);

Sign in with a third-party OAuth provider#

1await supabase.auth.signInWithProvider(
2  Provider.github,
3  options: AuthOptions(
4      redirectTo: kIsWeb
5          ? null
6          : 'io.supabase.flutter://reset-callback/'),

Sign in with phone#

1await supabase.auth.signIn(
2  phone: '+13334445555',
3  password: 'example-password',

Sign in with phone using OTP#

1final res = await supabase.auth.signIn(phone: phone);

Reset password for email#

1await supabase.auth.api.resetPasswordForEmail(
2  email,
3  options:
4      AuthOptions(redirectTo: 'io.supabase.flutter://reset-callback/'),

Get the user's current session#

1final session = supabase.auth.session();

Get the logged-in user#

1final user = supabase.auth.user();

Update user data for a logged-in user#

1await supabase.auth.update(
2  UserAttributes(data: {'hello': 'world'})

Data methods#

.insert() / .upsert() / .update() / .delete() don't return rows by default.

Previously, these methods return inserted/updated/deleted rows by default (which caused some confusion), and you can opt to not return it by specifying returning: 'minimal'. Now the default behavior is to not return rows. To return inserted/updated/deleted rows, add a .select() call at the end.

Also, calling .execute() at the end of the query was a requirement in v0, but in v1 .execute is deperecated.

Insert without returning inserted data#

1await supabase
2  .from('my_table')
3  .insert(data, returning: ReturningOption.minimal)
4  .execute();

Insert with returning inserted data#

1final res = await supabase
2  .from('my_table')
3  .insert(data)
4  .execute();

Realtime methods#


.stream() no longer needs the .execute() at the end. Also, filtering by eq is a lot easier now. primaryKey is now a named parameter to make it more obvious what to pass.

2  .stream(['id'])
3  .listen();


1final subscription = supabase
2  .from('countries')
3  .on(SupabaseEventTypes.all, (payload) {
4    // Handle realtime payload
5  })
6  .subscribe();