Recommended resources
The freely available resources this lesson will direct you to.
In our last session, we generated the native iOS and Android project skeletons that will house your React application. You now have ios and android directories at your monorepo's root, marking the first concrete step in transforming your web app into a mobile one. However, these native projects currently contain only a snapshot of your web code from when they were created. This brings us to a fundamental question in the Capacitor workflow: how do you keep your native projects updated as your web app evolves?
This lesson focuses on the synchronization process. We'll dissect three essential Capacitor CLI commands: copy, update, and sync. Understanding the precise role of each is key to an efficient development cycle. By the end of this lesson, you will master bunx cap sync as your primary tool for keeping your web assets and native dependencies perfectly aligned, and you'll know exactly when its constituent parts, copy and update, might be used individually.
1. The Two Halves of Synchronization
Before diving into the commands, it's important to recognize that "synchronizing" in a Capacitor project involves two distinct tasks, stemming from the separation between your web codebase and the native projects:
- Web Asset Synchronization: Every time you build your React application, new HTML, CSS, and JavaScript files are generated in your
apps/web/distdirectory. These built assets need to be copied into the native projects' designated locations (ios/App/publicandandroid/app/src/main/assets/public) so they can be loaded by the WebView. - Native Dependency Synchronization: When you add, remove, or update a Capacitor plugin (e.g.,
@capacitor/push-notifications), you are changing your project'spackage.json. These plugins often contain native Swift/Kotlin code. The native projects (Xcode and Android Studio) must be updated to include this new native code, configure permissions, and link the necessary libraries.
Capacitor provides specific CLI commands to handle each of these tasks, and a master command to handle both.
2. Dissecting the Commands: copy, update, and sync
Let's break down the three commands that manage the synchronization workflow. The documentation from ionic.zone provides a clear, high-level overview of each.
Capacitor CLI: @capacitor/cli · ionic.zone
This article offers concise explanations for the core update commands in the Capacitor CLI. It will help you quickly grasp the purpose of each one.
Please read the three short subsections under the "Update your native Capacitor project(s)" heading: npx cap copy, npx cap update, and npx cap sync. As you read, focus on the distinct responsibilities described for copy and update.
As you've just read, the commands have very specific roles:
-
bunx cap copy: This command performs only the first task: web asset synchronization. It recursively copies the contents of yourwebDir(as defined incapacitor.config.ts, which we set toapps/web/dist) into the iOS and Android projects. You would use this after every single build of your web application to ensure the native shell has the latest version of your UI. -
bunx cap update: This command handles the second task: native dependency synchronization. It scans yourpackage.jsonfor Capacitor plugins and updates the native projects accordingly. For iOS, this often involves runningpod install, which can take some time. For Android, it updates Gradle dependencies. You must run this command after installing or updating any plugin with native capabilities. -
bunx cap sync: This is the convenience command you'll use most often. As the official Capacitor documentation states, it simply runscopyand thenupdatein sequence.
CLI Command - cap sync | Capacitor Documentation
The official Capacitor documentation provides the definitive statement on what sync does.
Read the first sentence on this page, which explicitly defines sync. This confirms that sync is a combination of the other two commands.
Using bunx cap sync is the most reliable way to ensure your project is fully up-to-date, as it handles both web assets and native dependencies in one go.
3. The Standard Workflow in Action
Let's put this into practice. The typical development loop involves building your web app and then syncing the changes to the native platforms.
First, ensure your web app is built. From the root of your Turborepo, run the build command for your web package:
bun run build --filter=web
This command uses Turborepo's filtering to build only the web app, populating the apps/web/dist directory with fresh assets.
Now, run the sync command from the root of your monorepo:
bunx cap sync
You'll see output in your terminal indicating the steps being performed:
- It will find your Capacitor configuration.
- It will run the
copyoperation, printing which platforms it's copying to. - It will then run the
updateoperation, checking for plugins and updating the native projects. For iOS, you'll likely see output related to CocoaPods (pod install).
The following video demonstrates this exact sequence. While the creator uses npm and npx, the process is identical to our bun and bunx workflow.
Build a Mobile App Fast! React + Capacitor + Tailwind + DaisyUI
Watch this short segment to see the build-then-sync workflow in a real project.
The key part is from build and sync. Observe how the developer first runs the web build to create the dist directory, then runs cap sync to copy those assets into the native project. He correctly describes the developer loop as "sync and then run".
4. Choosing the Right Command
With your lead developer experience, you appreciate optimizing workflows. So when should you deviate from always using sync?
-
Use
bunx cap sync(Recommended Default):- When you've installed, updated, or removed a Capacitor plugin.
- When you're starting a new coding session and want to ensure everything is aligned.
- When in doubt. It's the safest and most comprehensive option.
-
Use
bunx cap copy:- You've only made changes to your React components, hooks, or styles and have performed a new web build.
- You are 100% certain you haven't touched any native plugins.
- In this scenario,
copyis slightly faster because it skips the native dependency check and potentialpod install. In a rapid iteration cycle where you are only changing frontend code, this can save a few seconds per cycle.
-
Use
bunx cap update:- This is rarely used alone. A common reason to run it would be if you manually edited a native plugin's configuration and need to force Capacitor to re-apply its settings to the native projects without re-copying all the web assets.
For your goal of creating a "minimal viable wrap," establishing the habit of using bunx cap sync after each web build is a robust and error-proof strategy.
Conclusion
In this lesson, we demystified the process of keeping your native projects synchronized with your web application. You now have a clear understanding of the Capacitor commands that form the backbone of the development workflow.
The key takeaways are:
bunx cap copy: Transfers your built web assets (distfolder) to the native projects. Use it when only your web code has changed.bunx cap update: Updates native project configurations based on installed Capacitor plugins. It's essential after adding or changing plugins.bunx cap sync: The master command that performs acopyfollowed by anupdate. This is your reliable, go-to command for ensuring everything is in its correct state.
You now have all the foundational pieces configured: the web app, the native projects, and the knowledge to keep them synchronized. The next step is to bring your application to life. In our upcoming lesson, we will install the necessary iOS development tools—Xcode, its command-line tools, and CocoaPods—and run your Capacitor app on an iOS Simulator for the very first time.