Patches

A patch delivers Dart changes to devices running a specific release.

Publishing a patch

$ overpush patch android

One patch serves every phone type in the release. A small fix is usually under a megabyte.

$ overpush patch ios

The first patch for a release is usually a couple of MB; later ones are usually tens of KB.

By default the patch is built for the newest release on your computer. To patch a different release:

$ overpush patch android --release-version 1.4.0+31
$ overpush patch ios --release-version 1.4.0+31

Options

OptionWhat it does
--release-versionRelease to patch: a release id, a version such as 1.4.0+31, or latest. Defaults to the newest on disk.
--rollout-percentShare of devices to offer the patch to, 0–100. Default 100. See Rollouts.
--notesRelease notes for your own log. Shown in the dashboard.
-n, --dry-runBuild and check the patch, but don't publish it.
-y, --yesDon't ask for confirmation.
--patch-numberOverride the patch number. Defaults to the next unused one.
--allow-native-diffsPublish even though native code changed. Not recommended.
--allow-asset-diffsPublish even though assets changed. Not recommended.

What a patch can carry

A patch contains Dart code only. That covers most of what you change day to day:

It can't carry anything that isn't Dart:

Before publishing, the CLI compares the project with the release. If native code or assets changed, it stops and explains why. The --allow-*-diffs flags exist for the rare case where the change doesn't affect what the Dart code needs, such as an edited comment in a native source file. If your Dart code relies on the native or asset change, the patch will fail on devices.

Flutter features ready for patches

iOS releases built with CLI 1.2.7 or newer are ready for patches that use these, even if the release itself never did:

Layout & scrollingTabBar, TabBarView, DefaultTabController, PageView, IndexedStack, ListView.separated, GridView.builder, CustomScrollView, SliverAppBar, SliverList, SliverGrid, NestedScrollView, RefreshIndicator, Scrollbar, Wrap, Table, ExpansionTile, ReorderableListView, DraggableScrollableSheet
Async & stateFutureBuilder, StreamBuilder, ValueListenableBuilder, ListenableBuilder, AnimatedBuilder, StatefulBuilder, LayoutBuilder, OrientationBuilder
InputForm, TextField, TextFormField, Checkbox, CheckboxListTile, Radio, RadioListTile, Switch, SwitchListTile, Slider, RangeSlider, DropdownButton, DropdownMenu, Autocomplete, SearchBar, SegmentedButton, ChoiceChip, FilterChip, InputChip
Buttons & feedbackFilledButton, ElevatedButton, OutlinedButton, TextButton, IconButton, FloatingActionButton, PopupMenuButton, MenuAnchor, SnackBar, Tooltip, Badge, Chip, LinearProgressIndicator, CircularProgressIndicator
Dialogs & navigationshowDialog, AlertDialog, SimpleDialog, showModalBottomSheet, showDatePicker, showDateRangePicker, showTimePicker, Drawer, NavigationBar, NavigationRail, BottomNavigationBar, Hero, PageRouteBuilder
Gestures & listsDismissible, InkWell, GestureDetector, Draggable, LongPressDraggable, DragTarget, InteractiveViewer, ListTile, Card, Divider
AnimationAnimatedContainer, AnimatedOpacity, AnimatedSwitcher, AnimatedCrossFade, AnimatedList, AnimatedSize, TweenAnimationBuilder, FadeTransition, SlideTransition, ScaleTransition
CupertinoCupertinoButton, CupertinoSwitch, CupertinoPicker, CupertinoDatePicker, CupertinoSlidingSegmentedControl, CupertinoAlertDialog, CupertinoActionSheet
TextEvery TextStyle field (fontFeatures, decoration, shadows, fontStyle, …), Text.rich, RichText, SelectableText
More layout & MaterialStack / Positioned, AspectRatio, FittedBox, ClipPath, CustomPaint, BackdropFilter, ShaderMask, Transform, Visibility, SafeArea, Stepper, DataTable, ExpansionPanelList, CarouselView, BottomAppBar, ToggleButtons, ActionChip, CalendarDatePicker, ListWheelScrollView, SliverPersistentHeader, SliverFillRemaining, NavigationDrawer, PopScope, showSearch, showMenu, MaterialBanner
Your own animations & statewith SingleTickerProviderStateMixin, TickerProviderStateMixin, AutomaticKeepAliveClientMixin, WidgetsBindingObserver, AnimationController, TabController, PageController, ScrollController, FocusNode, AnimatedPositioned, AnimatedAlign, AnimatedPadding, RotationTransition, SizeTransition
More CupertinoCupertinoPageScaffold, CupertinoNavigationBar, CupertinoTabScaffold, CupertinoTextField, CupertinoSearchTextField, CupertinoActivityIndicator, CupertinoSlider, CupertinoCheckbox, CupertinoListSection, CupertinoContextMenu
ServicesClipboard, HapticFeedback, SystemChrome, input formatters, Overlay, OverlayPortal, Focus, compute
Generic typesshowDialog, showModalBottomSheet, Navigator.push and Future.wait with bool, String, int, Map<String, dynamic> and dynamic
DartFuture.wait, Future.any, Completer, Timer.periodic, Stream.periodic, StreamController, runZonedGuarded, jsonEncode / jsonDecode, base64, RegExp, Uri, DateTime, dart:math, records and patterns

If your app depends on any of these packages, their common APIs are ready too: get, provider, flutter_bloc, flutter_riverpod, go_router, dio, http, shared_preferences, intl, url_launcher, cached_network_image, path_provider. Nothing is added for a package your app doesn't use.

Anything your app's own code uses is ready too. If a patch reaches for something neither list covers and it changes too much, the CLI names it and stops before publishing; keep it out of the patch or ship a release.

Limits

Patch numbers

Patches are numbered 1, 2, 3… per release. Devices only ever move forward to a higher number than the one they have. Each patch contains every change since the release, so a device on patch 1 can go straight to patch 4.

Don't reuse or lower patch numbers. A device that already has patch 5 ignores a new "patch 3". Use --patch-number only if you know why you need it.

Inspecting patches

Open the release in the console: every patch with its status, rollout, installs and failures. The CLI can also list the patches built on your computer:

$ overpush patches list
$ overpush patches list
$ overpush patches info --patch-number 4

info shows the size, rollout, notes, and whether this is the patch devices currently receive.

Testing a patch before everyone gets it

  1. Try the release on your own phone with overpush preview android.
  2. Run overpush patch android --dry-run to make sure it builds and passes the checks.
  3. Publish with a small rollout: overpush patch android --rollout-percent 5.
  4. Watch the release page in the console for failures.
  5. Raise the rollout with overpush patches rollout <n> --percent 100, or from the console.
  1. Try the release on your own iPhone with overpush release ios --artifact app and overpush preview ios.
  2. Run overpush patch ios --dry-run to make sure it builds and passes the checks.
  3. Publish with a small rollout: --rollout-percent 5.
  4. Watch the release page in the console for failures.
  5. Raise the rollout with overpush patches rollout <n> --percent 100, or from the console.