A Godot 4 editor plugin that exports your project for mobile and ships it — to TestFlight, the App Store, Firebase App Distribution and Google Play — without leaving the editor.
It adds a Release tab next to 2D/3D/Script with one column per destination: the store's recent releases on top, a Release button underneath, and a live build log at the bottom. The work is mainly done by Godot's headless exporter and fastlane.
What it does
- One click per destination: patch the version, export the preset, upload the artifact.
- Live log streamed from the running build, with a Stop button that kills the whole process tree (not just the shell).
- Fetch pulls the current release list from each store so you can see which build numbers are already taken before you upload another one.
- Release notes are written once and delivered everywhere they can be: the TestFlight changelog, the Firebase App Distribution release note, and the Google Play changelog. They are also archived to
release-notes/<version>-<build>.md. - Version name and build number are written into
export_presets.cfg, so a manual export from Project → Export produces the same build.
In the Release tab
| Function | What it does |
|---|---|
| Version name + build number | Written into every enabled target's export preset as soon as the field loses focus |
| Release notes | One field, delivered to every store that accepts a changelog, and archived to disk |
| Release to … | Releases one target, after a confirmation dialog that lists exactly what is about to happen |
| Release group | Releases every target in a group: exports run one after another, then all uploads start |
| Fetch | Loads that store's recent releases — date, version, status — so a duplicate build number never reaches the store |
| Stop | Kills one target's run, or all of them, including every child process the script started |
| Test groups | Per-target tester group aliases for TestFlight and Firebase, editable right in the column |
| Debug build | Per-target debug template toggle. Never offered for App Store or Google Play |
| CI | Copies the exact command that reproduces this release on a runner, with the current version, build, groups and debug flag |
| PID | Shows the running process id, so you can find or stop it by hand |
| Log tabs | One tab per target, auto-following new output, with a Jump to latest button when you scroll back |
Notes, tester groups and the debug flag are remembered per project, so they survive an editor restart — and they never leak into your other projects.
In the Setup tab
A checklist of everything the plugin needs — Ruby, Bundler, fastlane, Xcode, the Godot binary, export presets, the config resource, the fastlane files, installed gems, credentials, .gitignore, and every target's own validation — each row with a Docs ↗ link straight to the page that explains it.
Above it, the buttons that fix what is missing, greyed out once their step is done:
| Button | What it does |
|---|---|
| 1 · Create config | Writes release_config.tres with one target per store your export presets can actually serve |
| 2 · Install release scripts | Copies Gemfile and fastlane/{Fastfile,Appfile,Pluginfile} into your project, creates fastlane/.env with placeholders, runs bundle install in the background |
| 3 · Edit credentials | Opens fastlane/.env in your editor |
| Update .gitignore | Keeps credentials, logs and build artifacts out of git |
| Edit config | Opens release_config.tres in the Inspector |
| Install agent skills | Drops plain-markdown notes into .agents/ so an AI coding agent can run and debug a release safely |
Nothing here ever overwrites a file that already exists — the fastlane files are yours to edit, and a plugin update leaves them alone.
Configuration
Three resources, edited in the Inspector, every field documented on hover:
| Resource | What it is |
|---|---|
AppReleaseConfig |
One per project: bundle id, package name, team id, log and release-note paths, Godot binary override, extra PATH entries |
AppReleaseGroup |
A panel in the Release tab — e.g. Test and Store — with its own button that releases everything in it |
AppReleaseTarget |
One export preset plus one store: the unit that gets released, and what a column shows |
Pick the export preset first and the rest follows. The platform is read out of the preset, and that decides which stores you can pick, how the build modes are labelled, and which fields are shown at all. Targets are ordinary resources, so add, duplicate and remove them freely.
Target fields are grouped as Source, Destination, Build, Native project and Testers — export preset, store, Play track, fastlane lane, column label, build mode, artifact path, debug build, enabled, Xcode project/scheme/plist/PCK paths, tester groups, and skip build processing wait for TestFlight.
Build modes
| Mode | iOS | Android |
|---|---|---|
| Godot export | not available — a Godot iOS export produces an Xcode project, never an .ipa |
Godot builds the APK/AAB through Gradle |
| Regenerate native project | Godot regenerates the Xcode project, then xcodebuild archives and exports it |
Reinstalls the Android build template, then exports |
| PCK only | Exports just the .pck, then rebuilds your existing, hand-maintained .xcodeproj |
Exports just the .pck, then runs gradlew in your existing android/build |
PCK only is the mode that matters once you have edited the Xcode project by hand — capabilities, entitlements, extra frameworks — because a full Godot export overwrites all of it.
What each destination does
| Destination | Lane behaviour |
|---|---|
| TestFlight | Uploads the .ipa, sets your notes as the changelog, distributes to your tester groups, optionally skips waiting for processing |
| App Store | Uploads the build as a new version, not submitted — and deliberately uploads no metadata, so your live listing can never be overwritten by a local folder |
| Firebase App Distribution | Uploads the APK with your notes as the release note and your tester groups |
| Google Play | Uploads the AAB to internal, alpha, beta or production, with your notes as the changelog; production lands as a draft |
Runs outside the editor, identically
Every release is a plain shell script driven by a plain KEY="value" file, so nothing is locked inside the editor:
# Repeat the last release the panel configured
addons/app_release/scripts/release.sh .release_tools/run_<target>.env logs/manual.log
# Or run just one phase: export, upload, or all
addons/app_release/scripts/release.sh .release_tools/run_<target>.env logs/manual.log upload
On CI, one headless command replaces the panel:
godot --headless --path . \
--script addons/app_release/scripts/ci_release.gd -- \
--target play_internal --version 1.4.0 --build "$GITHUB_RUN_NUMBER"
bash addons/app_release/scripts/release.sh .release_tools/run_play_internal.env
It runs the same validation the panel runs, patches the version, and writes the run configuration; both commands exit non-zero on failure, so a job fails where the problem is. No fastlane/.env is needed on a runner — the lanes read plain environment variables from your CI secrets.
Credentials
Secrets only ever live in fastlane/.env and in the key files it points at, both outside version control. The plugin does not read, store or transmit them — it hands fastlane the environment and gets out of the way.
Requirements
| Godot | 4.4 or newer | ||
| Ruby + Bundler + fastlane | required for every target | ||
| Xcode | required for iOS targets — macOS only | ||
| Android build template + release keystore | required for Android targets | ||
| Destination | macOS | Linux | Windows |
|---|---|---|---|
| TestFlight, App Store | yes | no | no |
| Firebase App Distribution, Google Play | yes | yes | best-effort* |
Windows runs through scripts/release.ps1, which ships untested — the plugin is developed on macOS. Bug reports welcome.
Documentation
- Repository and README — full setup, daily use, CI, troubleshooting
- TestFlight and the App Store — Apple Developer Program, App Store Connect API key, signing,
ExportOptions.plist, build numbers - Google Play — Play Console, keystore, the first manual upload, service account, tracks, AAB vs APK
- Firebase App Distribution — Firebase project, App ID, service account, tester groups
- Architecture — how the pieces fit, for contributors
Tested with GUT, RSpec and bats-core — GDScript, Ruby and shell each have their own suite, run on every push.
Get in touch
Found a bug, hit a store behaving differently than described, or want a feature? Open an issue on the repository — that is the fastest way to reach me, and it keeps the answer where the next person will find it. A log excerpt from logs/ plus your Godot and fastlane versions makes a report much easier to act on. Pull requests are welcome too.
Windows users especially: scripts/release.ps1 ships untested, so reports from there are genuinely useful.
More of my work: github.com/chris-prenissl
MIT licensed. Free, open source, and yours to fork.
Changelog for version v1.0.0-beta1
No changelog provided for this version.