To upgrade a Capacitor plugin to Capacitor 8, run bunx @capacitor/plugin-migration-v7-to-v8@latest from the plugin root, then review the diff: Capacitor dependencies move to 8.x, Android targets SDK 36 with minSdk 24, AGP 8.13 and Gradle 8.14.3, Kotlin goes to 2.2.20 with compilerOptions, and iOS moves to a 15.0 deployment target with capacitor-swift-pm 8. Finish by building the example app on both platforms and publishing a new major version.
This guide is for plugin maintainers. App teams should follow How to Upgrade Your Capacitor App to Capacitor 8.
What changes for plugin authors
| File | Change |
|---|---|
package.json |
@capacitor/core peer to >=8.0.0, dev deps @capacitor/cli, core, android, ios to ^8.0.0 |
android/build.gradle |
compileSdk = 36, minSdkVersion = 24, targetSdkVersion = 36, AndroidX bumps |
android/build.gradle (buildscript) |
AGP 8.13.0, google-services 4.4.4, Kotlin 2.2.20 |
android/gradle/wrapper/gradle-wrapper.properties |
Gradle 8.14.3 |
| All Gradle files | = assignment syntax, kotlinOptions replaced by compilerOptions |
*.podspec |
s.ios.deployment_target = '15.0' |
Package.swift |
.iOS(.v15) and capacitor-swift-pm from: "8.0.0" |
Platform tooling you need locally and in CI: Node.js 22+, Xcode 26+, Android Studio Otter (2025.2.1) or later, and a JDK 21.
Option 1: run the official migration tool
From the plugin root, on a clean git tree:
bunx @capacitor/plugin-migration-v7-to-v8@latest
The tool:
- Updates the Capacitor dependencies and sets your package version to
8.0.0. - Updates dev tooling that the official template uses:
@capacitor/docgen, Rollup, TypeScript,@types/node, and Prettier (from v2 to v3 if you use@ionic/prettier-config, plusprettier-plugin-java). - Deletes
node_modules/@capacitorandpackage-lock.json, then runsnpm install. If you use Bun, that step fails with a warning. Runbun installyourself afterwards and commitbun.lock. - Regenerates the Gradle wrapper with
./gradlew wrapper --gradle-version 8.14.3. - Rewrites
build.gradle: SDK levels, AndroidX versions, AGP, Kotlin version, Java 21 compatibility, andkotlinOptionstocompilerOptions. - Raises the podspec deployment target from 14.0 to 15.0, and in
Package.swiftsets.iOS(.v15)andfrom: "8.0.0"forcapacitor-swift-pm.
When a string it expects is missing, it logs Unable to find "..." in <file>. Try updating it manually. Every one of those lines is a manual step for you. Plugins with custom Gradle logic, non-standard folders or renamed files produce the most of them.
If Prettier moved from v2 to v3, run your format and lint scripts after the migration. The formatting diff can be large, so commit it separately from the functional changes.
Option 2: upgrade manually
Use this when the tool can’t parse your files, or when you want to review each change. The steps follow the official plugin upgrade guide.
1. Dependencies
{
"devDependencies": {
"@capacitor/android": "^8.0.0",
"@capacitor/cli": "^8.0.0",
"@capacitor/core": "^8.0.0",
"@capacitor/ios": "^8.0.0"
},
"peerDependencies": {
"@capacitor/core": ">=8.0.0"
}
}
2. Android SDK levels and Gradle syntax
android {
namespace = "com.example.plugin"
compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
defaultConfig {
minSdkVersion = project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
targetSdkVersion = project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
}
lintOptions {
abortOnError = false
}
}
Keep the project.hasProperty(...) ? rootProject.ext... : default pattern. It lets the host app’s variables.gradle control the values, which avoids the “compile against version 36” class of errors in apps.
The = syntax applies to properties only. Method calls like mavenCentral() stay unchanged, and maven { url = "..." } needs the =.
3. AndroidX defaults
Only bump libraries your plugin actually uses. The Capacitor 8 defaults are:
ext {
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.17.0'
androidxActivityVersion = project.hasProperty('androidxActivityVersion') ? rootProject.ext.androidxActivityVersion : '1.11.0'
androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.14.0'
}
Others from the official list: androidxCoordinatorLayoutVersion 1.3.0, androidxFragmentVersion 1.8.9, firebaseMessagingVersion 25.0.1, androidxBrowserVersion 1.9.0, androidxMaterialVersion 1.13.0, androidxExifInterfaceVersion 1.4.1, coreSplashScreenVersion 1.2.0.
4. AGP and the Gradle wrapper
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:8.13.0'
}
}
cd android
./gradlew wrapper --distribution-type all --gradle-version 8.14.3
If your plugin uses Firebase or other Google Services, set com.google.gms:google-services to 4.4.4.
5. Java 21 and Kotlin 2.2
Java 21 is recommended for AGP 8.13 and SDK 36. Java 17 still works for the plugin itself.
compileOptions {
sourceCompatibility = JavaVersion.VERSION_21
targetCompatibility = JavaVersion.VERSION_21
}
For Kotlin plugins, update the default version and move jvmTarget out of kotlinOptions. Kotlin 2.2 makes the old block an error:
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
buildscript {
ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '2.2.20'
}
android {
// remove: kotlinOptions { jvmTarget = '17' }
}
kotlin {
compilerOptions {
jvmTarget = JvmTarget.JVM_21
}
}
Keep jvmTarget and targetCompatibility on the same Java version, or Gradle stops with an “Inconsistent JVM-target compatibility” error. If you still apply kotlin-android-extensions, remove it. Use kotlin-parcelize for @Parcelize and view binding for synthetic view access.
6. iOS deployment target
Podspec:
s.ios.deployment_target = '15.0'
Package.swift:
platforms: [.iOS(.v15)],
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
],
Use from:, not branch: or exact:. The app’s generated CapApp-SPM package pins capacitor-swift-pm to the exact version of @capacitor/ios the app installed, and a range lets SPM resolve your plugin against it.
Plugins with the old Xcode project layout also need the deployment target raised in the project’s Build Settings and in ios/Podfile (platform :ios, '15.0').
If your plugin has no Package.swift yet, do that next. Apps created with Capacitor 8 default to SPM and will skip your plugin with a “not compatible with SPM” warning. Follow How to Migrate a Capacitor Plugin to Swift Package Manager.
Option 3: let an agent do it
The open Capgo Skills include capacitor-plugin-upgrade-v7-to-v8, capacitor-plugin-upgrades for multi-version jumps, and capacitor-plugin-spm-support. Install with bunx skills add Cap-go/capgo-skills and ask your agent to upgrade the plugin. The skill runs the official tool, then handles the steps the tool logs as skipped. Review the diff the same way you would review a teammate’s PR.
Which approach to use
| Approach | Good fit | Watch out for |
|---|---|---|
| Migration tool | Plugins generated from the official template | Skipped steps on customized files, npm install step with Bun |
| Manual | Heavily customized Gradle or Xcode setup | Easy to miss one AndroidX or Kotlin change |
| Agent + skill | Many plugins to upgrade, or mixed layouts | You still own the review |
Start with the tool in almost every case. Its log tells you exactly what’s left.
Verify before you publish
bun install && bun run build(or yourverifyscript).- Android:
cd android && ./gradlew clean build test. Build with JDK 21. - iOS with CocoaPods:
cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin -destination generic/platform=iOS(new layout plugins usexcodebuild -scheme <YourPackageName> -destination generic/platform=iOS). - iOS with SPM:
swift package resolve, then build the scheme. - Install the plugin in a fresh Capacitor 8 app (
bunx cap add iosgives you SPM by default) and in a CocoaPods app. Call every public method on a real device. - Run
bunx cap doctorin the test app.
Release
- Bump to a new major (the tool uses
8.0.0). Raising minSdk and the iOS floor is a breaking change for consumers. - Write a short
BREAKING.mdor changelog entry: new peer range, minSdk 24, iOS 15, Java 21 for builds, any API behavior changes. - Keep a
7.xbranch if you still ship fixes for Capacitor 7 users, and publish those under a dist-tag such aslatest-7. - Update the README install section and the compatibility table.
Capgo maintains a large set of plugins on this cycle, with each @capgo/* major tracking a Capacitor major. You can browse them in the plugin directory.
Troubleshooting
invalid source release: 21. Gradle is running on JDK 17 or older. Use the JDK 21 bundled with Android Studio Otter and set JAVA_HOME in CI.
Unsupported class file major version 65. The opposite problem: you run JDK 21 with an old Gradle wrapper that can’t read Java 21 class files. Regenerate the wrapper at 8.14.3.
Namespace not specified. AGP 8+ requires namespace = "..." in the plugin’s android block. Older plugins only had a package attribute in AndroidManifest.xml. Move it to Gradle and remove package from the manifest.
'compileDebugJavaWithJavac' task (current target is 21) and 'compileDebugKotlin' task (current target is 17). Your Kotlin jvmTarget doesn’t match targetCompatibility. Set both to 21 or both to 17.
Errors mentioning proguard-android.txt with AGP 9. Some apps already run AGP 9. Switch to proguard-android-optimize.txt so your plugin builds in those apps too. Details are in fix Capacitor plugin build errors with AGP 9.
SPM: product 'Capacitor' required by package ... not found. Your Package.swift dependency line has a typo or uses a version that doesn’t exist. Use from: "8.0.0" against https://github.com/ionic-team/capacitor-swift-pm.git.
16 KB page size warnings in Play Console. If your plugin ships native .so libraries, rebuild them with 16 KB alignment. See Android 16 KB page size and Capacitor plugins.
Once the plugin is on 8, the next step is getting ready for 9. Preparing for Capacitor 9 lists the changes plugin teams can make now without breaking Capacitor 8 users.