Supabase & Riverpod Minicourse | Build A Realtime Photo Sharing App

Supabase & Riverpod Minicourse | Build A Realtime Photo Sharing App

In this free minicourse, we will build a realtime photo sharing app with Supabase, Flutter and Riverpod. Supabase is an open-source Firebase alternative that offers a set of tools to create scalable and secure web and mobile applications.

Flutter is an open-source framework by Google for building natively compiled, multi-platform applications. The SDK is written in Dart which prides itself as being a flexible, general-purpose programming language which supports both AOT and JIT compilation targets.

On the other hand, Riverpod is a state management library for Flutter that provides a simple, composable way of managing application state. It uses dependency injection to enable sharing state across the app and offers an intuitive API for managing state.

Get started

To get set up and prepped for the course:

  1. Get the source code on GitHub. It contains the starting base that we build upon in the course

  2. Create a Supabase account or spin up a Docker instance. This is a necessary first step to create our Supabase project

  3. Install the Flutter SDK. This is what we’re building our app with.

Package Dependencies

There are several dependencies that are added to the project, though the important ones are:

supabase_flutter

This contains the client library for interacting with Supabase. Creating a Supabase account and project will expose a Project url as well as an API key. These will enable you to initialise Supabase by doing the following:

import 'package:supabase_flutter/supabase_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Supabase.initialize(
    url: 'SUPABASE_URL',
    anonKey: 'SUPABASE_ANON_KEY',
  );

  runApp(MyApp());
}

Initialising Supabase successfully gives you access to the SupabaseClient objects by doing the following:

final supabase = Supabase.instance.client;

flutter_riverpod

This allows using the riverpod state management solution in a Flutter project. We will be creating several Providers and Notifier instances via Code Generation, available via Riverpod 2+.

Here is a snippet of how creating a Provider that exposes a Repository client looks like:

// file: memory_repository.dart

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

part 'memory_repository.g.dart';

@riverpod
MemoryRepository memoryRepository(MemoryRepositoryRef _) => MemoryRepository();

class MemoryRepository {
  final _client = Supabase.instance.client;

  Future getMemories() async {
    return _client.from('memories').select('id, title, image_id')
      .order('created_at');
  }
}

You’ll then be able to generate the relevant AutoDisposeProvider<MemoryRepository> object by running the following:

$ flutter pub run build_runner build

When listening to authentication state changes, the StreamProvider<T> object is quite effective for sharing the Supabase authentication state:

// file: auth_user.dart

import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

part 'auth_user.g.dart';

@riverpod
Stream<User?> authUser(AuthUserRef ref) async* {
  final authStream = Supabase.instance.client.auth.onAuthStateChange;

  await for (final authState in authStream) {
    yield authState.session?.user;
  }
}

Watch full minicourse

Get the source code