Force Update in Flutter (Part 5): GitHub Gist Remote Config
Force Update series: 1. Why you need it · 2. Upgrader · 3. Remote config intro · 4. force_update_helper · 5. GitHub Gist · 6. Firebase Remote Config · 7. Dart Shelf API
Fastest remote source for required_version: a public GitHub Gist. No Firebase, no server. Ideal for indie apps and prototypes. Production at scale should plan for Firebase or your API.
Create the Gist
- github.com → Gist → New
- Public gist (private raw URLs need auth)
- File e.g.
force_update.json:
{
"required_version": "1.0.0"
}
- Create gist → open Raw → copy the raw URL
Raw URLs look like:
https://gist.githubusercontent.com/<user>/<id>/raw/<revision>/force_update.json
Prefer a URL that includes a commit revision or always hit /raw/ and accept that GitHub CDN may cache briefly after edits.
Fetch from Flutter
Future<String> fetchRequiredVersionFromGist(Dio dio) async {
const url =
'https://gist.githubusercontent.com/you/GIST_ID/raw/force_update.json';
final response = await dio.get(url);
final data = response.data;
if (data is String) {
// sometimes raw is returned as string
final map = jsonDecode(data) as Map<String, dynamic>;
return map['required_version'] as String;
}
return (data as Map<String, dynamic>)['required_version'] as String;
}
Wire into the client from Part 4:
ForceUpdateClient(
fetchRequiredVersion: () => fetchRequiredVersionFromGist(dio),
iosAppStoreId: Env.appStoreId,
);
Raising the floor
- Ship and wait for store availability
- Edit the gist → bump
required_versionto e.g.1.2.0 - Users below 1.2.0 see the force prompt on next successful fetch
No app release required to change the floor.
Rate limits and reliability
GitHub rate-limits unauthenticated API/raw traffic. For a small user base this is often fine. For large traffic:
- Cache the last successful value on disk (SharedPreferences / secure storage)
- Fetch at most once per session or every N hours
- Back off on 403 / 429
- Have a migration plan to Firebase or your API
Future<String> fetchWithCache() async {
try {
final v = await fetchRequiredVersionFromGist(dio);
await prefs.setString('required_version_cache', v);
return v;
} catch (_) {
return prefs.getString('required_version_cache') ?? '0.0.0';
}
}
Using '0.0.0' as fallback means fail open (never force when unknown). That is usually correct.
Security notes
- Public gists are public — do not put secrets there
- Anyone can read your required version (that is OK)
- Anyone could try to MITM if you ship cleartext and no pinning — use HTTPS (Gist already does)
- Attackers cannot lower the floor on your gist without your GitHub account; they could still MITM the response on a compromised device network — treat this as best-effort, not DRM
Summary
- Gist = zero-ops remote config for force update
- Public raw JSON + Dio + cache
- Respect rate limits; graduate to Firebase/API when you grow
- Still never bump required_version before the store build is live
← Previous Part 4: force_update_helper
Next → Part 6: Firebase Remote Config



