Supabase Setup
Setting up Supabase — the open-source Firebase alternative — for your Flutter applications.
Supabase is an open-source Firebase alternative that provides a full backend solution for your Flutter apps. It's built on top of PostgreSQL , the world's most trusted relational database, and offers:
✅ Why Supabase Over Firebase?
- PostgreSQL – Real relational database with advanced querying
- Open Source – Self-hostable, no vendor lock-in
- Better Pricing – Free tier includes 500MB database, 1GB storage, 2GB bandwidth
- SQL – Use SQL directly for complex queries
- Real Realtime – Full CRUD subscriptions, not just Firestore-like
To get started with Supabase, you need to create an account and set up your first project.
- Name – e.g., "my_flutter_app"
- Database Password – Choose a strong password
- Region – Choose the closest region to your users
- Pricing Plan – Free tier works for learning
-
Project URL
–
https://your-project.supabase.co - anon public key – Used for client-side requests
- service_role key – Used for server-side/admin operations (keep secret!)
⚠️ Important: API Keys
- anon key – Safe to use in client-side Flutter apps. This key is limited by Row Level Security policies.
- service_role key – Never expose this in client-side code! It bypasses all RLS policies.
To connect your Flutter app to Supabase, you need to add the
supabase_flutter
package
and configure it with your project credentials.
dependencies:
flutter:
sdk: flutter
supabase_flutter: ^2.8.0
import
'package:flutter/material.dart'
;
import
'package:supabase_flutter/supabase_flutter.dart'
;
void
main
() async {
// Initialize Supabase before running the app
await
Supabase.initialize(
url:
'https://your-project.supabase.co'
,
// Replace with your project URL
anonKey:
'your-anon-key'
,
// Replace with your anon key
);
runApp(
MyApp
());
}
class
MyApp
extends
StatelessWidget {
@override
Widget
build
(BuildContext context) {
return
MaterialApp(
title:
'Supabase Flutter'
,
theme: ThemeData(
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3:
true
,
),
home: HomePage(),
);
}
}
class
HomePage
extends
StatelessWidget {
@override
Widget
build
(BuildContext context) {
// Check if user is already logged in
final
session = Supabase.instance.client.auth.currentSession;
return
Scaffold(
appBar: AppBar(
title: Text(
'Supabase Demo'
),
centerTitle:
true
,
),
body: Center(
child: session !=
null
? Text(
'Welcome, ${session.user.email}'
)
: Text(
'Not logged in'
),
),
);
}
}
💡 Using Environment Variables (Recommended)
For production apps, store your Supabase credentials in environment variables:
// lib/constants/env.dart
class
Env
{
static
const
String supabaseUrl = String.fromEnvironment(
'SUPABASE_URL'
);
static
const
String supabaseAnonKey = String.fromEnvironment(
'SUPABASE_ANON_KEY'
);
}
Then run with:
flutter run --dart-define=SUPABASE_URL=your-url --dart-define=SUPABASE_ANON_KEY=your-key
To verify that your Flutter app is correctly connected to Supabase, you can make a simple query to fetch data from a table.
import
'package:supabase_flutter/supabase_flutter.dart'
;
class
ConnectionTestService
{
final
SupabaseClient client = Supabase.instance.client;
Future
<
bool
>
testConnection
() async {
try
{
// Try to fetch a single row from a table
// This will throw an error if the table doesn't exist yet, but
// that's okay — it means the connection is working!
final
response = await client
.from(
'your_table_name'
)
.select()
.limit(
1
);
return
true
;
}
catch
(e) {
// If error is about the table not existing, connection worked
if
(e.toString().contains(
'relation'
) &&
e.toString().contains(
'does not exist'
)) {
return
true
;
}
// If it's a different error, something else went wrong
return
false
;
}
}
// Simple health check
Future
<Map<String, dynamic>>
healthCheck
() async {
try
{
final
response = await client.rest.get(
Uri.parse(
'${client.rest.url}/health'
),
);
return
{
'status'
:
'ok'
,
'data'
: response.body};
}
catch
(e) {
return
{
'status'
:
'error'
,
'message'
: e.toString()};
}
}
}
supabase_flutter
to your
pubspec.yaml
.
Supabase.initialize()
before running the app,
passing your project URL and anon key.
Supabase.instance.client
to access the
Supabase client anywhere in your app.
Supabase.instance.client.auth.currentSession
to check if a user is logged in.
These packages work great with Supabase and are recommended for production apps:
go_router
- Declarative routing
- Deep linking support
- Auth guards
- Nested routes
flutter_riverpod
- State management
- Dependency injection
- Providers for Supabase
- AsyncValue handling
freezed
- Immutable data classes
- Union types
- JSON serialization
- CopyWith methods
cached_network_image
- Image caching
- Placeholder widgets
- Error handling
- Memory management
📦 Package Versions
-
supabase_flutter: ^2.8.0 -
go_router: ^14.0.0 -
flutter_riverpod: ^2.5.0 -
freezed_annotation: ^2.4.0 -
json_serializable: ^6.7.0 -
cached_network_image: ^3.3.0
The
service_role
key bypasses all security policies. Never expose it in your Flutter app.
Always use the
anon
key in your Flutter app. It's safe and respects Row Level Security policies.
If you try to use Supabase before calling
Supabase.initialize()
, you'll get an error.
Always call
await Supabase.initialize()
before
runApp()
.
Hardcoding your Supabase URL and anon key in your source code makes it harder to manage different environments.
Use
--dart-define
or a
.env
file with
flutter_dotenv
to manage credentials.
🎯 Key Takeaway
Supabase is a powerful open-source Firebase alternative built on PostgreSQL. Setting up your Flutter app with Supabase is simple: create a project, get your API keys, and initialize the client. Always use the anon key for client-side code and store credentials securely using environment variables.