Skip to content

Releases: respawn-app/FlowMVI

3.3.0-alpha03

04 Jan 21:45
7a1405e

Choose a tag to compare

3.3.0-alpha03 Pre-release
Pre-release

This is a small release that downgrades kotlin to 2.2.21 until https://youtrack.jetbrains.com/issue/KT-83395 is resolved.
If you target 2.3.0, keep using alpha02. If you face KT-83395 or any other issues, consider alpha03.

3.3.0-alpha02

14 Dec 10:36
8ada7fd

Choose a tag to compare

3.3.0-alpha02 Pre-release
Pre-release

📊 Performance Metrics

New artifact: :metrics is here!

With FlowMVI in just a 5 lines of code you can now set up metrics collection to understand the performance and usage patterns of your app!

FlowMVI metrics collect over 66 different stats including speed of intent handling, state updates, error frequencies, data loading delays, bootstrapping time and lifecycle events, and more, then lets you upload to any popular metrics ingestion service such as OpenTelemetry, Prometheus, OpenMetrics etc, and visualize them in dashboards:

val metrics = collectMetrics(
    reportingScope = applicationScope
)
reportMetrics(
    metrics = metrics,
    sink = OtlpJsonSink(BackendSink()), 
)

The debugger IDE plugin and desktop apps have been upgraded to support the ingestion of metrics and also visualize them in a similar way out of the box, with minimal setup required to send metrics to the debugger:

Screen.Recording.2025-12-14.at.11.06.00.AM.mov

Metrics are being benchmarked and are optimized to minimally influence the performance of your business logic, so that you can just plug them in your store configuration once and enjoy the benefits everywhere.

Get started by reading the documentation

🚀 New Hooks:

  • onActionDispatch hook will trigger when side-effects are dequeued, as opposed to onAction which triggers when enqueued
  • onIntentEnqueue hook will trigger when intents are enqueued, as opposed to onIntent which triggers when dequeued

ShutdownContext

ShutdownContext now implements StoreLifecycle which holds a reference to the last store lifetime. Previously, any lifecycle was
grabbed from the Store itself which may not be the one that onStop was invoked with. This should improve reliability.

This may be a behavioral breaking change if you relied on StoreLifecycle inside of onStop. Worth double-checking your onStop hooks to be safe.

🚢 Other New Stuff

Note: Debugger of version 3.3.0 may be incompatible with FlowMVI 3.2x and older, downgrade or upgrade one of these to fix.

  • Debugger will now merge events from stores if they have the same name
  • Add debounceIntents decorator
  • Migrate PluginTestScope to be an interface instead of class.
  • Add validation to BatchIntentsDecorator modes. Worth re-checking that you don't pass invalid values there before shipping.
  • Each StoreConfiguration now has storeId a unique UUID of the store instance. Using static unique names is now even more important with metrics to aggregate events per-screen reliably.

🐞 Bug Fixes

Important fix: onUndeliveredAction callback wasn't properly wired and was never invoked since 3.1.0, fixed with this release + tests added that should prevent such issues in the future.

  • add failsafe to debug client store when events can't be deserialized
  • add failsafe to debug server when events can't be deserialized
  • let StoreConfiguration's state be covariant

Deps

  • Kotlin 2.3.0-RC3
  • Compose 1.10-rc1
  • Ktor 3.3.3

Safe upgrade checklist

  • Check onStop callbacks that use StoreLifecycle methods awaitUntilClosed etc for correctness
  • Upgrade debugger IDE plugin
  • Check onUndeliveredAction usages which should now work
  • Check batchIntents decorator configuration for validity of passed values
  • Wire/migrate to onActionDispatch or onIntentEnqueue based on your needs (analytics plugins etc)

Rest of the changelog

  • add metrics decorator
  • feat!: let ShutdownContext implement StoreLifecycle and pass one-time shutdown context there
  • refactor metrics collector for safe event handling across restarts
  • implement Metrics api for decoupling metric collection and flushing
  • implement default metrics flusher plugin
  • implement OpenMetricsSink
  • implement otel metrics
  • add metrics schema versioning surface
  • add metrics showcase to the sample app
  • implement benchmarks evaluating metrics collection overhead
  • add debounce intents decorator
  • feat!: let ShutdownContext implement StoreLifecycle and pass one-time shutdown context there
  • add debounce intents decorator
  • feat!: add validation to BatchIntentsDecorator modes
  • add wasm-wasi target to metrics and common debugger code
  • introduce stable store IDs for debugging and metrics
  • enable wasmJs and js for debugger plugin module
  • implement DebuggerSink for metrics, wire metrics to sample app
  • add storeName parameter to client events
  • accumulate metrics in debug server
  • implement metrics visualization in the debugger
  • add documentation for metrics visualization in debugger
  • update deps
  • downgrade kotest due to kotest/kotest#5203
  • apply hack for JetBrains/intellij-platform-gradle-plugin#2062
  • downgrade intellij plugin due to JetBrains/intellij-platform-gradle-plugin#2062
  • migrate compose deps to version catalog
  • replace material debugger icons with custom iconpack
  • migrate sample app from material icons extended dependency
  • temporarily set logging level to quiet to silence fp warning
  • cover enqueue dispatch hooks with tests
  • update agents and SECURITY.md
  • provide fixed timestamp for tests to otel metrics mapper
  • remove fluxo benchmarks
  • add tests for sinks and basic apis
  • more tests for edge cases of sinks
  • add tests for quantiles/ema/perfmetrics
  • cleanup to improve testability of new metrics internals
  • add tests for debounce decorator
  • add test utils for metrics
  • enhance and simplify test dsl for new tests
  • add utils to test metrics with real store
  • add full test suite for the MetricsCollector and plugin composition
  • align collector tests
  • update readme with metrics and more benefits, reduce size
  • temp remove claude workflow
  • update agents and SECURITY.md
  • added testing guidance for agents
  • create a documentation page on Metrics

Full Changelog: 3.2.1...3.3.0-alpha02

3.2.1

06 Nov 16:49
3a821db

Choose a tag to compare

Breaking changes

  • Android minimum API requirement is now 23, because Google forced us by upgrading it in activity-ktx.

🚀 New Features

Enforce must-use return value (#152).

If you enable compiler flag -Xreturn-value-checker=check, the IDE will warn you when you create a store/subscription/plugin and not use it.

  • add lambda intent emit { } lambda overload
  • improve return type in store.test { } with SubscriptionAware to test subscriptions. You can now access subscriberCount in tests.
  • Batch intent decorator now exposes onUnhandledIntent. This is used when the intent is batched, but then was unhandled. This is likely a temporary solution to "catch" those intents, as due to intents being deferred, we can' use our regular onUndeliveredIntent functions.
  • implement new sample showcasing serialized state transactions

🐞 Bug Fixes

This update includes many important fixes for decorators and child stores.

  • #173 ensure delegate unsubscribes child stores
  • fix off-by-one in batch intents decorator
  • harden decorator batching and timeouts
  • treat batched intents as undelivered on stop
  • call onUndeliveredIntent correctly when buffer overflows
  • cancel coroutines launched in plugins during tests when harness block ends. This fixes "hanging" tests due to plugins launching coroutines.
  • allow decorators to define handlers even if children don't specify a hook. this fixes skipped logic in decorators because the plugin didn't define a callback.
  • synchronize batched intent flushing

❔ Other

  • extend update_deps.sh to autobump docs
  • Enhance documentation for updateState function (#169)
  • Add Claude Code GitHub Workflow (#175)
  • update config
  • update deps: kotlin 2.2.21
  • promote subscription aware APIs to stable
  • add more tests for delegates
  • let kotest run on more platforms since 6.0
  • trim redundant tests
  • expand decorator test coverage
  • test coverage for conflate decorators
  • validate batch queue flush
  • enable return value checker and other flags
  • change syntax of setOnce to be infix
  • fix deprecations
  • gradle 9.2

📚 Docs

add docusaurus-plugin-llms for AI-friendly documentation

New Contributors

Full Changelog: 3.2.0...3.2.1

3.2.0

20 Sep 10:26
6f974e8

Choose a tag to compare

3.2.0

🚀 New Features

  • Child and Delegated Stores: New plugins childStorePlugin and storeDelegatePlugin allow composing stores into tree-like hierarchies and splitting responsibilities more easily. This enables better code organization by creating parent-child relationships between stores, where child stores can handle specific sub-features while maintaining their own lifecycle. The sample app demonstrates progressive content loading implemented with just 7 lines of code using this feature. Learn more in the delegates documentation.
  • SubscriptionAware: PipelineContext now implements SubscriptionAware interface to observe subscribers from within the store, enabling plugins to react to subscription lifecycle events. This foundation powers the completely reimplemented whileSubscribed plugin, which now includes a configurable delay before reporting unsubscriptions to avoid wasted resources during configuration changes (e.g., Android screen rotations). This makes resource management more efficient while maintaining responsiveness.
  • Updated IDE plugin live templates to generate plugins for specific stores
  • Custom descriptive exceptions for duplicate store startup
  • Added logging convenience functions like logi, logw, loge and more.

🧨 API Changes

  • Removed deprecated parentStore and savedState plugins
  • Saver API Changes: recover function deprecated in favor of new RecoveringSaver
  • Changed file saver path parameters to lazy lambdas (previous API deprecated)
  • Removed inline from CallbackSaver to fix compiler crashes
  • Migrated to context parameters partially (old receiver functions un-deprecated)

🐞 Bug Fixes

  • Fixed no-op saver test throwing ClassCastException on JVM
  • Created parent directories when writing files on native
  • Fixed saver on Native throwing obscure errors without considering recovery
  • Fixed no message when duplicate plugin installed in store
  • Fixed clipboard copy not working in debugger
  • Added interruption support to blocking file IO calls in save state plugin
  • Added missing DelicateStoreApi to state property
  • Added missing name parameter to init plugin

⚙️ Dependencies

  • Kotlin 2.2.20 (minimum supported: 2.0.x)
  • Gradle and Compose bumped to release versions
  • Compose Multiplatform 1.9.0
  • Kotlinx.datetime 0.7.1.

❔ Other

  • Android compile SDK updated to 36
  • Recreated Android keystore (made sample keystore optional for publishing)
  • Updated ConnectScreen UI of the debugger to fix layout issues
  • Added Google Play publishing requirements to sample app
  • Improved test task output
  • Added app store screenshots
  • Await startup completion in store test DSL
  • Refactored FileAccess to use kotlinx.io when possible

📚 Docs

  • Added documentation for delegated stores
  • Documented store delegate and child stores code
  • Updated documentation of whileSubscribed plugin and composable stores
  • Updated docs website title style

Testing

  • Added tests for various savers
  • Added tests for file write/read functions
  • Added tests for child stores and delegates
  • Added tests for new whileSubscribed plugin
  • Added tests for store lifecycle

Contributors

Changes since alpha06:

  • added logging convenience functions
  • CMP 1.9.0 and Kotlin 2.2.20

3.2.0-alpha06

13 Aug 11:11
3.2.0-alpha06
6b49db5

Choose a tag to compare

3.2.0-alpha06 Pre-release
Pre-release

🐞 Bug Fixes

  • change file saver path parameters to lazy lambdas. The previous API for FileSaver has been deprecated. This is an improvement needed because platforms like Android require accessing the file system before they can get the file path for caching. With this change, the lambda is accessed on the background thread.
  • fix no op saver test throwing ClassCastException sometimes on jvm. Rare bug that pops up for unknown reasons on Android
  • remove inline from CallbackSaver to fix compiler crashes.
  • Migrated to context parameters partially, the old receiver functions are un-deprecated now. Please open a ticket if you face any issues due to the usage of context parameters.

Dependencies:

  • Kotlin 2.0.20-beta. The minimum supported kotlin version is 2.0.x and above.
  • compose 1.9.0-beta
  • Kotlinx.datetime 0.7.1. This repo was migrated away from Kotlinx.datetime.Instant.

3.2.0-alpha05

13 Jun 13:23
049f794

Choose a tag to compare

3.2.0-alpha05 Pre-release
Pre-release

🐞 Bug Fixes

  • create parent directories when writing to a file on native
  • fix recovering saver calling deprecated recover which throws, not allowing null values

❔ Other

  • refactor FileAccess to always use kotlinx.io when possible
  • add tests to file write/read functions

3.2.0-alpha04

12 Jun 10:56
5d370be

Choose a tag to compare

3.2.0-alpha04 Pre-release
Pre-release

🐞 Bug Fixes

  • fixed Saver on Native is throwing obscure errors without considering recovery
  • update deps - Kotlin 2.2-RC2, CMP 1.8.1

❔ Other

  • fix typo in sample index.html
  • add gunk required for google play publishing to the sample app.
  • general code cleanup
  • add app store screenshots

3.2.0-alpha03

24 May 06:31
0c41905

Choose a tag to compare

3.2.0-alpha03 Pre-release
Pre-release

🚀 New Features

  • New plugins: childStorePlugin and storeDelegatePlugin allow you to compose stores into tree-like hierarchies and split responsibilities even more easily. Learn more in the new doc page
  • Let PipelineContext implement new SubscriptionAware interface to allow observing subscribers from within the store
  • Completely new implementation of whileSubscribed plugin based on new SubscriptionAware support, that now includes a small delay for reporting unsubscriptions to avoid wasted resources during configuration changes on Android. Tests for the plugin have been expanded. The delay can be configured via a parameter.
  • implement sample app showcase for the delegated stores feature. It implements a progressive content loading feature with 7 lines of code.
  • update IDE plugin live templates to allow generating plugins for a specific store or general store
  • Use custom, more descriptive exceptions for duplicate store startup

🧨 API Changes

  • remove deprecated parentStore and savedState plugins
  • The recover function is now deprecated in Savers. Instead, a new RecoveringSaver is introduced that does the same thing but works not only in framework code, but when you call save and restore as well. Due to compiler bugs, signatures of some methods had to change, so it may introduce small source breaking changes.

🐞 Bug Fixes

  • add missing name parameter to init plugin
  • add missing DelicateStoreApi to state property
  • await the completion of startup on store test DSL. This should improve test stability.
  • add interruption support to blocking file IO calls in save state plugin
  • fix no message when duplicate plugin is installed in store. Previously it would throw cryptic "kotlin.Unit"
  • fix bogus compiler errors with usages of inline in Saver overloads
  • fix clipboard copy not working in the debugger

Dependencies

  • Kotlin 2.2-RC
  • CMP 1.8.1

❔ Other

  • update android compile sdk to 36
  • remove and re-create android keystore. Make sample keystore optional for publishing.
  • Update ConnectScreen ui, use ImageVector logo (#145)
  • bump actions/upload-artifact from 4.6.1 to 4.6.2 (#144)
  • add rules for AI
  • cleanup code and address deprecations
  • add tests for store lifecycle
  • update docusaurus
  • improve test gradle task output
  • tests for child stores and delegates
  • write tests for the new whileSubscribed plugin
  • update docs website title style

📚 Docs

  • add documentation for delegated stores
  • document store delegate and child stores code
  • update documentation of whileSubscribed plugin and composable stores

New Contributors

Full Changelog: 3.2.0-alpha01...3.2.0-alpha03

3.2.0-alpha01

15 Mar 10:17
b0d3cf5

Choose a tag to compare

3.2.0-alpha01 Pre-release
Pre-release

⚙️ Dependencies

  • Compose Multiplatform 1.8.0-alpha04. This compose release contains breaking changes, such as dropped support for Kotlin K1, Kotlin <2.0 and androidx libraries changes. Please stay on 3.1 if you're still using compose 1.7.3!
  • Kotlin 2.1.20-RC
  • Essenty 2.5-beta01
  • Ktor 3.1

🚀 New Features

  • Add ContainerViewModel class that allows grabbing the exact type of the container from the ViewModel. This is more flexible as it allows clients to access public methods of the container class itself, instead of just the Store contract.
  • add intent extension functions on Container. This makes sending intents easier when Containers are used
  • add store name to exception messages for easier debugging. Sometimes the error messages are not helpful because they are thrown outside the store. This change allows to find the store with the problem from the stacktrace

🐞 Bug Fixes

  • fix intent DSL extensions accepting 0 intents / actions. This is a binary breaking change, but shouldn't need any source changes. It was made because a call like store.intent() was possible, sending 0 intents, which is a developer error.
  • Fix store.subscribe() overloads using collect for states instead of collectLatest. When the render function is slow (e.g. resources, file reads, widgets, services) it could lead to the backpressure buildup from the store. This release changes state updates to be cancelled instead, ensuring you show the latest data. I hope that no one relied on the old non-cancellable behavior, but if you do, consider using a Provider overload and collect states manually.

❔ Other

  • removed deprecated useState function and StoreConfiguraIon top-level properties.
  • updated run configurations for contributors

📚 Docs

  • Add documentation on DI setup with Kodein and Koin #138 #131. The page contains ready-to-use samples on how to inject containers using DI as ViewModels with lifecycle and backstack support.
  • Add resources page with articles, case studies, samples #139
  • Update contribution guide with more detailed setup

3.1.0

24 Dec 10:31
304b73f

Choose a tag to compare

Highlights of 3.1 release

API Changes:

  • Reversed the order of onStop invocations. The onStop callback in plugins is now invoked in the opposite order (bottom to top)! This change was made to support using and referencing plugins or values of a store (such as cache) in the onStop callback. Most users shouldn't be affected, but ideally you should check each place where onStop is used manually.
  • updateStateImmediate is now inline. This will require additional imports in your code.
  • the unsafe state property of the store is now inline. Additional imports will be needed in your code if you are using it.
  • In test DSL, the time travel plugin is now installed after the plugin is run, meaning it gets the resulting value of the plugin test, not the initial. For example, if previously a plugin swallowed an exception, it was still present in the TimeTravel. Now it isn't, to better align with expectations on plugin execution.
  • Changed the return type of Store.start() to a new object - StoreLifecycle - which can be used to wait for the store to start, stop, and shut it down.

New features

  • First release of the IDE plugin 💫! It provides easy to use Live templates which generate stores, plugins, screens for you using shortcuts fmvim - for models, fmvic - for containers, fmvis - for composable screens, fmvip - for plugins, and more.
    • Additionally, the plugin fully includes the debugger, previously packaged as a standalone app.
  • New branch of plugin DSL - Decorators! Currently experimental, they are very similar to plugins, but allow to intercept and observe the invocation chain of a plugin, or the entire store. They are a more powerful alternative to plugins with a slightly different behavior. See docs for more info.
  • Debugger now allows basic operations to control the store
  • New onStop handler callback for PipelineContext, which will invoke an action on store closure. It is less safe than the deinit plugin but can be used where deinit is not available, e.g. async code.
  • android module now has more than just the android target and uses the new Androidx.Viewmodel multiplatform support.
  • Wasm WASI support for core module
  • New plugin callbacks:
    • onUndeliveredIntent to handle undelivered intents
    • onUndeliveredAction - same for actions.
    • onStop now has access to store config and can change the state.
  • Huge performance improvements to the library improve the speed by 250-1600%, making the library one of the fastest among 35 researched alternatives
  • New config property stateStrategy that replaces the atomicStateUpdates and allows for customization of whether the state transactions will be reentrant, serialized, or immediate. The non-reentrant strategy now includes runtime checks that prevent deadlocks (active in debug mode only)
  • New config property allowTransientSubscriptions allows to control whether the subscribers can leave and return on their own
  • New savedStatePlugin's SaveBehavior - Periodic, that allows to save the state every N seconds.
  • Quickstart has been rewritten from scratch to explain the library in <10 minutes. Added a page for decorators and updated readme as well

New Plug-Ins

  • resetStatePlugin - to clean up the store's state
  • asyncCache - to asynchronously run initialization routines and cache the result
  • deinit - for running actions when the store is stopped

New Decorators

  • intentTimeout - for disallowing long reducing operations
  • conflateIntents / conflateActions - for preventing duplicate events
  • retryIntents - for retrying failed intent reduction
  • batchIntents - sends intents in batches to improve peformance

Dependencies:

  • CMP 1.7.3
  • Kotlin 2.0.21
  • Coroutines 1.10.1
  • Ktor 3.0.3 for debugger
  • Serialization 1.8-RC

Bug fixes

  • Important fix for #121 which would throw UnrecoverableException if the exception was caught in a nested clause, like: onStart { updateState { throw Exception() } }
  • A lot of issues fixed on the debugger
  • Improved visuals of the debugger and sample app, new theme colors

Since 3.1.0-beta06 release:

  • fix plugin live templates
  • fix wide screen display on sample app
  • bump deps
  • update readme
  • remove dokka workaround and enable it back