fastlane-plugin-godot
A fastlane plugin for shipping Godot Engine
games to mobile app stores: headless exports with real diagnostics, composing
with the fastlane actions (gym, pilot, cert, sigh, supply, …) that
already handle signing and store upload.
Published on RubyGems as
fastlane-plugin-godot ·
source, examples, walkthroughs, and issues live at
github.com/Mad-Science-Software/fastlane-plugin-godot
(the examples/ links below are relative — browse them there).
New to fastlane? Start with the from-zero walkthroughs — complete copy-paste setups including Ruby installation, credentials, Godot project prep, and working Fastfiles (first setup ~30 minutes; minutes per release after):
- Godot → TestFlight (iOS)
- Godot → Google Play (Android)
- Godot → TestFlight from CI, no Mac required
— build on GitHub's macOS runners with
match-based signing; develop on Linux or Windows and still ship iOS
Already using fastlane?
fastlane add_plugin godot
Actions
godot_init
Scaffolds everything a Godot project needs for mobile releases — run once from the project directory:
bundle exec fastlane run godot_init
Creates (only when missing — existing files are never touched): Gemfile,
fastlane/{Pluginfile,Appfile,Fastfile,.env.template}, an
export_presets.cfg with iOS + Android presets, build/.gdignore (so Godot
doesn't import its own build products), a placeholder 1024×1024 app_icon.png
(iOS export hard-fails without an icon; pass icon:false to skip), and a
.gitignore (or a warning listing entries yours is missing). Finishes by
listing the placeholders you must fill in: bundle identifier, team ID, and
your App Store Connect API key in fastlane/.env.
godot_get_version / godot_set_version
Read and write the version name + build number in export_presets.cfg,
keeping iOS (short_version/version) and Android (version/name/
version/code) in sync across every preset:
godot_set_version(version: 'patch', build_number: 'increment')
godot_set_version(from_git: true) # version from latest tag, build from commit count
godot_get_version # => { version_name: '1.2.0', version_code: 42 }
godot_export
Exports a Godot project headlessly using a named export preset from
export_presets.cfg, wrapping every footgun we have personally hit shipping
a real game with it:
- verifies the preset exists (and lists the available ones when it doesn't)
- verifies the matching engine version's export templates are installed for the preset's platform, with download guidance when they aren't
- runs a headless
--importfirst — a stale import cache aborts Godot exports with a crash-lookalike exit 134 - creates the output directory (Godot errors rather than create it)
- confirms the artifact was actually produced — Godot has historically exited 0 on some failed exports
lane :beta do
xcodeproj = godot_export(preset: 'iOS')
build_app(project: xcodeproj, scheme: File.basename(xcodeproj, '.xcodeproj'))
upload_to_testflight
end
| Option | Description | Default |
|---|---|---|
preset |
Export preset name (required) | — |
project_path |
Directory containing project.godot |
. |
godot_binary |
Path to the Godot binary | godot |
output_path |
Artifact destination, relative to the project | the preset's export_path |
debug |
Export a debug build | false |
import_first |
Run headless --import before exporting |
true |
verbose |
Pass --verbose to Godot |
false |
Every option is also settable via environment variable (FL_GODOT_*).
Returns the absolute artifact path (for iOS presets, the generated Xcode
project) and sets lane_context[:GODOT_EXPORT_OUTPUT].
godot_export also resolves and sanity-checks the engine: when godot
isn't on the PATH it looks in common install locations and the GODOT
environment variable, and it refuses to export when the binary's version
doesn't match the engine version the project declares in
config/features (cross-version exports corrupt import caches) —
skip_version_check: true overrides.
godot_install_templates
Downloads and installs the export templates matching your Godot binary's version — one platform's worth or everything:
godot_install_templates(platform: 'iOS') # or Android, macOS, Web, all
Skips work when the templates are already present, so it's safe to leave at the top of a lane as a CI bootstrap.
The iOS signing story (read this once)
Godot generates a fresh Xcode project on every export, with two properties that break naive pipelines:
- It writes
CODE_SIGN_IDENTITY="Apple Distribution"into an automatic-signing configuration (godot#110052), which xcodebuild rejects as conflicting. Fix: archive withxcargs: 'CODE_SIGN_IDENTITY="Apple Development"'and let the export step re-sign for distribution. - xcodebuild's cloud signing requires an Admin App Store Connect API
key (
Cloud signing permission errorotherwise). You don't need it: fastlane's stockget_certificates+get_provisioning_profiledo classic signing with an App Manager key, idempotently.
The example Fastfile wires both correctly. Its README's sharp-edges table maps the exact error messages to fixes.
Requirements
- Godot 4.2–4.7 (every version in that range is exercised by this repository's CI export matrix on each push)
- The engine version's export templates installed for your target platform
(
godot_install_templatesdoes this for you) - For iOS builds: macOS with Xcode; Android builds work on Linux too
Project principles
The original parity roadmap (vs the Unity fastlane plugins) completed with v0.2.1 — see the CHANGELOG for what shipped when. Ongoing direction comes from issue reports, held to three standing rules:
- Every release is dogfooded against a shipping game before tagging.
- Every newly discovered export footgun becomes a diagnostic in the action and a row in a sharp-edges table.
- Godot 4.2–4.7 support is enforced by the CI export matrix (Web exports on every version, plus an Android APK export on a Linux runner) — the supported-version claim is tested, not asserted.
Development
bundle install
bundle exec rake # runs the RSpec suite
Issues and pull requests welcome — especially reports of export footguns this plugin doesn't yet catch.