Flutter / Dart SDK
feat_sdk is the Flutter and Dart client SDK. Like the browser SDK, it evaluates flags remotely: it sends the current context to feat’s edge, receives the resolved values back, and caches them so reads are synchronous. Your targeting rules and segments never reach the device. A live stream keeps the cached values fresh.
It has a single runtime dependency (http), so it works in pure-Dart backends as well as Flutter apps.
Install
Section titled “Install”dependencies: feat_sdk: ^0.1.0Then dart pub get (or flutter pub get).
import 'package:feat_sdk/feat_sdk.dart';
final client = await FeatClient.initialize( FeatClientConfig( apiKey: 'feat_cs_...', // client-side ID or mobile key context: EvalContext.user('user-123'), // optional: set now or later ),);
final enabled = client.getBool('checkout-v2', false); // syncfinal greeting = client.getString('hero-greeting', 'Hi');final limit = client.getNumber('upload-limit', 10);final config = client.getObject('theme', {'mode': 'light'});Use a client-side ID (feat_cs_…) or a mobile key. Never ship a server key in an app. Values evaluate against the context you set, so reads return the default until a context is present.
getDetail returns the reason and variation alongside the value:
final detail = client.getDetail('checkout-v2', defaultValue: false);// detail.value, detail.variationId, detail.reasonContexts
Section titled “Contexts”Build a context from a raw map or with the typed builder:
// Raw map (matches the wire shape exactly):final ctx = EvalContext.fromMap({ 'targetingKey': 'user-123', 'user': {'key': 'user-123', 'plan': 'pro'}, 'device': {'key': 'ios-42', 'os': 'ios'},});
// Typed builder:final ctx = (EvalContextBuilder() ..targetingKey('user-123') ..kind('user', 'user-123', attributes: {'plan': 'pro'})) .build();
await client.setContext(ctx);EvalContext.user('user-123') is a shorthand for the common single-user case. See Contexts for the model.
Reacting to flag changes
Section titled “Reacting to flag changes”client.changes is a broadcast stream of per-flag changes, fired after a context change or a new snapshot from the server:
final sub = client.changes.listen((change) { print('${change.key} changed'); setState(() {}); // in Flutter, re-read the flags you render});Adding the first listener opens the live stream; removing the last closes it (the default StreamingMode.followSubscription). Use StreamingMode.always to keep it open, or StreamingMode.never to rely on polling only.
Anonymous contexts and offline snapshots
Section titled “Anonymous contexts and offline snapshots”With anonymous: true and no context, the client mints a stable per-install anonymous context. It stores the anonymous key and the last evaluated snapshot through a FeatStorage, so the next launch renders immediately while the SDK refreshes. A persisted snapshot holds resolved values only (keyed by context), never your rules.
The core package is pure Dart, so its default InMemoryStorage keeps everything for the process lifetime only. To survive app restarts, pass a persistent FeatStorage:
final storage = await SharedPreferencesFeatStorage.create();final client = await FeatClient.initialize( FeatClientConfig(apiKey: 'feat_cs_...', anonymous: true, storage: storage),);SharedPreferencesFeatStorage is Flutter glue (it pulls in shared_preferences), so it lives in the SDK’s example rather than the pure-Dart core: copy it into your app or implement the small FeatStorage interface (read / write / delete) over any store you like.
Lifecycle
Section titled “Lifecycle”Poll cadence defaults to 30 seconds and relaxes while the stream is connected.
In Flutter, pause live updates while the app is backgrounded and resume on foreground. The example ships a FeatLifecycleObserver (a WidgetsBindingObserver) for this; or call client.pause() / client.resume() directly.
Call close() when you are done (e.g. in a dispose) to stop polling, close the stream, and release the HTTP client:
await client.close();OpenFeature
Section titled “OpenFeature”To use feat through the OpenFeature Dart API, add the feat_openfeature provider. See OpenFeature.
Related
Section titled “Related”- Evaluation model - how remote evaluation works and why.
- Browser SDK - the JavaScript equivalent, same remote-evaluation model.
- API keys for client-side IDs and mobile keys.
- Contexts for the input shape.