agentleFS
Cap-goCap-go/capgo-skills/skills/capacitor-best-practices/SKILL.md

capacitor-best-practices

Skill75 starsChanged 33 days agoMITView on GitHub

Review and set up Capacitor apps against current best practices (Capacitor 8.5 stable, 9 alpha via `@next`). Use for a Capacitor codebase review, `capacitor.config.ts` audit, new project setup, aligning `@capacitor/core`/`cli`/`ios`/`android` and plugin majors, plugin patterns (availability checks, `checkPermissions`/`requestPermissions`, error `code` handling, web fallbacks), or release prep; or on `"<Plugin>" plugin is not implemented on ios`, `Could not find the web assets directory`, `platform has not been added yet`, a dev `server.url` shipped to production, lost edits in `android/app/src/main/assets/public`, SPM vs CocoaPods, or AppDelegate/UIScene drift. Do not use for security audits (capacitor-security), performance (capacitor-performance), tests (capacitor-testing), crashes (debugging-capacitor), major upgrades (capacitor-app-upgrades), SPM migration (cocoapods-to-spm), UIScene adoption (capacitor-uiscene-migration), or live updates (capgo-live-updates).

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Use the permission API: Call checkPermissions() then requestPermissions() for official plugins that expose them, and handle denied with a …

    line 65
  2. Very specific:

    iOS lifecycle is scene-based from Capacitor 8.5: After adopting UIScene, AppDelegate application(_:open:options:), continue userActivity, …

    line 68
  3. Distinctive:

    Only load a reference when its topic is in play.

    line 74

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Capacitor Best Practices

Review a Capacitor app for structural mistakes that cause broken builds, lost edits, production leaks, and plugin crashes. Route deep topics to the sibling skill that owns them.

When to Use

TRIGGER when:

  • The user asks for a general code/architecture review of a Capacitor or Ionic + Capacitor app.
  • Setting up a new Capacitor project or adding iOS/Android to an existing web app.
  • capacitor.config.ts|json review: webDir, server.url, cleartext, plugin config, env-specific config.
  • Version drift between @capacitor/core, @capacitor/cli, @capacitor/ios, @capacitor/android, or plugin majors that do not match Capacitor's major.
  • Plugin usage review: missing npx cap sync, no availability check, no permission flow, matching on error message strings.
  • Errors such as "<Plugin>" plugin is not implemented on ios, Could not find the web assets directory, ios platform has not been added yet.
  • Pre-release sanity checklist across config, native projects, and live updates.

Do not use:

  • Security audit, secrets, storage, pinning, CSP -> capacitor-security; Xcode hardening -> capacitor-ios-security-hardening.
  • Bundle size, startup time, memory, bridge profiling -> capacitor-performance.
  • Unit/E2E test setup and plugin mocking -> capacitor-testing.
  • Crashes, white screen, native logs -> debugging-capacitor, ios-android-logs.
  • Major upgrades -> capacitor-app-upgrades (8 -> 9: capacitor-app-upgrade-v8-to-v9).
  • CocoaPods -> SPM -> cocoapods-to-spm; UIScene adoption -> capacitor-uiscene-migration.
  • Finding or installing a specific plugin -> capacitor-plugins.
  • Store submission and review -> capacitor-app-store, capacitor-apple-review-preflight; CI -> capacitor-ci-cd; live updates -> capgo-live-updates.

Current baseline (October 2026)

Capacitor 8 (stable, latest 8.5.x)Capacitor 9 (next, alpha)
Node22+24+
iOS min / XcodeiOS 15 / Xcode 26 (8.5 adopts UIScene so Xcode 27 builds work)iOS 16 / Xcode 27+
AndroidminSdk 24, compile/target 36, AGP 8.13, Gradle 8.14.3minSdk 26, compile/target 37, AGP 9.2.1, Gradle 9.5.1
iOS depsSPM default for new projectsSPM default

CocoaPods Trunk is expected to go read-only on December 2, 2026. Recommend SPM for every app still on CocoaPods. Install Capacitor 9 only with @next until it reaches GA, and do not recommend it for production apps.

Review workflow

  1. Inventory (read-only).
    npx cap doctor          # installed vs latest Capacitor packages
    npx cap ls              # plugins Capacitor detects per platform
    cat capacitor.config.ts 2>/dev/null || cat capacitor.config.json
    ls ios/App/Podfile ios/App/CapApp-SPM 2>/dev/null   # CocoaPods or SPM
    grep -nE "minSdkVersion|compileSdkVersion|targetSdkVersion" android/variables.gradle
  2. For large codebases, write a TODO list of areas (config, versions, plugins, native iOS, native Android, live updates, release) and review one at a time.
  3. Report findings before editing, grouped by severity, each with file:line and the fix. Ask before invasive changes (upgrading a major, migrating to SPM, enabling R8, changing appId).
  4. Fix, loading the matching reference.
  5. Run Verification.

Rules that matter most

  1. Keep Capacitor packages on one version. @capacitor/core, cli, ios, android must match. Plugin majors must match the Capacitor major (official and @capgo/* plugins follow it: v8 plugins for Capacitor 8).
  2. npx cap sync after every plugin install/removal and every config change. Missing sync produces "<Plugin>" plugin is not implemented on <platform>.
  3. Never edit generated web assets. android/app/src/main/assets/public/ and ios/App/App/public/ are overwritten by cap copy/sync. Edit src/ and rebuild.
  4. Commit ios/ and android/. They are source code with your native customizations, not build output. Do commit capacitor.config.*; do not commit node_modules, Pods/, build dirs.
  5. No dev settings in release config. server.url, server.cleartext, allowNavigation to dev hosts, webContentsDebuggingEnabled: true. Gate them on an env var (see references/config-and-project.md). On Capacitor 9, use npx cap run <platform> --url <dev-url> for live reload.
  6. Feature-detect before calling plugins. Capacitor.isNativePlatform(), Capacitor.getPlatform(), Capacitor.isPluginAvailable('Name'). Provide a web fallback or hide the feature.
  7. Use the permission API. Call checkPermissions() then requestPermissions() for official plugins that expose them, and handle denied with a path to Settings. Add the matching NS*UsageDescription keys / Android permissions.
  8. Branch on error.code, not error.message. Messages change between versions and platforms. Official plugins expose structured codes (for example OS-PLUG-CAMR-0006 for a cancelled camera capture in @capacitor/camera 8.1+ new APIs); Capacitor core uses UNIMPLEMENTED / UNAVAILABLE.
  9. Move large binary data as files, not base64. Pass file paths/URIs across the bridge and render with Capacitor.convertFileSrc().
  10. iOS lifecycle is scene-based from Capacitor 8.5. After adopting UIScene, AppDelegate application(_:open:options:), continue userActivity, and foreground/background callbacks stop firing. Move custom native code to SceneDelegate (capacitor-uiscene-migration). Avoid UIScreen.main and idiom-based layout for resizable windows.
  11. Live updates: call CapacitorUpdater.notifyAppReady() on every launch, and apply manual updates with next() (on background/relaunch) rather than set() mid-session. Details in capgo-live-updates.
  12. Secrets never go in the app. Anything in the bundle or capacitor.config is extractable. Hand off to capacitor-security for anything beyond this rule.

References

Only load a reference when its topic is in play.

ReferenceLoad when
references/config-and-project.mdReviewing capacitor.config, env-specific builds, repo layout, .gitignore, version alignment
references/plugins.mdPlugin install/sync, availability checks, permissions, error codes, web fallbacks, lazy loading, mocking
references/native-projects.mdiOS SPM vs CocoaPods, UIScene, deployment targets; Android variables.gradle, R8, Capacitor 9 Gradle changes
references/release-checklist.mdPreparing a release build or reviewing release readiness

Verification

# Versions aligned (all @capacitor/* core packages show the same version)
npm ls @capacitor/core @capacitor/cli @capacitor/ios @capacitor/android
npx cap doctor

# Web build exists where webDir points, then sync succeeds without errors
npm run build && npx cap sync

# No dev server or debug flags in the synced native config
grep -nE "\"url\"|cleartext|webContentsDebuggingEnabled" \
  android/app/src/main/assets/capacitor.config.json ios/App/App/capacitor.config.json

# No hand edits in generated web assets (should show nothing)
git status --porcelain android/app/src/main/assets/public ios/App/App/public

# Error handling does not depend on message text
grep -rnE "error\.message\s*(===|==|\.includes)" src/

# Native builds
cd android && ./gradlew assembleRelease && cd ..
xcodebuild -project ios/App/App.xcodeproj -scheme App -configuration Release -destination 'generic/platform=iOS' build CODE_SIGNING_ALLOWED=NO

With CocoaPods, build ios/App/App.xcworkspace with -workspace instead of -project. Finally run on a real device and exercise each plugin-backed feature, including permission denial.

Error handling

ErrorCauseFix
"<Plugin>" plugin is not implemented on ios (or android)Plugin installed but not synced, plugin has no implementation for that platform, or plugin major does not match Capacitornpx cap sync; check npx cap ls; install the plugin version matching your Capacitor major; rebuild the native app
"<Plugin>.<method>()" is not implemented on webCalling a native-only method in the browserGuard with Capacitor.isNativePlatform() or isPluginAvailable, provide a web fallback
Could not find the web assets directory: ./dist.webDir wrong or web app not builtBuild first; set webDir to the real output folder (dist, www, build, out)
ios platform has not been added yet.Native project missingnpx cap add ios (SPM default) or restore the committed ios/ folder
Invalid App ID "<id>"appId not reverse-domain or contains invalid charactersUse com.company.app style; changing it on a published app creates a new store listing
App loads a LAN IP or blank screen in productionserver.url shipped from a dev configRemove it, rebuild, npx cap sync, rebuild the native app
net::ERR_CLEARTEXT_NOT_PERMITTEDHTTP request on AndroidUse HTTPS; cleartext only in dev config (see capacitor-security)
pod install fails / CocoaPods spec errorsCocoaPods trunk deprecation, outdated specsMigrate with cocoapods-to-spm
Deep links or resume handling stopped on iOS after 8.5Custom code still in AppDelegate after UIScene adoptionMove it to SceneDelegate (capacitor-uiscene-migration)

Resources

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.