BowlerKitBowlerKit
FlutterGuides

Release workflow

9/18/2026

Record changes, stamp the next version, tag the release, and produce Play Store release notes with one command.

Every production release follows the same loop: record what changed, pick the next version, stamp it into the project, tag it, and build. BowlerKit turns that loop into a single command — bowler changelog release — so the version in pubspec.yaml, the changelog, git history, and your bowlerShip dashboard never drift apart.

Version convention

BowlerKit uses the Flutter convention x.y.z+N: a semantic version name plus a monotonically increasing integer code.

SurfaceWhereExample
Version namemobile-app/pubspec.yamlversion:, before the +1.2.4
Android versionCode / iOS build numbersame line, after the +8

The full string 1.2.4+8 also labels the changelog block and the git tag (v1.2.4+8), so one identifier traces a release from source to store. Flutter derives the iOS CFBundleVersion from the same build number automatically.

Google Play rejects an upload whose versionCode is not higher than the previous one. The release command enforces the store rules before touching any file: the code must rise on every release and the version name must never go down.

Record what changed

Changelog entries live in .bowlerkit/changelog.md (Keep a Changelog format, committed with the project):

bowler changelog add         # interactive: pick a section + one-line summary
bowler changelog draft       # propose entries from commits since the last v* tag
bowler changelog list        # show the changelog

draft maps conventional-commit prefixes to sections (feat → Added, fix → Fixed, remove/revert → Removed, anything else → Changed), skips merge commits, and records commit hashes for traceability. Re-running is safe: commits already recorded are skipped. Entries stay close to the commit subjects on purpose — release notes that read well for end users are produced on bowlerShip, which the changelog mirrors to on every bowler changelog release.

Run the release

From the generated project root:

bowler changelog release

Without flags the command is interactive — it proposes the next patch bump and asks you to confirm:

Versi baru? (sekarang 1.0.0+3)
  1.0.1+4   Patch (usulan)
  1.1.0+4   Minor
  2.0.0+4   Major
  1.0.0+4   Code only
  > Custom…

After you choose, the command stamps the version, releases the changelog, commits, tags, and prints the store notes:

✓ mobile-app/pubspec.yaml → 1.2.4+8
✓ .bowlerkit/project.json → 1.2.4+8
✓ .bowlerkit/changelog.md → ## [1.2.4+8] - 2026-09-12
✓ commit chore(release): v1.2.4+8
✓ tag v1.2.4+8

What's new untuk Play Console (versi 1.2.4+8):
- Crash saat refresh
- Mesin kalender Bali

✓ 42 karakter — aman (batas 500 per bahasa).

Flags

FlagEffect
(none)Interactive prompt with the patch proposal as default
--patch / --minor / --majorBump the corresponding segment; code +1
--code-onlyKeep the version name, raise only the code
--version x.y.zExplicit version name (code defaults to current + 1)
--code NOverride the version code
--yesAccept the patch proposal without prompting
--date YYYY-MM-DDOverride the changelog date (default: today)
--allow-emptyRelease with an empty [Unreleased] (code-only re-release)
--no-commit / --no-tag / --no-syncOpt out of the automatic commit / tag / bowlerShip push
--dir <path>Run against another project directory

What gets written

FileChange
mobile-app/pubspec.yamlThe version: line is rewritten to x.y.z+N (a trailing comment is preserved)
.bowlerkit/project.jsonThe app.version block follows the new release
.bowlerkit/changelog.md[Unreleased] entries move into a ## [x.y.z+N] - date block

Git commit and tag

The command commits exactly the release-touched files — anything else you have modified or staged stays untouched — with the message chore(release): v<x.y.z+N>, then creates the matching git tag. The tag is the anchor the next bowler changelog draft counts commits from.

If a tag v<x.y.z+N> already exists, the release aborts before any file is modified — that exact version was already released, so pick another. Use --no-commit/--no-tag to manage git yourself; with --no-commit the tag (if any) points at HEAD, which does not yet contain the release.

Sync to bowlerShip

When the project is bound (bowler ship connect), the release pushes a snapshot automatically: the new version appears on the bowlerShip dashboard and the released changelog shows up on its Changelog page. Without a binding the command prints the manual follow-up (bowler ship sync). Skip the push with --no-sync.

Code-only re-release

Sometimes the store rejects an upload, or a build fix does not merit a changelog line. Re-release the same version name with a fresh code:

bowler changelog release --code-only --allow-empty

--allow-empty permits an empty [Unreleased]; the resulting version block carries no entries and stays invisible on the bowlerShip changelog page.

After the release

Build the production artifacts:

flutter build appbundle --release   # Google Play
flutter build apk --release         # sideloading / internal testing
flutter build ipa --release         # App Store (macOS/Xcode only)

For the surrounding checklist (signing, store listing, assets), see Play Store Assets & Publishing Checklist. For the rest of the CLI, see CLI Reference.