Integration guide for creating local-first apps with FlutterFlow and PowerSync with Supabase as the backend.
lists
table. The demo app will have access to this table even while offline. Run the below SQL statement in your Supabase SQL Editor:
SELECT
privilege, and for the publication mentioned in the next step (as well as for any other publications that may exist).Next
version of the Service, which may contain early access or experimental features. Always use the Stable
version in production.[YOUR-PASSWORD]
placeholder)
powersync_role
and password you created when configuring your Supabase for PowerSync (see Source Database Setup).
verify-full
SSL mode without additional configuration.
sync-rules.yaml
file.
sync-rules.yaml
file’s contents with the below:
anon
public
in your Supabase dashboard.powersync_core:1.3.0
:powersync_core
is required for running FlutterFlow on Web.
Login
.Login
page you just created.Click on 'Test'
For once, a blank screen means success!
PowerSyncQuery
component.PowerSyncStateUpdater
component.PowerSyncQueryOnce
custom action.supabaseRowsToList
(if your Supabase table name is “Customers”, you would name this supabaseRowsToCustomers
).Supabase Row
lists
.supabaseRows
Custom function to map the lists table from Supabase
ListItems
.
ListItems
component.
ListView
widget.
The ListItems component should now look like this
ListItems
component.
lists
.Supabase Row
.lists
.listItem
.lists
).The ListItems component should now look like this
ListTile
widget.
Set the list item title text
The ListItems component should now look like this
HomePage
.
PowerSyncQuery
library component into your page.
ListItems
we previously created.lists
.supabaseRowsToList
we created previously.supabaseRows
argument, set the “Value” to “Widget Builder Parameters” -> rows
.select * from lists order by created_at;
lists
table is empty in Supabase. Create a test row in the table by clicking on “Insert” -> “Insert Row” in your Supabase Table Editor.
id
and created_at
blank.owner_id
and select your test user.ListView
component clickable and navigate the user to a page which will eventually display the list’s To-Do items. This page will show the selected list’s name in the title bar (“AppBar”). This uses Page State and the PowerSyncStateUpdater
library component.
Todos
.Todos
page.id
.Todos
page selected:list
.lists
.PowerSyncStateUpdater
library component into your page.
PowerSyncStateUpdater
component.
select * from lists where id = :id;
id
.id
.list
page state variable.supabaseRowsToList
.rows
List Name
.ListView
Component ClickableListItems
component.ListTile
widget.Todos
page.HomePage
page.INSERT INTO lists(id, created_at, name, owner_id) VALUES(uuid(), datetime(), 'new item', :userId);
userId
parameter we’re using the above query:
userId
.powersyncWrite
helper of the Library, and a guide will be published soon. In the mean time, use the section below about Deleting Data as a reference. Please reach out on our Discord if you have any questions.ListTile
to delete it.
ListItems
component.
ListTile
widget.
delete from lists where id = :id;
id
parameter we’re using the above query:
id
.signOut
without Arguments or Return Values and paste the below code:power_sync_b0w5r9
is the project ID of the PowerSync library. Update it if it changes.HomePage
page.
Sign Out
.
signOut
Custom Action.
PowerSyncConnectivity
component into your home page’s “AppBar”.
owner_id
matches their user id:
sync-rules.yaml
file.tags
column on the lists
table used in this guide. These tags will be
encoded as a string array in Postgres:
["default", "tags"]
.
FlutterFlow does not support extracting a list from that string, so the custom functions responsible
for mapping SQLite rows to FlutterFlow classes needs to be aware of the transformation and reverse it:
'["default", "tags"]'
value as it appears into ["default", "tags"]
, the list value expected
for this row.
A similar approach is necessary when making local writes. The local database should be consistent with the
data synced with PowerSync. So all local writes should write array and JSON values as strings by
encoding them as JSON.
Finally, the PowerSync mapping also needs to be reverted when uploading rows to Postgres. For a
text[]
column for instance, the local string value would not be accepted by Supabase.
For this reason, the upload behavior for columns with advanced types needs to be customized.
0.0.7
of the PowerSync FlutterFlow library.
Please make sure you’re using that version or later.applyPowerSyncOptions
). After the
default imports, put this snippet:
main.dart
as a final action.
When setting powersyncOptions.transformData
, a callback is invoked every time a created or updated row
is uploaded to Supabase.
This allows you to customize how individual values are represented for Postgres. In this case, the tags
column of the lists
table is decoded as JSON so that it’s uploaded as a proper array while being stored
as a list locally.
applyPowerSyncOptions
). It’s important that this action runs
before anything else in your app uses PowerSync, so add this action to your main.dart
as a final action.
Podfile
located in the ios/
directory.Podfile
needs to be updated from use_frameworks! :linkage => :static
to use_frameworks!
(remove everything after the exclamation sign).