Documentation
Mobile
Web
TV

All but React Native are in beta.

Desktop App
docs

BuoyDevTools

The BuoyDevTools widget is the entry point for Buoy on Flutter — the analog of React Native's FloatingDevTools. It wraps your app and renders a draggable floating button that opens a menu containing all your registered debugging tools.

Explore the floating menu

1 / 7

This browser example runs the menu over a mock app. Drag the grip to reposition it and try the available controls.

9:41
Loading live demo…
The real Buoy menu, not a recording — this is the React Native build over a mock app, and the Flutter BuoyDevTools bubble and dial are a 1:1 port of it. Step through the tour, or just start dragging and tapping.

Basic Usage

dart
import 'package:buoy/buoy.dart';

MaterialApp(
  builder: (context, child) => BuoyDevTools(
    child: child ?? const SizedBox.shrink(),
  ),
)
import 'package:buoy/buoy.dart';

MaterialApp(
  builder: (context, child) => BuoyDevTools(
    child: child ?? const SizedBox.shrink(),
  ),
)

The buoy umbrella registers its bundled tools when it mounts. To sign in, run npx --package=@buoy-gg/core buoy login. Then run the app with flutter run --dart-define-from-file=.env.local. The widget reads the token by itself. See Sign In.

Mount it from MaterialApp.builder (or MaterialApp.router) so it sits above your Navigator and survives every route change.

Props

PropTypeDefaultNotes
childWidgetrequiredYour app (usually the MaterialApp builder child)
licenseKeyString?BUOY_KEY dart-defineLeave unset to use the buoy login token. Or pass your account key. Widget stays debug-only
signInBuoySignIn?nullSign in with a code instead: BuoySignIn(appId: 'com.acme.shop'). Debug builds only
deviceNameString?autoLabel in Buoy Desktop / MCP. Default: 'Flutter App (ios · 2c1d)' — the app, the platform, and the last 4 of the install id
deviceIdString?autoLeave unset: each install mints flutter-app-ios-<8 hex> once and keeps it. If you pin one it MUST be unique per device — two devices under one id look like one device to the broker
socketUrlString?autoLAN broker URL for physical devices
toolsList<BuoyTool>[]Extra custom tools beyond self-registered ones

How Tools Register

React Native discovers tools by optional-require; Dart has no equivalent, so Flutter tools register explicitly — but with the umbrella package you never write the call yourself:

  • Umbrella — package:buoy calls the registration functions for its bundled tool list when BuoyDevTools mounts. Adding a separate dependency does not extend that list. Install and it shows up:

    bash
    flutter pub add buoy
    
    flutter pub add buoy
    
  • À la carte — depend on the individual packages instead, call registerBuoyNetwork() (etc.) yourself before runApp, and mount BuoyDevTools from buoy_core.

A few tools still need one app-owned hook — the router for Routes, a ProviderScope observer for Riverpod, BuoyImage for Images, a search callback for Impersonate. The umbrella can't supply those, so each tool page notes its one line.

Custom Tools

Need something specific to your app? Pass your own BuoyTools via the tools prop (or Buoy.registerTool before mount):

dart
import 'package:buoy/buoy.dart';
import 'package:flutter/material.dart';

MaterialApp(
  builder: (context, child) => BuoyDevTools(
    tools: [
      BuoyTool(
        id: 'flags',
        name: 'Flags',
        color: const Color(0xFF34D399),
        icon: (size, color) => Icon(Icons.flag, size: size, color: color),
        screenBuilder: (context) => const FeatureFlagDebugger(),
      ),
    ],
    child: child ?? const SizedBox.shrink(),
  ),
)
import 'package:buoy/buoy.dart';
import 'package:flutter/material.dart';

MaterialApp(
  builder: (context, child) => BuoyDevTools(
    tools: [
      BuoyTool(
        id: 'flags',
        name: 'Flags',
        color: const Color(0xFF34D399),
        icon: (size, color) => Icon(Icons.flag, size: size, color: color),
        screenBuilder: (context) => const FeatureFlagDebugger(),
      ),
    ],
    child: child ?? const SizedBox.shrink(),
  ),
)

See Custom Tools for the full schema and desktop-sync adapters.

Draggable Button

The floating button can be dragged anywhere on screen. It remembers its position between sessions, so it stays where your team likes it, and it tucks out of the way on its own while the dial or a tool is open. Tools you minimize dock above it and come back with a tap.

Beyond the in-app menu

BuoyDevTools is also the source of truth for Buoy's other surfaces. The same tools you see in the menu sync out over a local broker, so once this is set up you can — with no extra code — also:

  • open the Buoy Desktop dashboard and inspect the same live app on a full screen, or
  • point an AI agent at your app with the MCP server.

Simulators and emulators connect automatically. Physical devices take one socketUrl pointing at your machine:

dart
BuoyDevTools(
  socketUrl: 'http://192.168.1.20:42831',
  child: child ?? const SizedBox.shrink(),
)
BuoyDevTools(
  socketUrl: 'http://192.168.1.20:42831',
  child: child ?? const SizedBox.shrink(),
)

The current sync target and connection state show up in the menu's Settings tab under desktop sync.

Debug builds by default

BuoyDevTools renders your child and nothing else outside a debug build — no button, no dial, no sync, no capture. Release builds has the flag to change that. This describes initialization managed by the widget; separately initialized code has its own behavior.

Two React Native options have no Flutter counterpart today:

  • environment — the RN floating button prints an environment badge (local, dev, staging, qa, prod). The Flutter bubble doesn't.
  • headless — RN can mount sync-only with no on-device UI.

Both are on the Flutter roadmap.

Release builds

A release build has no Buoy tools by default. To keep them in a test build, add this flag:

bash
flutter build apk --release --dart-define=BUOY_ENABLE_IN_RELEASE=true
flutter build apk --release --dart-define=BUOY_ENABLE_IN_RELEASE=true

Without the flag, Buoy's tools are left out of your app.

That build needs a Pro or Business plan. A buoy login dev token won't work there, so testers sign in with a code:

dart
BuoyDevTools(signIn: const BuoySignIn(appId: 'com.acme.shop'), child: child)
BuoyDevTools(signIn: const BuoySignIn(appId: 'com.acme.shop'), child: child)

First, add app: and your app id at buoy.gg/dashboard/sites.

If you guard your own Buoy setup with kDebugMode, use buoyCompiledIn instead. It is true in debug builds, and in release builds with the flag.

Network rules, slow and offline modes, and Bug Links loading also need the Buoy menu on screen. With no paid plan or no menu, saved rules do nothing. An amber FAKE NETWORK pill shows while a rule or a speed setting is on. Press and hold it to stop.

Keep the flag out of your store build. Android also needs the INTERNET permission in your main manifest, which a real app that makes web calls already has.

Next Steps