Skip to content

Building & Deploying

In React, deploying means running npm run build to get a static dist/ folder, then pushing it to Vercel, Netlify, or S3. Flutter has three build targets — Android (APK/AAB), iOS (IPA), and web — each with its own command and signing requirements. The CI pipeline logic is almost identical to a React pipeline; only the action steps differ.

Flutter’s build commands map directly to npm run build, but you specify the target platform as a subcommand:

Terminal window
# Android
flutter build apk # Debug APK (for testing)
flutter build apk --release # Release APK (signed)
flutter build appbundle # Android App Bundle (Play Store preferred)
# iOS (requires macOS + Xcode)
flutter build ipa # iOS Archive for App Store / TestFlight
flutter build ipa --export-method ad-hoc # Ad-hoc distribution
# Web
flutter build web # Output to build/web/
flutter build web --release # Minified production build
# Desktop
flutter build macos
flutter build windows
flutter build linux

The web build outputs to build/web/ — a static folder equivalent to Vite’s dist/. You can deploy it to any CDN or static host without modification.

Android release builds must be signed with a keystore. This is equivalent to code-signing in native app development — unsigned builds cannot be distributed through the Play Store.

Create a keystore with the Java keytool utility:

Terminal window
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload

Then create android/key.properties to reference the keystore:

storePassword=<your-store-password>
keyPassword=<your-key-password>
keyAlias=upload
storeFile=<path-to>/upload-keystore.jks

Finally, reference key.properties in android/app/build.gradle so the release build picks up the signing config automatically.

Treat key.properties and the .jks file exactly like .env files containing secrets — never commit them to git. Add both to .gitignore.

iOS signing requires an Apple Developer account, a provisioning profile, and a signing certificate managed through Xcode. You can use Xcode’s “Automatically manage signing” for most cases — it handles profile creation and certificate rotation.

flutter build ipa generates a .xcarchive and then exports it to a .ipa file. The export method (--export-method) controls the distribution channel: app-store for App Store / TestFlight, ad-hoc for direct device distribution, and development for local testing.

flutter build web --release produces a minified static build in build/web/. The folder contains an index.html, compiled JavaScript, and any assets you declared in pubspec.yaml. Deploy it anywhere you would deploy a Vite dist/:

Terminal window
# Firebase Hosting
firebase deploy --only hosting
# Or drag-drop build/web/ to Netlify's deploy UI
# Or push to Vercel via the Vercel CLI

No server required. The output is a pure static site.

A React CI pipeline installs Node, runs npm ci, lints, tests, and builds. A Flutter CI pipeline does the same with subosito/flutter-action in place of actions/setup-node.

React / GitHub Actions
name: React CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run lint
- run: npm test -- --watchAll=false
- run: npm run build
Flutter / GitHub Actions
name: Flutter CI
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.0'
channel: 'stable'
- run: flutter pub get
- run: flutter analyze
- run: flutter test --coverage
- run: flutter build web --release

Here is a full CI workflow with branch triggers for both main and feature branches:

name: Flutter CI
on:
push:
branches: [main, dev]
pull_request:
branches: [main]
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: subosito/flutter-action@v2
with:
flutter-version: '3.22.0'
channel: 'stable'
- name: Install dependencies
run: flutter pub get
- name: Analyze
run: flutter analyze
- name: Run tests
run: flutter test --coverage
- name: Build web
run: flutter build web --release
Which command builds a Flutter app for the web?
What is the Flutter equivalent of actions/setup-node in GitHub Actions?
What does flutter build appbundle produce, and why prefer it over APK for the Play Store?
Where should you NEVER commit your Android keystore or key.properties file?