For a long time, developers felt forced to choose: build a high-performance web app or dive into the complexity of native mobile development. But in my experience, the most efficient path is often the ‘hybrid’ approach. If you’re already comfortable with the Vue ecosystem, learning how to use Capacitor with Vue.js is a complete game-changer.
Capacitor, created by the Ionic team, is a cross-platform app runtime that turns your web project into a native mobile app. Unlike some other frameworks, it doesn’t force you to use a specific UI library. You can use Tailwind CSS, PrimeVue, or even plain CSS, and Capacitor will wrap it in a native web view with access to device APIs.
If you’re weighing your options against other frameworks, you might want to check out my deep dive on React Native vs Ionic performance in 2026 to see where Capacitor fits in the current landscape.
Prerequisites
Before we start, make sure you have the following installed on your machine:
- Node.js: Latest LTS version.
- Vue CLI or Vite: I highly recommend Vite for its speed.
- Android Studio: For Android builds (including SDK and Command Line Tools).
- Xcode: For iOS builds (requires a macOS machine).
- A working Vue.js project: If you don’t have one, you can create one via
npm create vue@latest.
Step-by-Step: Integrating Capacitor into Vue.js
Step 1: Initialize Capacitor
First, navigate to the root of your existing Vue.js project. We need to install the Capacitor CLI and Core libraries. Run the following commands in your terminal:
npm install @capacitor/core @capacitor/cli
# Initialize Capacitor configuration
npx cap init
During the init process, it will ask for your App name and App ID (e.g., com.yourname.vueapp). This ID is critical as it serves as the unique identifier for the App Store and Play Store.
Step 2: Configure the Build Directory
This is where most developers get stuck. Capacitor needs to know where your compiled web assets live. In a standard Vite-powered Vue project, the output folder is dist.
Open your capacitor.config.ts (or .json) file and ensure the webDir property is set correctly:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.yourname.vueapp',
appName: 'My Vue App',
webDir: 'dist', // Ensure this matches your Vue build folder
bundledWebRuntime: false
};
export default config;
Step 3: Add Native Platforms
Now, let’s add the platforms you want to target. I usually start with Android and iOS simultaneously to test consistency.
npm install @capacitor/android @capacitor/ios
# Add the platforms to your project
npx cap add android
npx cap add ios
Step 4: The Build and Sync Workflow
You cannot simply run npm run dev and see changes in the native app. Capacitor requires a production build of your Vue app to sync the files to the native project. Here is the workflow I use every time:
- Build your Vue app:
npm run build - Sync files to native folders:
npx cap copy(ornpx cap syncif you’ve added new plugins) - Open the native IDE:
npx cap open androidornpx cap open ios
As shown in the image below, once you run the open command, Capacitor launches Android Studio or Xcode, where you can hit the ‘Run’ button to deploy to a physical device or emulator.
Step 5: Accessing Native Features
The real power of knowing how to use Capacitor with Vue.js comes from the plugins. For example, if you want to use the device camera, you don’t need to write Java or Swift. Just install the plugin:
npm install @capacitor/camera
npx cap sync
Then, use it inside your Vue component:
<script setup>
import { Camera, CameraResultType } from '@capacitor/camera';
const takePhoto = async () => {
const image = await Camera.getPhoto({
quality: 90,
allowEditing: true,
resultType: CameraResultType.Uri
});
console.log('Image path:', image.webPath);
};
</script>
<template>
<button @click="takePhoto">Take Photo</button>
</template>
Pro Tips for Vue Developers
- Use Live Reload: To avoid building and syncing every time, you can use the
serveroption incapacitor.config.tsto point to your local Vite dev server (e.g.,url: 'http://192.168.1.XX:5173'). Just ensure your phone and PC are on the same Wi-Fi. - Safe Area Insets: Mobile devices have notches. Use CSS environment variables like
padding-top: env(safe-area-inset-top);to ensure your Vue components aren’t hidden under the status bar. - Conditional Rendering: Use
Capacitor.getPlatform()to render different UI elements for web vs. mobile users.
Troubleshooting Common Issues
Issue: “White Screen” on Startup
This is almost always due to the webDir being incorrect or the app not being built before running npx cap copy. Double-check that your dist folder actually contains an index.html.
Issue: Plugin Not Working on Android
Remember that some plugins require permissions in AndroidManifest.xml. If you’re adding Camera or Geolocation, you must manually add the permission tags to the XML file in Android Studio.
What’s Next?
Now that you have a basic app running, I recommend exploring more advanced native integrations. If you find that your app requires extremely heavy computation or complex background tasks, you might explore native-first options. I’ve written a comparison of NativeScript vs React Native in 2026 that explains when to move away from the WebView approach.
Alternatively, if you want to optimize your Vue app’s performance for mobile, look into lazy loading your routes and optimizing your asset pipeline to keep the initial load time under 2 seconds.