In this article
When Flutter works in debug but crashes in release, investigate the exact distributed artifact and collect the first useful error before changing build settings. Release-only is an observation, not a diagnosis. Several independent differences can produce the same visible symptom.
Flutter's Android release guide, checked October 8, 2026, documents release building and Android configuration. The diagnostic method below is an original evidence worksheet; it is not a claim that we reproduced your crash.
Establish the object that failed#
Record the platform, device/OS, app identifier, version/build number, installation channel, source revision, flavor and artifact checksum. Confirm the installed app is the one CI produced.
If a developer's local release build works but the store-distributed app fails, preserve that difference. It may concern artifact selection, configuration, signing-related integration or environment—not simply “release mode.”
Capture the first native or Dart error with synthetic data where possible. Redact credentials, personal data and unrelated logs before sharing evidence.
Use observations to narrow hypotheses#
Build a worksheet that includes what would disprove each explanation:
Observation: native missing-class exception
Supports: investigate shrinker rules or dependency packaging
Does not prove: every dependency needs a keep rule
Disconfirming check: verify the named class and targeted rule in the artifact
Observation: requests reach the staging endpoint
Supports: investigate flavor/defines/configuration selection
Does not prove: signing or optimization is broken
Disconfirming check: compare the artifact's resolved environment with the contract
Observation: crash occurs before Flutter starts
Supports: inspect native startup and plugin initialization
Does not prove: the first Dart screen is the cause
Disconfirming check: read the native startup stack and reproduce a minimal pathThese are diagnostic examples. Let the actual error determine which row deserves work. A blank screen without a stack trace cannot distinguish all of these cases.
Compare one variable at a time#
Run the intended release configuration on an authorized test device and follow the failing path. Compare its artifact identity and configuration with the distributed build.
If inspecting a shrinker hypothesis, use targeted documented rules for the named component and retain the original failure. Broadly disabling optimization may help an isolated diagnostic experiment, but it is not evidence for a permanent production fix.
If configuration differs, correct the configuration selection and verify the packaged result. Do not rotate signing credentials solely because a backend URL is wrong.
Keep the remediation tied to the evidence#
Record the hypothesis, supporting error, narrowly scoped change and expected result. Rebuild through the same relevant release path and inspect the resulting artifact.
Then repeat the original failing action, including upgrade state or device conditions that matter. Starting the app successfully is insufficient if the crash occurred after authentication or a particular native feature.
If the symptom disappears after several simultaneous changes, the result may be useful but the cause remains uncertain. Document that limitation rather than inventing an explanation.
Improve the next incident's evidence#
Retain release symbols, build configuration and artifact records. Ensure crash reporting captures the relevant native and Dart failure types without unnecessary customer data. Test observability in a designated safe environment.
Our AI code review guide applies when an assistant suggests a dozen unrelated fixes. Ask what observation each change addresses and what would falsify it. A release incident needs a verified failing-path test, not a checklist of plausible edits.