Skip to main content

supabase-migrate-v3

Migrates a Dart or Flutter project from supabase v2 to v3, including the renamed gotrue, realtime_client, storage_client and functions_client packages. Generates a typed database schema with the Supabase CLI, applies every breaking change from the migration guide, and moves queries from the untyped from() API to the typed table() API. Use when the user asks to upgrade or migrate Supabase to v3, bumps supabase to ^3, or hits v3 breaking changes.

Informações da origem

Repositório
supabase/supabase-flutter
Última atividade na origem
23 de outubro de 2026 às 14:45
Idioma detectado do SKILL.md
inglês
Estrelas
1.039
Forks
312

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Explorador de arquivos
2 arquivos

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
name
supabase-migrate-v3
description
Migrates a Dart or Flutter project from supabase v2 to v3, including the renamed gotrue, realtime_client, storage_client and functions_client packages. Generates a typed database schema with the Supabase CLI, applies every breaking change from the migration guide, and moves queries from the untyped from() API to the typed table() API. Use when the user asks to upgrade or migrate Supabase to v3, bumps supabase to ^3, or hits v3 breaking changes.
# Migrate supabase from v2 to v3 The full migration guide is in [references/migration-v2-v3.md](references/migration-v2-v3.md). Its section headings name the symbol that changed, so search it for the symbol in a compiler error or in the code you are changing. Every "Before" and "After" snippet there is authoritative. This file is the order to apply it in and the checks that make the migration complete. ## Rules - Follow the steps in order. Do not skip the Supabase CLI check. - Never write the table definitions by hand. They come from `supabase gen types --lang dart`, and the generated file is never edited. - Every query ends up on the typed `table()` API unless it matches one of the exceptions in step 8. Report every exception to the user. - Keep the behavior of the app. Where v3 changed a default, pin the v2 behavior explicitly unless the user asks for the new one. - Do not suppress analyzer errors or warnings to get a clean run. Fix them. - Ask the user before a choice that changes runtime behavior and is not covered here. ## 1. Preflight 1. Read `pubspec.yaml`. Note which of these are dependencies and their versions: `supabase_flutter`, `supabase`, `gotrue`, `postgrest`, `realtime_client`, `storage_client`, `functions_client`. 2. Run `git status`. If the tree is dirty, ask the user to commit or stash first so the migration is one reviewable diff. 3. Run `dart analyze` and save the output. Issues that exist before the migration are the baseline, and step 9 is measured against it. 4. Check for a `supabase/` folder with `config.toml` and `migrations/`. It decides the source of the generated types in step 4. ## 2. Supabase CLI 2.122.0 or newer Dart generation requires Supabase CLI 2.122.0 or newer. ```sh supabase --version ``` If the project runs the CLI through npm (a `supabase` entry in `package.json`), check `npx supabase --version` instead. If the command is missing or prints a version below `2.122.0`, stop and give the user the command for their platform, then wait until the version check passes: | Install method | Upgrade command | | ----------------------- | ---------------------------------------------------------------------- | | Homebrew (macOS, Linux) | `brew upgrade supabase/tap/supabase` | | npm | `npm install --save-dev supabase@latest` | | Scoop (Windows) | `scoop update supabase` | | Not installed | https://supabase.com/docs/guides/local-development/cli/getting-started | Do not continue on an older CLI and do not fall back to hand-written types. ## 3. Pin the changed `order()` defaults while still on v2 v3 changed two defaults of `order()` without a compile error. Both pins below already mean the same thing on v2, so add them before upgrading: ```sh grep -rnE '\.order\(' lib test bin ``` - A call without `ascending:` sorted descending on v2 and sorts ascending on v3. Add `ascending: false`. - A query that sorts descending (including the ones you just changed) put `NULL`s last on v2 and puts them first on v3. When the column is nullable, add `nullsFirst: false`. This does not apply to `stream().order()`, which takes no null placement. The direction pin applies to `stream().order()` too. The result is that every `order()` call states its direction and, on a descending query of a nullable column, its null placement. ## 4. Dependencies and the typed schema Once `supabase_typegen` is added, its `supabase-typegen-generate` skill has the details of the generator, its options and its errors. 1. Update the dependencies. Use the newest 3.x version of each package; `dart pub outdated` lists it, prereleases included. - `supabase` to 3.x. - Replace any direct dependency on a renamed package, and its imports: | v2 | v3 | | ------------------ | -------------------- | | `gotrue` | `supabase_auth` | | `realtime_client` | `supabase_realtime` | | `storage_client` | `supabase_storage` | | `functions_client` | `supabase_functions` | A direct dependency that only duplicates what `supabase` already re-exports can be removed instead. 2. Add the generator: `dart pub add dev:supabase_typegen`. 3. Run `dart pub get`. 4. Generate the schema. Pick the source: - A `supabase/` folder with migrations: run `supabase start` (needs Docker), then `supabase gen types --lang dart --local`. - A project linked with `supabase link`: `--linked`. - Otherwise ask the user for the project ref and use `--project-id <ref>`. Ask which schemas the app queries. Pass `--schema` for each schema other than `public` that the app uses. Write to `lib/supabase_schema.g.dart` unless the project already has a generated-code convention: ```sh supabase gen types --lang dart --local > lib/supabase_schema.g.dart ``` 5. Run `dart analyze lib/supabase_schema.g.dart`. It must be clean. If it is not, report the error to the user rather than editing the file. ## 5. Mechanical renames Apply these across the project before reading compiler errors, since they remove most of them. The tables are in the reference: - "The client packages are renamed": imports and the `GoTrue*` type names, such as `GoTrueClient` to `AuthClient`. - "Abbreviations in the public API are spelled out": for example `queryParams:` to `queryParameters:` and `opts:` to `options:`. - "Plural enum names singularized" and "One shared `SortDirection` for every sort direction". - "Every deprecated API is gone": for example `User.confirmedAt` to `User.emailConfirmedAt` and `AuthUser` to `User`. ## 6. Compiler-driven pass 1. Run `dart analyze`. 2. For each new error, search the reference for the symbol it names and apply the "After" form of that section. 3. Repeat until the only issues left are the baseline from step 1. The sections that most often apply: - "Sign-in methods that always issue a session return the `Session`": `signInWithPassword()` and others return the `Session` directly. - "`AuthState` is a sealed class" and "`User.appMetadata` is an `AppMetadata` and `userMetadata` is never null". - "Realtime listener callbacks are now streams": `onPostgresChanges`, `onBroadcast` and the connection callbacks. - "The auth client persists the session itself": `localStorage:` and `LocalStorage` subclasses become an `AuthAsyncStorage`. - "Service exceptions share one base" and "`FunctionsException` is sealed". - "Every client takes one `SupabaseRetryOptions`". - "Timestamps are `DateTime` instead of `String` or `int`". - "`rpc` is a getter", "`insert()` and `upsert()` no longer take filters" and "The rest client and its builders are stateless". ## 7. Changes the compiler will not catch Go through every item. For each one, search with the given pattern, read every match, and fix or confirm it. Keep a list of the sites you could not decide for the summary in step 9. | Change (reference section) | Search | Action | | ----------------------------------------------------------------- | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `order()` defaults | `\.order\(` | Confirm step 3 covered every call. | | `RealtimeClient.connectionState` is now typed | `connectionState` | Compare against `SocketState.open` and friends, not strings. Prefer `isConnected`. | | `HttpMethod` is one shared enum | `HttpMethod\.[a-z]+\.index` | Persist `name` instead of `index`. | | Confirming an email or phone change emits `userUpdated` | `AuthChangeEvent\.signedIn` | Handle `userUpdated` where an email or phone change confirmation should be seen. | | `AuthChangeEvent.initialSession` is emitted to every subscriber | `onAuthStateChange` | Listeners that act on `signedIn` at subscription time must also act on `initialSession`. | | A client without an `asyncStorage` keeps pkce verifiers in memory | `SupabaseClient\(` | A directly constructed client whose pkce flow completes in another process, such as from an email link, passes a persistent `AuthClientOptions(asyncStorage: …)`. | | The retry backoff defaults are the same in every client | `retryOptions\|SupabaseRetryOptions` | Ask whether the old PostgREST curve matters. If it does, pass the options shown in the reference. | | The rest client and its builders are stateless | `=\s*await .*\.(insert\|upsert\|update\|delete)\(` | A write without `select()` resolves to `void`. Drop the assignment or add `.select()`. | | `userMetadata` is never null | `userMetadata\s*(\?\|==\|!=)` | Remove the dead null checks. | | `SupabaseClient` builds its own default HTTP client | `runWithClient` | Pass the client as `httpClient:` instead. | | A request that gets no response throws a transport exception | `on ClientException\|on TimeoutException` | Catch `SupabaseTransportException` around Supabase calls. | | A failing `accessToken` callback throws `AccessTokenException` | `accessToken:` and transport exception catches | Catch `AccessTokenException` where token failures were handled. | | The request timeout bounds idle time | `requestTimeout` | Add `.timeout(…)` on the builder where a total deadline was intended. | | Realtime throws exceptions instead of strings | `on String\|toString\(\)\.contains` near `subscribe`, `httpSend`, `track`, `send` | Catch `StateError`, `RealtimeApiException` or `RealtimeTransportException`. | | Cross-tab session sync is opt-in for standalone clients | `AuthClientOptions\(` | On web, pass `persistSession: true` where the session must be shared and persisted. | Search `lib`, `test`, `bin` and any other source folders with `grep -rnE '<pattern>'`. ## 8. Move every query to the typed `table()` API Follow the reference section "Moving from `from()` to the typed table API". Convert one table at a time and re-run `dart analyze` after each. Naming in the generated file: table `books` in `public` is `Books`, `BooksRow`, `BooksInsert` and `BooksUpdate`. A table in another schema carries the schema as a prefix, `inventory.books` is `InventoryBooks`, and `supabase.schema('inventory').from('books')` becomes `supabase.table(InventoryBooks.table)`. Columns are camelCase constants on the table class, `Books.authorId`. | Untyped | Typed | | ------------------------------------------------------ | ------------------------------------------------------------------------- | | `.from('books').select()` | `.table(Books.table).select()` | | `.select('id, title')` | `.selectOnly([Books.id, Books.title])`, read with `row.read(Books.title)` | | `.select('title, authors(name)')` | `.selectOnly([Books.title, Books.authors(Authors.name)])` | | `.eq('author_id', 2)` | `.where(Books.authorId.eq(2))` | | `.or('price.lt.10,in_print.eq.false')` | `.where(Books.price.lt(10) \| Books.inPrint.isFalse())` | | `.order('created_at', ascending: false)` | `.order(Books.createdAt.desc())` | | `.order('price', ascending: false, nullsFirst: false)` | `.order(Books.price.desc().nullsLast())` | | `.limit(3, referencedTable: 'books')` | `.embedded(Authors.books, (books) => books.limit(3))` | | `.insert({...})` | `.insert(BooksInsert(...))` | | `.insert([{...}, {...}])` | `.insertAll([BooksInsert(...), ...])` |
Ver no GitHub
Este SKILL.md e muito grande, entao o SkillsMP mostra aqui apenas a primeira secao. Ver no GitHub