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.
Build commands
Section titled “Build commands”Flutter’s build commands map directly to npm run build, but you specify the target platform as a subcommand:
# Androidflutter 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 / TestFlightflutter build ipa --export-method ad-hoc # Ad-hoc distribution
# Webflutter build web # Output to build/web/flutter build web --release # Minified production build
# Desktopflutter build macosflutter build windowsflutter build linuxThe 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.
Release signing — Android
Section titled “Release signing — Android”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:
keytool -genkey -v -keystore ~/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias uploadThen create android/key.properties to reference the keystore:
storePassword=<your-store-password>keyPassword=<your-key-password>keyAlias=uploadstoreFile=<path-to>/upload-keystore.jksFinally, 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.
Release signing — iOS
Section titled “Release signing — iOS”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.
Web deploy
Section titled “Web deploy”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/:
# Firebase Hostingfirebase deploy --only hosting
# Or drag-drop build/web/ to Netlify's deploy UI# Or push to Vercel via the Vercel CLINo server required. The output is a pure static site.
GitHub Actions CI
Section titled “GitHub Actions CI”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.
name: React CIon: 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 buildname: Flutter CIon: 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 --releaseHere 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