Skip to content
7 min read Guides Flutter

What's New in Flutter SDK 2.1

Flutter SDK 2.1 was tagged on 14 October 2026, about two hours after Flutter SDK 1.2. There is no 2.0 tag: 2.1.0 is the release after 1.2.0. Together they are the largest change since Flutter SDK 1.1. The board gets a new look, and the four defects that the 1.1 notes listed as still open are fixed. This post covers both tags, because 1.2.0 contains a source break of its own.

The short version

  • New look: FeedbackList draws Showcase cards by default, with a search field and a Sort & Filter sheet. listStyle: FeedbackListStyle.classic keeps the 1.x list.
  • Fixed: the SDK creates a user id when you do not pass one, removing a vote works, posting a comment works, and the email typed into the form reaches FeedbackKit.
  • Fixed in 1.2: the Team badge on comments renders, and a request with a status this build does not know is dropped from the list instead of showing as Pending.
  • Breaking: Dart 3.6 and Flutter 3.27 are now the minimums, Comment.feedbackId is nullable, and RegisterUserRequest no longer has an id getter.
  • Install: 2.1 is a git dependency on the 2.1.0 tag. pub.dev still holds 1.0.0 and 1.0.1.

Installing 2.1

flutter pub add feedbackkit_flutter still installs 1.0.1, and a ^2.1.0 constraint does not resolve from pub.dev. Depend on the tag in the SDK's repository:

dependencies:
  feedbackkit_flutter:
    git:
      url: https://github.com/Swiftly-Developed/SwiftlyFeedbackKit-Flutter-SDK.git
      ref: 2.1.0

Your app needs Dart 3.6 and Flutter 3.27 or later. Earlier versions of the SDK asked for Dart 3.0 and Flutter 3.10.

The Showcase list

Each request is a Material 3 card: a status line with its own glyph, the title, two lines of the description, the category and comment count in the footer, and a vote pill tinted with your theme's primaryColor. Above the cards sit a search field and a Sort & Filter button. The button opens a bottom sheet with four sort orders (Votes, Newest, Oldest and Comments) and Status and Category filters. Active filters show as chips with a Clear button, and a filter that matches nothing shows No Matching Requests with Clear Filters.

Search, sort and filters run on the device over the requests already loaded, so changing them does not reload the list. Search matches the title and the description, ignoring case and accents. Cards keep their place while someone votes, and a failed vote rolls back and shows a snackbar. The list remembers the reader's sort between launches, but never the filters, so nobody comes back to a list that is quietly narrowed.

The cards follow the host app's ColorScheme, including dynamic colour and dark theme, mirror for right-to-left languages, scale text up to 2.0, and give every control a 48dp touch target and a screen-reader label. Inside a CupertinoApp, the list brings its own Material 3 theme and opens the sheet as a Cupertino modal popup.

To keep the 1.x look, set the style once on the provider, or on one list:

FeedbackKitProvider(
  apiKey: const String.fromEnvironment('FEEDBACKKIT_API_KEY'),
  listStyle: FeedbackListStyle.classic,
  child: const MaterialApp(home: IdeasScreen()),
)

Driving the list from your own app bar

FeedbackListController holds the search text, the sort and the two filters. Create one in your widget's state, dispose it with the state, and share it between the list and a FeedbackSortFilterButton:

Scaffold(
  appBar: AppBar(
    title: const Text('Trailmate ideas'),
    actions: [FeedbackSortFilterButton(controller: _controller)],
  ),
  body: FeedbackList(
    controller: _controller,
    showToolbar: false,
    onFeedbackTap: _openRequest,
  ),
)

A list that is given a controller does not persist the sort; that is left to the owner. Showcase also takes showStatusBadge, showCategoryBadge, showCommentCount, showVoteCount, allowUndoVote, showStatusFilter and showCategoryFilter. The Classic list ignores them.

The fixes

Each of these was present in pub.dev 1.0.1 and in every tag through 1.2.0.

  • A user id from the start. When the provider gets no userId, the SDK creates one in the form local_ plus a UUID, stores it, and reuses it on the next launch. An id you pass now wins over a stored one and replaces it. The list waits until the id is ready, so the opening load already knows which requests the person voted for.
  • Removing a vote works. The user id now travels in the request body, where the server reads it.
  • Posting a comment works. The comment carries the user id the server requires.
  • The form's email reaches FeedbackKit. It is sent under the key the server reads, so the person who filed a request can be emailed when its status changes. The mailing-list opt-in from 1.1 now records the choice too, on projects with an email-list integration switched on, a Pro feature. FeedbackItem.userEmail reads the address back.
  • The status-change opt-in on votes. votes.vote() takes notifyStatusChange and an email, sent under the keys the server reads. The old notifyOnStatusChange still compiles, with a deprecation warning.
  • Server errors keep their message. A detailed error response used to surface as a generic NetworkError. It now becomes the matching error class, carrying the server's message and code, plus a new field.
  • The cards speak the reader's language. The comment count and age on FeedbackCard now come from the catalog, Arabic lays out right to left, and the vote, retry, submit and opt-in controls are announced as buttons and checkboxes.

Also new

  • feedback.list() and comments.list() read every page when you leave page out, and comments.list() gained page and perPage.
  • RegisterUserRequest takes userId and an optional mrr, the two fields the server reads.
  • A 429 now raises RateLimitError, a subclass of FeedbackKitError, with retryAfterSeconds when the server sends it. The SDK does not retry for you.
  • FeedbackKitStorage is exported and can be passed to the provider as storage.

Breaking changes and how to migrate

In 1.2.0, under a minor version number

Comment.feedbackId is String?. The server never sends that key on a comment, so in 1.1 it always decoded to an empty string. It is now null, and code that reads it as a String no longer compiles. Use the id of the request you loaded the comments for:

// Flutter SDK 1.1
final String parent = comment.feedbackId;

// Flutter SDK 1.2 and later: the request you loaded the comments for
final String parent = feedback.id;

Unknown statuses and categories throw. FeedbackStatus.fromJson and FeedbackCategory.fromJson used to turn a token they did not know into pending or other. They now throw UnknownEnumValueException, which the package exports. feedback.list() drops those rows and keeps the rest in order. If you call fromJson yourself, catch the exception.

In 2.1.0

  • Dart 3.6 and Flutter 3.27. Raise the environment in your pubspec.yaml if it is lower.
  • RegisterUserRequest.id is gone. Read userId instead. The id: constructor argument still compiles, deprecated, and is sent as user_id. email and name also still compile, deprecated, and are no longer sent, because the server ignores them.
  • The default list changed. Without listStyle, your users see Showcase cards on the next build.
  • A plain-HTTP baseUrl throws. The client refuses to send the API key over cleartext and throws an ArgumentError, except for a loopback address such as localhost, for a local server.
  • Stricter event tracking. events.track() throws a ValidationError when there is no user id, the name is empty, or a property value is not a string, number or boolean. Numbers and booleans are sent as strings.
  • Error messages changed. Errors now carry the server's own message where they used to carry a placeholder. Branch on the class or code, not on the text.

Calling setUserId before a vote is no longer needed. Voting, removing a vote and tracking an event with no id at all are refused before any request is sent, which the generated id makes rare.

How FeedbackKit fits in

With the email now reaching FeedbackKit, someone who files from your Flutter app hears back when your team moves their request along. Here is how that looks in FeedbackKit, with sample data from a fictional hiking app:

Telling the people who asked

Your team gets email and push on every plan, Slack on Pro and up. The person who asked is emailed when the new status is on the project's list.

Upgrading

  • Point pubspec.yaml at ref: 2.1.0, raise the Dart and Flutter minimums, and run flutter pub get.
  • Fix the compile errors: Comment.feedbackId and RegisterUserRequest.id.
  • Choose Showcase or Classic. Look at Showcase in dark theme, at large text sizes and in Arabic before you ship.
  • If you set a placeholder user id to get round the 1.x defects, you can drop it and let the SDK create one. If your app has its own accounts, keep passing your id.
  • Remove any workarounds for removing votes, posting comments or the form's email.

The notes for earlier versions are in Flutter SDK 1.0 and Flutter SDK 1.1, and the Flutter SDK 1.0 tutorial covers apps on the pub.dev build. The current Flutter tutorial is the place to start a new integration, and the reference is in the Flutter SDK docs.

Every plan includes the Flutter SDK. Start free and put the new board in your next build.

Keep reading

Collect feedback in your own app

FeedbackKit ships SDKs for Swift, Kotlin, React Native, Flutter and JavaScript, and syncs what your users ask for into the tracker your team already uses.