Building a backend from scratch is often the most tedious part of mobile development. In my experience, spending days configuring servers, writing API endpoints, and managing JWTs is a productivity killer. That’s why I’ve shifted most of my rapid prototyping to Supabase. If you’re looking for a supabase flutter tutorial for beginners, you’ve come to the right place.
Supabase is an open-source Firebase alternative that gives you the power of a full PostgreSQL database without requiring you to be a DBA. When you’re deciding on the best backend for flutter apps, Supabase usually wins for me because of its relational nature and intuitive Flutter SDK.
Prerequisites
Before we dive into the code, make sure you have the following ready:
- Flutter SDK installed and configured on your machine.
- A basic understanding of Dart (Async/Await and Futures).
- A free account at supabase.com.
- An IDE of your choice (I personally use VS Code with the Flutter extension).
Step 1: Setting Up Your Supabase Project
First, log into your Supabase dashboard and create a new project. Give it a name and a secure database password. Once the project is provisioned, navigate to Project Settings > API.
You’ll need two pieces of information: the Project URL and the anon public API key. Keep these handy, as we’ll plug them directly into our Flutter app. As shown in the image below, these are located in the API settings tab of your dashboard.
Step 2: Adding Dependencies to Flutter
Open your pubspec.yaml file and add the supabase_flutter package. I recommend using the latest stable version to ensure compatibility with the newest Flutter SDK.
dependencies:
flutter:
sdk: flutter
supabase_flutter: ^2.0.0
Run flutter pub get in your terminal to install the package.
Step 3: Initializing Supabase in Main
You need to initialize the Supabase client before your app starts. The best place for this is in your main() function. I’ve found that using WidgetsFlutterBinding.ensureInitialized() is critical here to prevent crashes during the async initialization phase.
import 'package:supabase_flutter/supabase_flutter.dart';
import 'package:flutter/material.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Supabase.initialize(
url: 'YOUR_SUPABASE_URL',
anonKey: 'YOUR_SUPABASE_ANON_KEY',
);
runApp(const MyApp());
}
// Shortcut to access the client throughout the app
final supabase = Supabase.instance.client;
Step 4: Implementing User Authentication
One of the best parts of this supabase flutter tutorial for beginners is how simple Auth is. Let’s implement a basic Sign-Up function. I typically wrap these calls in a try-catch block because network errors or “user already exists” exceptions are common.
Future<void> signUpUser(String email, String password) async {
try {
final AuthResponse res = await supabase.auth.signUp(
email: email,
password: password,
);
print('User signed up: ${res.user?.id}');
} catch (e) {
print('Error signing up: $e');
}
}
For logging in, the process is nearly identical using supabase.auth.signInWithPassword(). If you’re building an app that requires offline capabilities, you might also want to explore flutter local storage options comparison to cache user sessions locally.
Step 5: Database Operations (CRUD)
Supabase uses PostgreSQL, but you interact with it using a syntax that feels like JSON. Let’s say we have a table called profiles.
Inserting Data
await supabase
.from('profiles')
.insert({'username': 'ajmani_dev', 'website': 'ajmani.dev'});
Fetching Data
To get a single user’s profile, you can use a filter:
final data = await supabase
.from('profiles')
.select()
.eq('username', 'ajmani_dev')
.single();
Step 6: Enabling Real-time Updates
This is where the magic happens. Instead of polling the server, you can listen to changes in your database using Streams. This is perfect for chat apps or live dashboards.
final _stream = supabase.from('profiles').stream(primaryKey: ['id']);
// Use this stream in a StreamBuilder in your UI
StreamBuilder(
stream: _stream,
builder: (context, snapshot) {
if (!snapshot.hasData) return const CircularProgressIndicator();
final profiles = snapshot.data!;
return ListView.builder(
itemCount: profiles.length,
itemBuilder: (context, index) => Text(profiles[index]['username']),
);
},
)
Pro Tips for Supabase & Flutter
- Use RLS (Row Level Security): Never leave your tables open. Always enable RLS in the Supabase dashboard and create policies so users can only edit their own data.
- Model your Data: Don’t pass around Maps. Create a
Profileclass and afromMap()factory to keep your code type-safe. - Avoid Over-fetching: Only select the columns you need (e.g.,
.select('username, avatar_url')) to keep your app snappy.
Troubleshooting Common Issues
Issue: “Permission Denied” when fetching data.
This is almost always an RLS issue. If you haven’t created a policy for the SELECT operation, Supabase defaults to denying all requests for security.
Issue: App hangs during initialization.
Ensure you’ve added the Internet permission to your AndroidManifest.xml for Android apps. It’s a common step that beginners often miss.
What’s Next?
Now that you’ve completed this supabase flutter tutorial for beginners, you can expand your app by adding Supabase Storage for user avatars or Edge Functions for server-side logic like sending emails. I’ve found that combining these tools allows a single developer to do the work of a full team.