supabase-flutter ships a client library and a separate test helper package
Flutter integration for Supabase. These packages makes it simple for developers to build secure and scalable products.
At a glance
- What is it?
- supabase-flutter is an MIT licensed Dart monorepo from Supabase containing the Flutter client for Supabase plus its sub-libraries, and a distinct supabase_test package that publishes mock HTTP clients, JWT builders, auth session fixtures and realtime frames so an application can test against a real SupabaseClient with no running stack.
- Who is it for?
- supabase-flutter fits a Flutter team building on Supabase that wants the client's own test helpers rather than a hand-rolled mock, and it fits a contributor who wants to work on the client against a real local stack. It does not fit a team that has standardised on a different backend client, and it does not fit someone who wants a hosted backend rather than a client library.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository received new commits within the last day.
- What is it written in?
- Mainly Dart, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A monorepo where the client is only one package
supabase-flutter is the Flutter client library for Supabase, and the README describes the repository as a monorepo powered by Melos containing supabase_flutter and its sub-libraries, with all packages located in the packages directory.
That structure matters more than it might look. The main package is a facade over several separate published packages, and the README names the ones you can see in the release list, supabase_typegen for generating types from the database schema, supabase_test for the test helpers, and supabase_flutter_web_auth for the web authentication flow, alongside the core packages that the testing section names, postgrest, supabase_auth, supabase_realtime and supabase_storage.
So the client is layered the same way the backend is. There is a PostgREST client for the database, an auth client, a realtime client over websockets, a storage client, a web auth package, and a type generator. A Flutter application typically depends on the supabase_flutter facade and gets all of them, but a project that only wants the database access does not have to take the whole stack.
The repository top level listing matches that shape. There is a packages/ directory, an examples/ directory with a run.sh and separate directories for authentication, database_crud, edge_functions, launcher, passkeys, realtime_room, storage_transforms and supabase, a scripts/ directory, a supabase/ directory holding the local stack configuration, a MIGRATION.md at the root, and a sdk-compliance.yaml.
That last file is worth noting. A compliance file at the root of a client SDK repository is a machine readable description of what the SDK guarantees, and it is a sign of a project that takes the interface seriously, since a compliance document can be checked rather than read. There is also a .coderabbit.yaml for an automated code review tool and an AGENTS.md, so the repository is set up for both AI-assisted contribution and for agents working in it.
The main package is published on pub.dev as supabase_flutter, and the README links the guides, the Dart reference documentation and the migration guides, and the latter is a file in the repository rather than only a link, which is the right place for it.
supabase_test is the part application developers actually want
The testing section describes a package that exists so that applications can test against Supabase without a running stack, and the reasoning behind its existence is visible in how the helpers are shaped.
The helpers the test suites of these packages run on are published in package:supabase_test, so your tests can build on the same primitives: mock HTTP clients, JWT builders, auth session fixtures and realtime frames.
The mock client is a stubbing layer over the endpoints the client talks to.
final httpClient = MockSupabaseHttpClient()
..stubTable('todos', rows: [
{'id': 1, 'task': 'Ship it', 'status': false},
]);
final supabase = testSupabaseClient(httpClient: httpClient);
addTearDown(supabase.dispose);
final todos = await supabase.from('todos').select();
expect(todos, hasLength(1));So the object under test is a real SupabaseClient, constructed with a mock HTTP client underneath, and the mock is told which table returns which rows. The application code is unchanged, and the test exercises the real client logic, the real query building, the real response parsing, and only the transport is faked.
That is a meaningfully better design than mocking at a higher level, because it means the test covers the code the application actually ships rather than a stand-in for it.
The README points at the supabase_test README for the full guide, and the list of what it covers is specific: stubbing database, rpc, edge function and auth endpoints, asserting on recorded requests, running tests as a signed-in user, and wiring Supabase.initialize in Flutter widget tests.
The JWT builders and the auth session fixtures are the two pieces that solve the awkward part. A Supabase application is not much use unauthenticated, and constructing a valid session with a signed access token by hand in every test file is the kind of boilerplate that ends up copied and diverged. A published builder means the token shape is defined once.
The package is added as a dev dependency, and the README shows the version constraint as supabase_test: ^0.1.0, while the release list has it at v0.5.0 from 2026-10-15, so the constraint in the README is behind the current release.
The repository's own tests run against a real local stack
Testing this repo is a different exercise from testing your app with supabase_test, and the README is clear about the difference.
The tests for the packages postgrest, supabase_auth, supabase_realtime and supabase_storage run against a local Supabase stack. To run these tests locally you need docker and the Supabase CLI installed. The single configuration for the stack lives in the supabase directory at the repository root, and it starts with supabase start and stops with supabase stop.
So the client library's own tests exercise a real PostgREST, a real auth service, a real realtime websocket server and a real storage service. That is a much stronger guarantee than a mocked suite, and it is the reason the package's behaviour matches the server's behaviour.
The test command inside a package directory is dart test -j 1, and the README explains the flag. The -j 1 flag runs the tests not concurrently, which works better since the tests run against the same services.
That is worth pausing on, because it is a real constraint on anyone running the suite. The tests are not isolated, they share a stack, so they cannot be parallelised, and a shared stack means one failing test can leave state behind that affects the next. For a contributor that is a slower loop than a unit test suite, and for a package that has to be right about wire protocols it is the right trade.
The split between the two kinds of testing is therefore a deliberate design. The application gets the mock client, which is fast and hermetic, and the library gets the real stack, which is slow and faithful. The application developer is not asked to run a Supabase stack to have a test suite, and the library author is not allowed to ship a client that only works against a mock.
Working on the packages locally with Melos
The Run locally section is short and it explains how a contributor gets a local checkout into a working application.
The steps are: clone the repo, install Melos globally with dart pub global activate melos if you have not already, run melos bootstrap or melos bs at the root of the cloned directory to install dependencies, and add the target package to your pubspec.yaml file specifying the path.
supabase_flutter:
path: <your-path-to-the-local-supabase-flutter-repo>/packages/supabase_flutterSo a path dependency is how a change to the client is tested inside a real application before it is published. That is the workflow that makes a monorepo with published sub-packages workable, because the version in pub.dev is not always the version your application is using while you are working on it.
Melos is doing the workspace work here, the bootstrapping across all the packages at once, and it is the Dart community's standard answer to the same problem that pnpm workspaces solve in JavaScript and cargo workspaces solve in Rust. The repository also has a pubspec.yaml and a pubspec.lock at the root alongside the per-package ones, which is the Melos convention.
The examples/ directory is part of the same story. There is a run.sh and separate directories for authentication, database_crud, edge_functions, launcher, passkeys, realtime_room, storage_transforms and supabase, so the repository ships runnable applications covering each area of the client rather than only unit tests. The passkeys example is notable, because passkey support in a Flutter client is a feature that needs a real device to exercise, and the realtime_room example covers the websocket path that is hardest to test without a server.
The top level also has scripts/ and a .sdk-parse-ignore file, which is part of the SDK parsing and compliance tooling that the sdk-compliance.yaml belongs to.
Where supabase-flutter is the wrong choice
The first wrong case is a team that wants a backend rather than a client. This is a client library for a service that runs elsewhere. If the requirement is a hosted Postgres with auth, realtime and storage behind an API, the backend is the decision and the Flutter client is a consequence of it. Reading this repository will not tell you whether that backend suits you.
The second wrong case is a team that has already standardised on a different Dart client for the same service, or on a different backend entirely. The value here is the test helpers, the type generator and the coverage of the auth and realtime specifics, and that value only exists if this is the client you are using.
The third wrong case is a team that does not want a facade dependency. The main package pulls in the database, auth, realtime and storage clients whether you use them or not, and a project that needs one of them can depend on the sub-package directly, which is the point of the sub-libraries but also a configuration decision the README does not spell out for you.
The fourth wrong case is a contributor who expects a fast test loop. The repository's own tests need docker and the Supabase CLI, and they cannot run concurrently because they share the same services, so the feedback cycle for client work is minutes rather than seconds. That is acceptable for a client that has to be right about wire protocols, and it is a cost for anyone doing a large refactor.
How it differs from calling the Supabase REST API by hand
The comparison worth making is with a Flutter application that talks to Supabase over HTTP directly, and the difference in approach is in what the client library owns.
A hand-rolled client is a few methods over a PostgREST query string, a GoTrue login call and a websocket subscription. The interesting parts are the parts that are easy to get subtly wrong. The PostgREST query syntax, the filter and ordering operators and how null and arrays are encoded, is a small language. The auth flow involves a session, a refresh token, an expiry, and the rule that a refresh must happen before the token expires rather than after it fails. Realtime needs a websocket with a heartbeat and a reconnection policy and a subscription that survives a token refresh.
The library owns those, and the README describes the package set as a decomposition of exactly that surface, one package per protocol area.
The second difference is types. The supabase_typegen package generates Dart types from your database schema, so the row types you select are checked against the table definition. Without that, a Flutter application selecting from a table has untyped rows, and a renamed column is discovered at runtime rather than at compile time. This is the difference between the library and the raw API, and it is the one that matters most on a team with more than one developer.
The third difference is the test story, and it is the one this repository invests in most unusually. supabase_test publishes the primitives the library's own tests use, so an application is not inventing a second, divergent mocking approach. The mock is an HTTP layer with a stubTable method, the client under test is real, and the fixtures include JWT builders and auth sessions, so the tests can run signed in and assert on the recorded requests. A hand-rolled client has to have that built and maintained per project, which is a lot of work for something that has already been written and published.
The fourth difference is the migration cost. The client tracks the server's behaviour, and when Supabase changes an API the client is updated in the same repository and released as a version. A hand-rolled client discovers the change when it breaks.
Editorial conclusion
supabase-flutter fits a Flutter team building on Supabase that wants the client's own test helpers rather than a hand-rolled mock, and it fits a contributor who wants to work on the client against a real local stack. It does not fit a team that has standardised on a different backend client, and it does not fit someone who wants a hosted backend rather than a client library. Before adopting it, note that the repository is a Melos monorepo whose sub-libraries are published separately, that the repository's own integration tests need docker and the Supabase CLI, and that the current releases include supabase_typegen v0.5.2 and supabase_test v0.5.0 both dated 2026-10-15.
Frequently asked questions
What does the supabase-flutter repository contain?
It is a Melos monorepo containing the supabase_flutter client and its sub-libraries, with all packages under the packages directory. The releases include supabase_typegen, supabase_test and supabase_flutter_web_auth, and the repository's own tests cover the postgrest, supabase_auth, supabase_realtime and supabase_storage packages.
How can I test a Flutter app that uses Supabase without a running stack?
Add the supabase_test package as a dev dependency and use its MockSupabaseHttpClient with stubTable to declare what each endpoint returns, then build a real client with testSupabaseClient. The package also provides JWT builders, auth session fixtures and realtime frames, and an unmatched expectation makes Location-style calls return false so the test never touches the network.
How do I run the supabase-flutter repository's own tests?
You need docker and the Supabase CLI, then run supabase start from the repository root using the configuration in the supabase directory. Inside a package directory you run dart test -j 1, with the -j 1 flag because the tests share the same services and work better when not run concurrently. Stop the stack with supabase stop.
How do I use a local checkout of the Supabase Flutter client in my app?
Clone the repository, activate Melos globally with dart pub global activate melos, run melos bootstrap at the root, and add a path dependency in your pubspec.yaml pointing at packages/supabase_flutter in the cloned repository.
What is the supabase_typegen package for?
It is the package in the monorepo that generates Dart types from your database schema, so the rows you select are typed against the table definition rather than being untyped. It is published separately from the main client package and was released as v0.5.2 on 2026-10-15.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/supabase-supabase-flutter)Was this useful?