Automate Flutter Builds with GitHub Actions
Build a CI/CD pipeline that compiles your Flutter Windows app in the cloud.
Introduction
30 Second Summary
Every time you want to share your app with someone, you run the build command, open Inno Setup, click through the wizard, and hunt for the installer file to send. If your computer crashes or you switch machines, you have to set up that whole process again from scratch.
In this project, you will build an automated build pipeline that runs in the cloud. Push a button on GitHub and your Flutter app compiles, packages itself into an installer, and serves it up as a downloadable file.
What You'll Build
A working pipeline where you click "Run workflow" on GitHub, watch your app build itself in real time, and download the finished installer without touching your local machine.
By the end of this project, you'll have:
- A GitHub Actions workflow that builds your Flutter Windows app and packages it with Inno Setup automatically in the cloud.
- A downloadable installer artifact you can grab from GitHub after every workflow run.
- The confidence to read CI/CD logs and fix build failures without fear of breaking your code.
- Secret Mission: Auto-attach your installer to a GitHub Release so anyone can download it from your project page.
Are there any prerequisites?
This project assumes you already have a Flutter project with an Inno Setup .iss file pushed to a public GitHub repo. You also need VS Code and Git installed on your machine.
Before We Start
Before we dive in, let's lock in what you're about to build and why it matters for your workflow as a developer.
Create Your First Workflow File
Right now your Flutter build process lives only on your local machine. If your computer dies or you want to build from a different machine, you have to set everything up from scratch.
A workflow file tells GitHub exactly how to build your app, making the process repeatable anywhere. In this step, you will create your first GitHub Actions workflow that runs on demand in the cloud.
In this step, get ready to:
- Create a .github/workflows/build.yml file in your Flutter project.
- Push the workflow to GitHub and trigger it manually.
- Verify the workflow completes with a green checkmark.
Create the workflow folder and file
GitHub Actions looks for workflow files inside a specific folder in your repository: .github/workflows/. Any YAML file you place there becomes a workflow that GitHub can run.
- In VS Code, right-click the root of your project in the Explorer sidebar.
- Click New Folder and name it .github.
- Right-click the .github folder, click New Folder again, and name it workflows.
- Right-click the workflows folder, click New File, and name it build.yml.
- Paste the following YAML into build.yml:
name: Build Flutter Windows Installer
on:
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
What does this workflow do?
- name: gives your workflow a human-readable label that shows up in the Actions tab.
- on: workflow_dispatch: means this workflow only runs when you manually click a button on GitHub. It will never run automatically until you add more triggers later.
- runs-on: windows-latest tells GitHub to spin up a fresh Windows machine in the cloud to run your build.
- actions/checkout@v6 clones your repository code onto that cloud machine.
- subosito/flutter-action@v2 installs Flutter on the cloud machine and logs the installed version.
Why workflow_dispatch first?
Starting with a manual trigger gives you full control. Nothing runs until you press a button, so there is zero risk of flooding your repo with failed builds while you are still learning. Once you trust the pipeline, you will switch to automatic triggers in a later step.
- Save build.yml with Cmd+S (macOS) or Ctrl+S (Windows).
Don't see the .github folder in VS Code?
Some systems hide files and folders that start with a dot. In VS Code's Explorer sidebar, check that files.exclude in your settings is not hiding .github. You can also verify the folder exists by opening VS Code's integrated terminal and running ls -a (macOS) or dir /a (Windows).
Ask for help: Why can't I see my .github folder in VS Code?
Commit and push to GitHub
Your workflow file needs to be on your repository's default branch before GitHub will recognize it. Pushing it to main makes the Run workflow button appear in the Actions tab.
- Open VS Code's integrated terminal with Ctrl+` (backtick key, same shortcut on macOS and Windows).
- Stage, commit, and push your new file by running these commands:
git add .github/workflows/build.yml
git commit -m "Add GitHub Actions workflow"
git push
- Open your GitHub repository in a browser.
- Click the Actions tab at the top of the repository page.
- In the left sidebar, click Build Flutter Windows Installer.
- Click the Run workflow button above the list of workflow runs.
- Select main in the Branch dropdown, then click the green Run workflow button.
Don't see the Run workflow button?
The button only appears when the workflow file exists on your default branch and uses the workflow_dispatch trigger. Double-check that you pushed to main (not a feature branch) and that your on: section contains workflow_dispatch: exactly.
Ask for help: Why doesn't my Run workflow button appear in the GitHub Actions tab?
Verify the workflow run
Before you check the result, what do you expect to see when the run finishes? Think about what the two steps in your workflow actually do.
- Click into the running workflow (the orange spinning icon).
- Click the build job to expand the live logs.
- Wait for the run to finish.
You should see a green checkmark next to the run. Expand the Set up Flutter step in the logs and you will see the Flutter version printed, confirming the cloud machine installed Flutter successfully.
What just happened?
A Windows machine spun up on GitHub's servers, cloned your repository, and installed Flutter. Your actual repo was never modified. GitHub Actions is read-only by default: it works on a copy of your code, so nothing can break in your real project.
Seeing a red X instead of a green checkmark?
Click into the failed step to read the error message. Common causes at this stage:
- A YAML indentation error in build.yml. YAML is sensitive to spaces. Make sure each level is indented with exactly 2 spaces, not tabs.
- A typo in an action name (for example action/checkout instead of actions/checkout).
Ask for help: My GitHub Actions workflow failed with a red X. How do I fix it?
✔️ Awesome, I've got everything!
Great. Double-check you have saved build.yml and that your workflow run shows a green checkmark on GitHub.
ⓧ I'd like to double check the full code
Here is the complete .github/workflows/build.yml at this point:
name: Build Flutter Windows Installer
on:
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
Your pipeline is alive. A cloud machine just checked out your code and set up Flutter without you lifting a finger on your local machine. Next up, you will add the actual build commands so the workflow produces your Windows .exe file.
Build Your Flutter App in the Cloud
Your workflow can run, but it does not produce anything useful yet. It just prints a version number and exits.
The next milestone is to actually compile your app in the cloud. This is the same flutter build windows command you run locally, but executing on GitHub's cloud machine. If something is missing or misconfigured, the logs will tell you exactly what went wrong and where.
In this step, get ready to:
- Add flutter pub get and flutter build windows steps to your workflow file.
- Trigger the workflow and read the build logs.
- Confirm the compiled .exe appears in the expected output path.
Add the build steps to your workflow
Your workflow currently checks out the code and sets up Flutter. Now you need two more steps: one to install your project's dependencies, and one to compile the Windows app.
- In VS Code, open .github/workflows/build.yml.
- Find the last lines of the file (the Flutter setup step):
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
- Add the following two steps directly below that block, at the same indentation level:
- name: Install dependencies
run: flutter pub get
- name: Build Windows app
run: flutter build windows
What do these steps do?
- flutter pub get installs all the packages listed in your pubspec.yaml. Without this, the build would fail because none of your dependencies exist on the cloud machine.
- flutter build windows compiles your Dart code into a native Windows .exe file. This is the exact same command you run on your own machine.
- Save build.yml.
✔️ Awesome, I've got everything!
Great. Double check you have saved build.yml before moving on.
ⓧ I'd like to double check the full code
Here is the complete build.yml file at this point:
name: Build Flutter Windows Installer
on:
workflow_dispatch:
jobs:
build:
runs-on: windows-latest
steps:
- name: Checkout code
uses: actions/checkout@v6
- name: Set up Flutter
uses: subosito/flutter-action@v2
with:
channel: stable
- name: Install dependencies
run: flutter pub get
- name: Build Windows app
run: flutter build windows
Commit, push, and trigger the workflow
For GitHub Actions to pick up your changes, the updated file must be on your main branch.
- Open your terminal in VS Code by pressing Ctrl+` (backtick key).
- Commit and push the updated workflow by running these commands:
git add .github/workflows/build.yml
git commit -m "Add build steps to workflow"
git push
- In your browser, navigate to your repository on GitHub.
- Click the Actions tab.
- Select your Build Flutter Windows Installer workflow on the left.
- Click Run workflow, select your main branch, then click the green Run workflow button.
Before you watch the run, take a moment to predict: do you think the build will succeed on the first try, or will something go wrong?
- Click into the running workflow to watch the live logs.
Why first builds often fail in CI
Running flutter build windows in the cloud is stricter than building on your own machine. Your local environment has accumulated settings and cached packages over time that the cloud machine starts without.
Common reasons a first cloud build fails: a dependency in pubspec.yaml references something unavailable on the runner, or Windows desktop support was never explicitly enabled in the project. This is completely normal and safe. Nothing happens to your actual code on GitHub.
✔️ Build succeeded (green checkmark)
Your project was already CI-ready. Skip ahead to the next substep to confirm the output path.
ⓧ Build failed (red X)
This is the expected learning moment. The logs tell you exactly which step and which line caused the failure.
- Click the failed step in the log to expand it.
- Read the error message carefully. It will name the file, line, or package that caused the issue.
- Fix the issue in your local project (for example, update a dependency in pubspec.yaml or run flutter config --enable-windows-desktop locally and commit the change).
- Commit, push, and trigger the workflow again using the same steps above.
- Repeat until the build passes. Each failure teaches you something about what your project needs to run in a clean environment.
Stuck on a build error?
Copy the exact error message from the log. The most important line is usually right above where the step turns red.
Help me debug this GitHub Actions build error for my Flutter Windows app.
Confirm the build output in the logs
Once your workflow run shows a green checkmark, you know the build succeeded. Now confirm that the compiled app landed where you expect it.
- Click into the successful workflow run.
- Expand the Build Windows app step in the log.
- Look for the line that says Building Windows application... near the top of that step's output.
- Scroll to the end of the step. Confirm you can see the output path build\windows\x64\runner\Release\ referenced in the log, with your app's .exe file listed.
Your Flutter app is now compiling entirely in the cloud. The .exe exists on GitHub's runner, but it disappears when the workflow finishes. In the next step, you will save it as a downloadable artifact.
Why does the .exe disappear?
GitHub's runners are temporary machines. They spin up for your workflow, do the work, then get destroyed. Anything you build on them vanishes unless you explicitly save it as an artifact.
Your app now builds itself in the cloud. Next up, you will package the installer with Inno Setup and save it as a downloadable artifact you can grab from GitHub.
Package the Installer and Download It
Your Flutter app builds successfully in the cloud. The compiled .exe sits on GitHub's temporary runner machine and vanishes the moment the workflow finishes.
In this step, you'll run your existing Inno Setup script inside the workflow to create a proper installer. Then you'll save it as a downloadable artifact so you can grab the file from GitHub anytime.
In this step, get ready to:
- Run your Inno Setup script in the cloud to produce the installer.
- Upload the installer as a downloadable artifact on GitHub.
- Download and verify the installer on your local machine.
Add the Inno Setup build step
Inno Setup is already pre-installed on GitHub's windows-latest runners. You just need to tell the workflow where the compiler lives and which .iss file to run.
- In VS Code, open .github/workflows/build.yml.
- Find the last step (Build Windows app) and add the following step directly below it:
- name: Build installer with Inno Setup
shell: cmd
run: |
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" installer.iss
What does this step do?
- shell: cmd switches from PowerShell to the Windows command prompt. The quoted path with spaces works more reliably in cmd.
- ISCC.exe is the Inno Setup command-line compiler. It reads your installer.iss script and produces a ready-to-run installer .exe.
- The output lands in a folder called Output\ by default (relative to the .iss file location).
Different .iss filename?
If your Inno Setup script is not named installer.iss or lives in a subfolder, replace installer.iss with the correct relative path (e.g. setup/myapp.iss).
Add the upload artifact step
The installer now gets built, but it still lives on the temporary runner. An artifact step saves the file to GitHub so you can download it after the run completes.
- Add this step directly below the Inno Setup step you just added:
- name: Upload installer artifact
uses: actions/upload-artifact@v4
with:
name: windows-installer
path: Output\*.exe
if-no-files-found: error
What does this step do?
- actions/upload-artifact@v4 is GitHub's official action for saving files from a workflow run.
- name: windows-installer gives the artifact a recognisable label on the workflow run page.
- path: Output\*.exe tells GitHub which files to save. The Output\ folder is where Inno Setup places the finished installer by default.
- if-no-files-found: error makes the workflow fail loudly if the installer was not produced. Without this, a silent success could hide a broken build.
- Save build.yml.
What is a workflow artifact?
An artifact is a file or collection of files produced during a workflow run. GitHub stores artifacts for 90 days on public repos. You can download them from the workflow run page whenever you need them.
✔️ Awesome, I've got everything!
Great. Double check you have saved build.yml and both new steps appear below the Build Windows app step.
ⓧ I'd like to double check the full code
Scroll through your build.yml and confirm the following steps appear in this exact order:
- Checkout code (uses actions/checkout@v6).
- Set up Flutter (uses subosito/flutter-action@v2 with channel: stable).
- Install dependencies (runs flutter pub get).
- Build Windows app (runs flutter build windows).
- Build installer with Inno Setup (uses shell: cmd and runs ISCC.exe on installer.iss).
- Upload installer artifact (uses actions/upload-artifact@v4 with path Output\*.exe).
Commit, push, and download your installer
- Commit your changes by running this command in the VS Code terminal:
git add .github/workflows/build.yml
git commit -m "Add Inno Setup and artifact upload steps"
git push
- Open your repository on GitHub.
- Click the Actions tab.
- Select your Build Flutter Windows Installer workflow in the left sidebar.
- Click Run workflow, select your branch, then click Run workflow again to confirm.
- Click into the new workflow run to watch the live logs.
Before you scroll down to check the result, predict: do you think the run will succeed on the first try, or will the Inno Setup step fail? Think about whether your .iss file paths match the runner's workspace layout.
- Wait for the workflow run to finish (look for the green checkmark).
- Once it completes, click the workflow run name to return to the run summary page.
- Scroll to the bottom of the summary page. In the Artifacts section, you should see windows-installer listed.
- Click windows-installer to download the zip file to your local machine.
- Unzip the download and run the installer to verify it works.
Workflow failed at the Inno Setup step?
- Check that your .iss file is in the repo root and named installer.iss. If it has a different name or path, update the run: line in your workflow to match.
- Open your .iss file and look for the SourceDir directive. On your local machine this might point to an absolute path like C:\Users\you\project. Remove it or set it to . so it works relative to wherever the runner checks out your code.
- Check the Source: lines in your [Files] section. They must reference build\windows\x64\runner\Release\ (the Flutter output path on the runner) rather than a local path on your own machine.
Fix the paths locally, commit, push, and re-trigger the workflow.
Still stuck? Help me fix my Inno Setup paths for GitHub Actions
.
Workflow failed at the upload artifact step?
- The error means no .exe files were found in the Output\ folder. Check your .iss file for an OutputDir directive. If it writes to a different folder, update the path: value in the upload step to match.
- If your .iss does not specify OutputDir, the default is Output\ relative to the script. This should work without changes.
Need help? My upload-artifact step says no files were found
Your build pipeline now produces a downloadable installer with zero manual steps. Next up, you'll flip the switch so this pipeline runs automatically every time you push code.
Switch to Automatic Builds on Push
Your pipeline now builds a working installer and serves it as a downloadable artifact. Every time you needed a fresh build, though, you had to click the Run workflow button manually. You are still the bottleneck.
The real power of CI/CD is that builds happen automatically when code changes. Now that you trust the pipeline (you have seen it succeed and you know how to read failures), it is time to let it run on its own.
In this step, get ready to:
- Add a push trigger to your workflow so it fires automatically on every push to main.
- Verify that pushing code automatically starts a new build without you clicking anything.
Add the push trigger to your workflow
Right now your workflow only runs when you manually click a button. You will add a second trigger so the workflow also fires whenever you push code to main.
- In VS Code, open .github/workflows/build.yml.
- Find this section near the top of the file:
on:
workflow_dispatch:
- Add the push trigger with a branch filter directly below workflow_dispatch:, so the section now looks like this:
on:
workflow_dispatch:
push:
branches: [main]
What does this change do?
The on: section lists every event that triggers your workflow. By adding push: with branches: [main], the workflow now fires both when you click Run workflow manually AND whenever a commit lands on your main branch.
The workflow_dispatch trigger stays so you can still run builds on demand whenever you want.
- Save build.yml.
Push and verify the automatic trigger
The moment you push this change to main, the workflow should start on its own. No button click required.
- Commit and push your updated workflow file by running these commands in your terminal:
git add .github/workflows/build.yml
git commit -m "Add automatic push trigger to workflow"
git push
Push rejected?
If git push is rejected, pull first with git pull --rebase then push again. This happens if previous workflow runs created commits on the remote that you do not have locally.
Help me fix a rejected git push
Before you check the Actions tab, think about this: what event do you expect triggered the new workflow run?
- Open your repository on GitHub.
- Click the Actions tab.
- Look at the most recent workflow run in the list.
You will see a new run that started automatically. Click into the run to open its details. The event label shows push instead of workflow_dispatch.
How do I tell what triggered a run?
Each workflow run on the Actions tab displays the triggering event. Push-triggered runs show push as the event, while manual runs show workflow_dispatch. You can check this in the run's summary details next to the commit message.
- Wait for the run to complete with a green checkmark.
- Confirm that the Artifacts section at the bottom of the run summary shows your windows-installer file.
Your pipeline is now fully automated. Every push to main builds and packages your app without you lifting a finger.
No automatic run appeared?
Make sure you pushed to the main branch, not a feature branch. The branches: [main] filter only triggers on pushes to main.
Also check that the indentation in your build.yml is correct. YAML is whitespace-sensitive. The word push must be indented to the same level as workflow_dispatch (two spaces under on:).
Why didn't my push trigger the workflow automatically?
✔️ Awesome, I've got everything!
Great. Double check you have saved build.yml and confirmed the automatic run completed with a green checkmark.
ⓧ I'd like to double check the full code
Your .github/workflows/build.yml has grown across multiple steps. Scroll up through your file and confirm these sections appear in order:
- The on: section with both workflow_dispatch: and push: branches: [main].
- The jobs: section with runs-on: windows-latest.
- Steps in this order: Checkout code, Set up Flutter, Install dependencies, Build Windows app, Build installer with Inno Setup, Upload installer artifact.
If anything is out of place, compare against what you built in Steps 1 through 3 and the trigger you just added above.
Secret mission
Auto-Attach the Installer to a GitHub Release
Your installer artifact works, but it disappears after 90 days and lives buried in the Actions tab. Real open-source projects distribute software through GitHub Releases, a permanent public download page anyone can find. In this secret mission, you will wire your workflow to automatically attach the installer to a Release whenever you tag a new version.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project runs entirely on GitHub Actions, which is free and unlimited for public repositories. There are no ongoing costs.
Resources you used:
- GitHub Actions workflow file (.github/workflows/build.yml) in your repo.
- Workflow artifacts stored on GitHub (free for public repos, auto-deleted after 90 days).
Keep everything running
No action needed. Choose this if you are still actively building your Flutter app and want automatic builds on every push to main.
- Your workflow will continue to trigger on every push to main and on every new release.
- This costs nothing for public repositories.
- Artifacts are automatically cleaned up after 90 days.
Pause - I'll come back to this later
Stop automatic builds but keep the workflow file so you can re-enable later. This avoids unnecessary workflow runs while you are not actively pushing code.
- Open .github/workflows/build.yml in VS Code.
- Remove the push: and release: triggers from the on: section, leaving only workflow_dispatch:.
- Commit and push the change.
- Your workflow will now only run when you manually click Run workflow in the Actions tab.
Delete - I don't want to use this again
Remove all project resources and start fresh. This deletes your workflow entirely.
- Delete the workflow file from your repo by running this command from your project root:
rm .github/workflows/build.yml
- If the .github/workflows/ folder is now empty, remove it too:
rm -rf .github/workflows
- Commit and push the deletion:
git add -A
git commit -m "Remove CI workflow"
git push
- To delete existing workflow artifacts, go to your repo's Actions tab, click into a completed workflow run, scroll to the Artifacts section, and click the trash icon next to each artifact.
- Any artifacts you do not manually delete will auto-expire after 90 days.
That's a Wrap!
That's a Wrap!
Nice work! You just built a fully automated build pipeline that compiles, packages, and serves your Flutter Windows installer without you lifting a finger.
You've learned how to:
- Built a complete CI/CD pipeline that compiles your Flutter Windows app on a cloud machine using GitHub Actions.
- Packaged your app with Inno Setup and saved it as a downloadable artifact, all running automatically in the cloud.
- Switched from manual workflow_dispatch builds to fully automatic builds triggered on every push to main.
- Secret Mission: Attached your installer to a GitHub Release for permanent public distribution.
Ready to quiz yourself?