In this article

Cache the inputs and outputs you understand, then verify that a cache hit and a clean build produce the intended result. A faster job with stale or incompatible artifacts is not an improvement. Separate Flutter SDK, package-download and compiled-output caches before changing keys.

The flutter-action repository documentation, checked October 8, 2026, describes its cache options and keys. Those options do not make every native build output portable between runners or architectures.

Measure the stage you want to shorten#

Break job timing into SDK setup, dependency download, native resolution, compilation, tests, signing and upload. Use several representative runs, including cold starts and failures.

A large cache restore can cost more time than the work it replaces. Do not choose a cache because another team reports a speedup. Record your restore duration, rebuilt work and total job duration.

Make a cache inventory#

For each cached path, write down what it contains, who can write it, who can restore it and what makes it incompatible.

text
Cache category:
Contents:
Runner OS and architecture:
Toolchain/dependency inputs:
Exact key and fallback behavior:
Writer and reader trust:
Rebuild behavior on a miss:
Measured benefit:

An SDK installation, downloaded packages and compiled iOS intermediates have different compatibility boundaries. Do not give all three the same broad key just because they belong to one workflow.

Include the inputs that matter#

Read the action's current cache configuration and your workflow's actual restore settings. Consider Flutter version, channel, runner environment, architecture and relevant dependency-resolution files for the data being cached.

Avoid treating an unconstrained prefix fallback as an exact match. A fallback can intentionally restore older compatible downloads, but compiled outputs may need stricter boundaries. Document the distinction and rebuild stale output when required.

If a runner image or architecture changes, revalidate the cache assumptions rather than diagnosing every new error as a source regression.

Compare hit, miss and fallback behavior#

For an authorized non-production branch, run:

  1. A clean build with no cache hit.
  2. A build with the exact intended cache.
  3. A changed dependency or toolchain input that should produce a different key.

Compare build identity, relevant dependency resolution, tests and measured duration. Verify that a miss does ordinary work correctly; a cache should not be the only surviving copy of a required input.

If only the cache-hit build works, investigate missing declared inputs or setup steps. If only the clean build works, investigate stale or incompatible restored data before expanding the key's fallback.

Preserve the contribution trust boundary#

GitHub's secure-use guidance is relevant when cached data crosses between untrusted contribution jobs and privileged release jobs. Do not store credentials or signing files in a broadly readable cache.

Map actual cache permissions and scope for your events. A seemingly harmless restored executable can become a security concern if a trusted job runs it with release credentials.

Keep the benefit measurable#

After changing the cache, compare several normal runs with the earlier timings. Report observed savings for that workload, not a universal percentage.

Our Docker cleanup guide covers another useful operational habit: identify what stored material represents before deleting or reusing it. Apply that same discipline to CI caches.