Deploying a Flutter web app can feel repetitive if you’re doing it manually every time. GitHub Actions automates this by continuously deploying your app to Firebase Hosting whenever you push code to your repository.
This guide walks you through setting up Firebase Hosting, configuring GitHub Actions, and managing deployments. By the end, you’ll have a reliable CI/CD pipeline for your Flutter web project.
Table of Contents:
Prerequisites
Before diving in, make sure you have these ready:
1. Flutter Installed: You can install Flutter from flutter.dev, then confirm installation with:
flutter --version
2. Firebase CLI Installed: The Firebase CLI lets you interact with Firebase Hosting. Install it via npm like this:
npm install -g firebase-tools
Check installation with:
firebase --version
3. A GitHub Repository: Your Flutter project should be pushed to GitHub.
4. Firebase Project Created: Go to Firebase Console, create a project, and enable Firebase Hosting.
Step 1: Set Up Firebase Hosting
Initialize Firebase in Your Project
Open your terminal and navigate to your project:
<span class="hljs-built_in">cd</span> path/to/your/flutter/project
Initialize Firebase Hosting:
firebase init
During setup, you’ll need to provide some information:
-
Hosting: Select Firebase Hosting.
-
Public Directory: Enter
build/web
(this is where Flutter outputs web builds). -
Single-Page App: Select Yes (rewrites all routes to
/index.html
). -
Automatic Builds: You can skip since we’ll configure GitHub Actions manually.
Step 2: Configure Firebase Hosting
A file called firebase.json
will be created. Ensure it looks like this:
{
<span class="hljs-attr">"hosting"</span>: {
<span class="hljs-attr">"public"</span>: <span class="hljs-string">"build/web"</span>,
<span class="hljs-attr">"ignore"</span>: [
<span class="hljs-string">"firebase.json"</span>,
<span class="hljs-string">"**/.*"</span>,
<span class="hljs-string">"**/node_modules/**"</span>
]
}
}
-
hosting.public
tells Firebase where to find your built app (build/web
). -
ignore
files Firebase should not upload (hidden files, config files,node_modules
).
You may also see a .firebaserc
file for project aliasing:
{
<span class="hljs-attr">"projects"</span>: {
<span class="hljs-attr">"default"</span>: <span class="hljs-string">"your-project-id"</span>
}
}
This links your local project to your Firebase project ID.
Step 3: Add Firebase Config to Flutter
When you connect Firebase to Flutter (via the flutterfire
CLI), it generates a file like firebase_options.dart
.
In your main.dart
, initialize Firebase:
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:flutter/material.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'package:firebase_core/firebase_core.dart'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'firebase_options.dart'</span>;
<span class="hljs-keyword">void</span> main() <span class="hljs-keyword">async</span> {
WidgetsFlutterBinding.ensureInitialized();
<span class="hljs-keyword">await</span> Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(MyApp());
}
-
WidgetsFlutterBinding.ensureInitialized()
ensures that the Flutter engine is ready before Firebase initializes. -
Firebase.initializeApp()
connects your app to Firebase using the auto-generated options.
Step 4: Configure GitHub Actions
We’ll now create a workflow that automatically builds and deploys your Flutter web app.
Create a file in your repo: .github/workflows/firebase-hosting.yml
<span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">Firebase</span> <span class="hljs-string">Hosting</span>
<span class="hljs-attr">on:</span>
<span class="hljs-attr">push:</span>
<span class="hljs-attr">branches:</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">main</span> <span class="hljs-comment"># Deploy only when code is pushed to main</span>
<span class="hljs-attr">pull_request:</span>
<span class="hljs-attr">branches:</span>
<span class="hljs-bullet">-</span> <span class="hljs-string">main</span>
<span class="hljs-attr">jobs:</span>
<span class="hljs-attr">build_and_deploy:</span>
<span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
<span class="hljs-attr">steps:</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Checkout</span> <span class="hljs-string">Repository</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Flutter</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">subosito/flutter-action@v3</span>
<span class="hljs-attr">with:</span>
<span class="hljs-attr">flutter-version:</span> <span class="hljs-string">'3.24.1'</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Dependencies</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">flutter</span> <span class="hljs-string">pub</span> <span class="hljs-string">get</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Build</span> <span class="hljs-string">Flutter</span> <span class="hljs-string">Web</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">flutter</span> <span class="hljs-string">build</span> <span class="hljs-string">web</span> <span class="hljs-string">--release</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Set</span> <span class="hljs-string">up</span> <span class="hljs-string">Node.js</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-node@v3</span>
<span class="hljs-attr">with:</span>
<span class="hljs-attr">node-version:</span> <span class="hljs-string">'18'</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Install</span> <span class="hljs-string">Firebase</span> <span class="hljs-string">CLI</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">npm</span> <span class="hljs-string">install</span> <span class="hljs-string">-g</span> <span class="hljs-string">firebase-tools</span>
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Deploy</span> <span class="hljs-string">to</span> <span class="hljs-string">Firebase</span> <span class="hljs-string">Hosting</span>
<span class="hljs-attr">run:</span> <span class="hljs-string">firebase</span> <span class="hljs-string">deploy</span> <span class="hljs-string">--only</span> <span class="hljs-string">hosting</span> <span class="hljs-string">--project</span> <span class="hljs-string"><firebase-project-id></span>
<span class="hljs-attr">env:</span>
<span class="hljs-attr">FIREBASE_TOKEN:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.FIREBASE_TOKEN</span> <span class="hljs-string">}}</span>
Here’s what’s going on in this code:
-
Checkout Repository: Pulls your code into the runner.
-
Set up Flutter: Installs the specified Flutter version.
-
Install Dependencies: Runs
flutter pub get
. -
Build Flutter Web: Builds the release version of your web app.
-
Set up Node.js: Needed for Firebase CLI.
-
Install Firebase CLI: Installs Firebase deploy tool.
-
Deploy to Firebase Hosting: Deploys the built files to Firebase.
Step 5: Set Up Firebase Token
GitHub needs a token to authenticate with Firebase.
Run this locally:
firebase login:ci
Then copy the token shown.
Next, go to your GitHub Repository → Settings → Secrets and Variables → Actions.
Create a new secret named: FIREBASE_TOKEN
and paste in the token you copied. This keeps your credentials safe.
Step 6: Validate & Monitor Deployment
Commit the workflow file like this:
git add .github/workflows/firebase-hosting.yml
git commit -m <span class="hljs-string">"Setup GitHub Actions for Firebase Hosting"</span>
git push origin main
Go to your GitHub repo, select the Actions tab, and then watch the workflow run. You will see an interface that looks like these images:
Once it’s successful, go to:
https://your-project-id.web.app
https://your-project-id.firebaseapp.com
Advanced Configurations
Custom Build
If you need a specific renderer (for example, HTML instead of CanvasKit):
<span class="hljs-attr">run:</span> <span class="hljs-string">flutter</span> <span class="hljs-string">build</span> <span class="hljs-string">web</span> <span class="hljs-string">--release</span> <span class="hljs-string">--web-renderer</span> <span class="hljs-string">html</span>
Multiple Environments (Staging & Production)
<span class="hljs-attr">run:</span> <span class="hljs-string">firebase</span> <span class="hljs-string">deploy</span> <span class="hljs-string">--only</span> <span class="hljs-string">hosting</span> <span class="hljs-string">--project</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.FIREBASE_PROJECT</span> <span class="hljs-string">}}</span>
Define FIREBASE_PROJECT
as a secret for each environment.
Cache Dependencies (Speed up builds)
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Cache</span> <span class="hljs-string">Flutter</span> <span class="hljs-string">Dependencies</span>
<span class="hljs-attr">uses:</span> <span class="hljs-string">actions/cache@v3</span>
<span class="hljs-attr">with:</span>
<span class="hljs-attr">path:</span> <span class="hljs-string">~/.pub-cache</span>
<span class="hljs-attr">key:</span> <span class="hljs-string">${{</span> <span class="hljs-string">runner.os</span> <span class="hljs-string">}}-pub-cache-${{</span> <span class="hljs-string">github.sha</span> <span class="hljs-string">}}</span>
<span class="hljs-attr">restore-keys:</span> <span class="hljs-string">|</span>
<span class="hljs-string">${{</span> <span class="hljs-string">runner.os</span> <span class="hljs-string">}}-pub-cache-</span>
Troubleshooting
You might encounter a few common issues. Her are some quick fixes to help you deal with them:
Issue | Fix |
No active project | Run firebase use --add locally and check .firebaserc . |
Node.js version mismatch | Ensure node-version: '18' in workflow. |
Firebase CLI errors | Reinstall with npm install -g firebase-tools . |
Deprecated warnings in index.html | Update to latest Flutter web template. |
Wrapping Up
By integrating Firebase Hosting with GitHub Actions, you now have a CI/CD pipeline for your Flutter web app.
Every push to main
automatically triggers a build and deploy, keeping your app live with zero manual effort.
To dive deeper, check:
Source: freeCodeCamp Programming Tutorials: Python, JavaScript, Git & MoreÂ