Introduction
Due to its impressive performance and ease of use, Flutter is a popular option for creating
cross-platform mobile apps. Supabase is a great solution for integrating a robust database backend
into your Flutter application. This blog will explore Supabase, and show you how to use its features
to provide your Flutter application with a powerful database. Let’s get started!
What is Supabase?
To meet the needs of today’s users, it is important to build powerful and responsive apps. When it
comes to building data-driven apps with real-time functionality, having a robust, scalable backend
becomes crucial. Supabase is an open-source Backend-as-a-Service solution (BaaS), which combines
Firebase with traditional databases. It’s built on PostgreSQL, and adds features such as real-time
access and authentication. Supabase is a real-time, scalable and secure database that integrates
seamlessly with Flutter apps.
This blog post will examine the integration of Supabase and Flutter. It allows you to use its
real-time authentication and database features to create dynamic and interactive applications. We
will explore the core concepts of Supabase, and show how it allows developers to build applications
that scale easily while maintaining data security and integrity.
This guide is for all Flutter developers, whether you are a seasoned developer or just getting
started. It will give you a thorough understanding of Supabase’s integration with Flutter. You’ll
have the skills to create powerful real-time apps that are backed up by a scalable and reliable
database.
Getting Started with Supabase
You need to create a Supabase Project
before you can use Supabase with your Flutter application. Sign up for an account on the
dashboard,
and create a new project.
You will receive an API key and URL
once your project has been set up. These are essential to access the Superbase database.
To get the URL and API key, follow the below guidelines:
After successfully signing in and creating your project, go to the Home option
Integration of Supabase into Flutter
It’s now time to integrate your Supabase app into your Flutter application. This can be done using
the Supabase Dart Package, which offers a set of APIs for interacting with the Supabase Backend.
These APIs allow you to perform CRUD operations and manage user authentication.
You can also subscribe to real-time updates. To do this, follow the steps below:
In the pubspec.yaml of your Flutter
project, import the latest version of the supabase_flutter packages.
The Supabase URL and API Key are
required to initialize the Supabase connection in Flutter.
Code snippet
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(
url: 'https://***.supabase.co',
anonKey: '***'
);
final supabase = Supabase.instance.client;
runApp(ProviderScope(child: App(supabase: supabase)));
}
Code implementation
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(
url: '',
anonKey:
'eyJ bGc...',
);
await AppPreference().initialAppPreference();
final supabase = Supabase.instance.client;
runApp(ProviderScope(child: App(supabase: supabase)));
}
class App extends StatelessWidget {
const App({Key? key, required this.supabase}) : super(key: key);
final SupabaseClient supabase;
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
initialRoute: '/', routes: {
'/': (_) => SplashPage(supabase: supabase),
'/login': (_) => LoginPage(supabase: supabase),
'/register': (_) => RegisterUser(supabase: supabase),
'/home': (_) => HomeScreen(),
// home: Home(supabase: supabase),
});
}
}
Authentication
login. dart
class LoginPage extends StatefulWidget {
const
LoginPage({super.key, this.supabase});
final
SupabaseClient? supabase;
@override
LoginPageState
createState() => LoginPageState();
}
class
LoginPageState extends State {
...
Future
_signIn() async {
try
{
debugPrint("EMAIL:
${_emailController.text}, PASSS: ${_passwordController.text}");
await
widget.supabase?.auth.signInWithPassword(email: _emailController.text,
password: _passwordController.text);
if
(mounted) {
_emailController.clear();
_passwordController.clear();
_redirecting
= true;
Navigator.of(context).pushReplacementNamed('/home');
}
}
on AuthException catch (error) {
context.showErrorSnackBar(message:
error.message);
}
catch (error) {
context.showErrorSnackBar(message:
'Unexpected error occurred');
}
}
@override
Widget
build(BuildContext context) {
return
Scaffold(
appBar:
AppBar(title: const Center(child: Text('Login')), backgroundColor: Colors.teal),
body:
SingleChildScrollView(
...
Padding(
padding:
const EdgeInsets.only(top: 25.0),
child:
Container(
height:
50,
width:
250,
decoration:
BoxDecoration(color: Colors.teal, borderRadius: BorderRadius.circular(20)),
child:
TextButton(
//
style: ButtonStyle(backgroundColor: MaterialStateColor.resolveWith((states)
=> Colors.teal), ),
onPressed:
() async {
if
(_formKey.currentState!.validate()) {
_signIn();
}
},
child:
const Text(
'Login',
style:
TextStyle(color: Colors.white, fontSize: 25),
),
),
),
),
const
SizedBox(
height:
130,
),
TextButton(
onPressed:
() {
Navigator.push(context,
MaterialPageRoute(builder: (_) =>
//
RegisterUser(supabase: widget.supabase ?? Supabase.instance.client)
SignUpPage(supabase:
widget.supabase ?? Supabase.instance.client)
));
},
child:
const Text('Don\'t have an account?', style: TextStyle(color: Colors.teal),)),
const
SizedBox(
height:
30,
),
...
),
);
}
}
signup.dart
class SignUpPage extends StatefulWidget {
const
SignUpPage({super.key, required this.supabase});
final
SupabaseClient supabase;
@override
SignUpPageState
createState() => SignUpPageState();
}
class
SignUpPageState extends State {
...
Future
_signUp() async {
try
{
AuthResponse
response = await widget.supabase.auth.signUp(
password:
_passwordController.text, email: _emailController.text);
if
(mounted) {
_redirecting
= true;
print("Userrr
-- ${response.user}");
_saveId(response.user);
Navigator.of(context).pushReplacementNamed("/register").then(
(value)
=> context.showSnackBar(message: "Verify your email!"));
setState(()
{});
}
}
on AuthException catch (error) {
context.showErrorSnackBar(message:
error.message);
}
catch (error) {
context.showErrorSnackBar(message:
'Unexpected error occurred');
}
}
@override
Widget
build(BuildContext context) {
return
Scaffold(
appBar:
AppBar(
title:
const Text('Sign Up'),
backgroundColor:
Colors.teal,
),
body:
SingleChildScrollView(
child:
...
Container(
height:
50,
width:
250,
decoration:
BoxDecoration(
color:
Colors.teal,
borderRadius:
BorderRadius.circular(20)),
child:
TextButton(
onPressed:
() {
if
(_formKey.currentState!.validate()) {
if
(_passwordController.text ==
_confPasswordController.text)
{
_signUp();
}
else {
ScaffoldMessenger.of(context).showSnackBar(
const
SnackBar(
content:
Text(
"Passwords
didn't match! Try again.")));
}
}
},
child:
const Text(
'Sign
Up',
style:
TextStyle(color: Colors.white, fontSize: 25),
),
),
),
const
SizedBox(
height:
130,
),
...
}