CI/CD for a Capacitor App with GitHub Actions
Build the web layer, sync native, and produce an Android build automatically.
Capacitor wraps a web build into native iOS and Android projects. This recipe builds the web bundle, runs cap sync, and compiles the Android APK with Gradle in CI.
What the pipeline does
- install deps with npm ci
- build the web bundle
- sync native with npx cap sync android
- assemble the APK with Gradle
- upload the APK artifact
The workflow
cap sync copies the web build into the native project and updates plugins; the Gradle wrapper then assembles the APK. iOS builds need a macOS runner with Xcode and signing.
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 17
cache: gradle
- run: npm ci
- run: npm run build
- run: npx cap sync android
- run: cd android && ./gradlew assembleDebug
- uses: actions/upload-artifact@v4
with:
name: app-debug
path: android/app/build/outputs/apk/debug/app-debug.apkCaching and speed
cache: npm covers the web install and cache: gradle restores the Gradle dependency cache, which is the biggest CI win for the Android build. The native compile is heavy; cheaper managed runners such as Latchkey (around 69% cheaper than GitHub-hosted) keep these builds affordable and auto-retry transient Gradle download failures.
Deploying
For releases, run ./gradlew bundleRelease to produce an AAB, sign it, and upload to the Play Console (manually or with a Play publisher action). Build iOS on a macOS runner with npx cap sync ios followed by xcodebuild and TestFlight upload.
Key takeaways
- cap sync injects the web build into the native projects.
- Cache Gradle to cut Android build time substantially.
- iOS builds require a macOS runner with Xcode and signing.