---
description: Turn React, Angular, Vue, Svelte, or any web app into native iOS and Android apps with Capacitor — setup, configuration, live reload, and release tips.
title: Build Mobile Apps with Any Web Framework and Capacitor - Capawesome
image: https://capawesome.io/docs/assets/images/social/blog/build-mobile-apps-with-any-web-framework-and-capacitor.png
---

[ Skip to content](#build-mobile-apps-with-any-web-framework-and-capacitor) 

[ 🎉 Introducing **Capawesome Platform** — one platform for Live Updates, Native Builds, App Store Publishing, and Insider SDKs.](https://capawesome.io) 

* [  Formbricks ](/docs/plugins/formbricks/)
* [  Geocoder ](/docs/plugins/geocoder/)
* [  Google Sign-In ](/docs/plugins/google-sign-in/)
* [  Grafana Faro ](/docs/plugins/grafana-faro/)
* [  libSQL ](/docs/plugins/libsql/)
* [  Live Update ](/docs/plugins/live-update/)
* [  Managed Configurations ](/docs/plugins/managed-configurations/)
* [  Media Session ](/docs/plugins/media-session/)
* [  ML Kit ](/docs/plugins/mlkit/)
* [  Navigation Bar ](/docs/plugins/navigation-bar/)
* [  NFC ](/docs/plugins/nfc/)
* [  OAuth ](/docs/plugins/oauth/)
* [  Pedometer ](/docs/plugins/pedometer/)
* [  Photo Editor ](/docs/plugins/photo-editor/)
* [  PostHog ](/docs/plugins/posthog/)
* [  Printer ](/docs/plugins/printer/)
* [  Purchases ](/docs/plugins/purchases/)
* [  RealtimeKit ](/docs/plugins/realtimekit/)
* [  Screen Orientation ](/docs/plugins/screen-orientation/)
* [  Screenshot ](/docs/plugins/screenshot/)
* [  Secure Preferences ](/docs/plugins/secure-preferences/)
* [  Speech Recognition ](/docs/plugins/speech-recognition/)
* [  Speech Synthesis ](/docs/plugins/speech-synthesis/)
* [  Share Target ](/docs/plugins/share-target/)
* [  Square Mobile Payments ](/docs/plugins/square-mobile-payments/)
* [  SQLite ](/docs/plugins/sqlite/)
* [  Superwall ](/docs/plugins/superwall/)
* [  Torch ](/docs/plugins/torch/)
* [  Wifi ](/docs/plugins/wifi/)
* [  Zip ](/docs/plugins/zip/)
* [  Cloud ](/docs/cloud/)
* [  Live Updates ](/docs/cloud/live-updates/)
* Advanced
* Integrations
* [  Native Builds ](/docs/cloud/native-builds/)
* [  Configuration ](/docs/cloud/native-builds/configuration/)
* [  Environments ](/docs/cloud/native-builds/environments/)
* Guides
* [  Sample Projects ](/docs/cloud/native-builds/sample-projects/)
* [  Troubleshooting ](/docs/cloud/native-builds/troubleshooting/)
* [  Automations ](/docs/cloud/automations/)
* [  Assist ](/docs/cloud/assist/)
* Account
* Organizations
* [  Organization and User Management ](/docs/cloud/organizations/memberships/)
* [  Single Sign-On (SSO) ](/docs/cloud/organizations/sso/)
* [  Teams ](/docs/cloud/organizations/teams/)
* [  Two-Factor Authentication ](/docs/cloud/organizations/two-factor-authentication/)
* [  Integrations ](/docs/cloud/integrations/)
* [  License Keys ](/docs/cloud/license-keys/)
* [  Webhooks ](/docs/cloud/webhooks/)
* [  Pricing ](https://capawesome.io/pricing/)
* [  FAQ ](/docs/cloud/faq/)
* [  Support ](/docs/cloud/support/)
* [  Contributing ](/docs/contributing/)
* [  LLMs ](/docs/llms/)
* [  Insiders ](/docs/insiders/)
* [  License ](https://capawesome.io/legal/eula/)
* [  Support ](/docs/insiders/support/)
* [  FAQ ](/docs/insiders/faq/)
* [  Blog ](/blog/)
* Categories

* [  Framework-Specific Configuration ](#framework-specific-configuration)
* [  Connecting Your Project to Xcode and Android Studio ](#connecting-your-project-to-xcode-and-android-studio)
* [  Live Reload Workflow During Development ](#live-reload-workflow-during-development)
* [  App Icons and Splash Screens ](#app-icons-and-splash-screens)
* [  Adding Native Functionality with Plugins ](#adding-native-functionality-with-plugins)
* [  Live Updates: Benefits, Limits, and Best Use Cases ](#live-updates-benefits-limits-and-best-use-cases)
* [  Native vs Web Changes Decision Matrix ](#native-vs-web-changes-decision-matrix)
* [  Common Pitfalls and Fixes ](#common-pitfalls-and-fixes)
* [  Performance Tips in the WebView ](#performance-tips-in-the-webview)
* [  Automating Build and Deploy with Capawesome Cloud ](#automating-build-and-deploy-with-capawesome-cloud)
* [  Try Capawesome Cloud ](#try-capawesome-cloud)
* [  Conclusion ](#conclusion)

# Build Mobile Apps with Any Web Framework and Capacitor[¶](#build-mobile-apps-with-any-web-framework-and-capacitor "Permanent link")

If your team already ships a modern web app with React, Angular, Vue, Svelte, or another framework, you don't need to start from scratch to reach the iOS and Android stores. Capacitor lets you wrap your existing frontend code in native projects and add mobile capabilities where you actually need them.

This guide walks through the full workflow across frameworks, from setup and native platform generation to Xcode and Android Studio integration, live reload, and release automation. We also cover common pitfalls, how to add native functionality with plugins, and where Capawesome Cloud fits when you want to automate builds and deployment.

[ ![Build and deploy your Capacitor app with Capawesome Cloud](../../assets/external/cloud.capawesome.io/assets/banners/cloud-build-and-deploy-capacitor-apps.69628c3f.png) ](https://capawesome.io/) 

## Why Capacitor Works with Any Web Framework[¶](#why-capacitor-works-with-any-web-framework "Permanent link")

Capacitor is an open-source runtime developed by the Ionic team that runs your web app as a native iOS and Android app. It packages your built web assets into a native shell and renders them inside a `WebView`, while a thin native bridge exposes device APIs to your JavaScript code through plugins.

Because Capacitor only cares about your final build output, the framework you use to produce that output is mostly irrelevant. Whether you're building with React, Angular, Vue, Svelte, or another JavaScript framework, the core workflow stays almost identical. In practice, the biggest differences are your build command and the output directory you point Capacitor at.

## Shared Setup Flow for Any Framework[¶](#shared-setup-flow-for-any-framework "Permanent link")

Start from your existing web project root.

### 1\. Install Capacitor[¶](#1-install-capacitor "Permanent link")

`[](#%5F%5Fcodelineno-0-1)npm install @capacitor/core@latest
[](#%5F%5Fcodelineno-0-2)npm install -D @capacitor/cli@latest
`

### 2\. Initialize Capacitor[¶](#2-initialize-capacitor "Permanent link")

`[](#%5F%5Fcodelineno-1-1)npx cap init
`

The CLI prompts you for your app name, app ID (e.g. `io.company.app`), and web output directory (`dist`, `build`, `www`, `.output/public`, and so on). See [Framework-Specific Configuration](#framework-specific-configuration) below for typical values per framework.

### 3\. Add Native Platforms[¶](#3-add-native-platforms "Permanent link")

`[](#%5F%5Fcodelineno-2-1)npm install @capacitor/ios@latest @capacitor/android@latest
[](#%5F%5Fcodelineno-2-2)npx cap add ios
[](#%5F%5Fcodelineno-2-3)npx cap add android
`

### 4\. Build Web Assets and Sync[¶](#4-build-web-assets-and-sync "Permanent link")

`[](#%5F%5Fcodelineno-3-1)npm run build
[](#%5F%5Fcodelineno-3-2)npx cap sync
`

### 5\. Open Native Projects[¶](#5-open-native-projects "Permanent link")

`[](#%5F%5Fcodelineno-4-1)npx cap open ios
[](#%5F%5Fcodelineno-4-2)npx cap open android
`

This becomes your core dev loop: `build -> sync -> open/run`.

## Framework-Specific Configuration[¶](#framework-specific-configuration "Permanent link")

Most of the workflow is identical across frameworks. The main difference is the `webDir` value in your [Capacitor configuration](https://capacitorjs.com/docs/config) file, which must match your framework's build output directory. Here's a typical `capacitor.config.ts` for each framework:

AngularReact (Vite)Vue (Vite)SvelteKit

capacitor.config.ts

`[](#%5F%5Fcodelineno-5-1)import { CapacitorConfig } from "@capacitor/cli";
[](#%5F%5Fcodelineno-5-2)
[](#%5F%5Fcodelineno-5-3)const config: CapacitorConfig = {
[](#%5F%5Fcodelineno-5-4)  appId: "io.company.app",
[](#%5F%5Fcodelineno-5-5)  appName: "Example App",
[](#%5F%5Fcodelineno-5-6)  webDir: "www"
[](#%5F%5Fcodelineno-5-7)};
[](#%5F%5Fcodelineno-5-8)
[](#%5F%5Fcodelineno-5-9)export default config;
`

Use `www` if you set `outputPath` accordingly in `angular.json`, or `dist/<project-name>/browser` for Angular's default build output.

capacitor.config.ts

`[](#%5F%5Fcodelineno-6-1)import { CapacitorConfig } from "@capacitor/cli";
[](#%5F%5Fcodelineno-6-2)
[](#%5F%5Fcodelineno-6-3)const config: CapacitorConfig = {
[](#%5F%5Fcodelineno-6-4)  appId: "io.company.app",
[](#%5F%5Fcodelineno-6-5)  appName: "Example App",
[](#%5F%5Fcodelineno-6-6)  webDir: "dist"
[](#%5F%5Fcodelineno-6-7)};
[](#%5F%5Fcodelineno-6-8)
[](#%5F%5Fcodelineno-6-9)export default config;
`

For Create React App projects, use `webDir: "build"` instead.

capacitor.config.ts

`[](#%5F%5Fcodelineno-7-1)import { CapacitorConfig } from "@capacitor/cli";
[](#%5F%5Fcodelineno-7-2)
[](#%5F%5Fcodelineno-7-3)const config: CapacitorConfig = {
[](#%5F%5Fcodelineno-7-4)  appId: "io.company.app",
[](#%5F%5Fcodelineno-7-5)  appName: "Example App",
[](#%5F%5Fcodelineno-7-6)  webDir: "dist"
[](#%5F%5Fcodelineno-7-7)};
[](#%5F%5Fcodelineno-7-8)
[](#%5F%5Fcodelineno-7-9)export default config;
`

capacitor.config.ts

`[](#%5F%5Fcodelineno-8-1)import { CapacitorConfig } from "@capacitor/cli";
[](#%5F%5Fcodelineno-8-2)
[](#%5F%5Fcodelineno-8-3)const config: CapacitorConfig = {
[](#%5F%5Fcodelineno-8-4)  appId: "io.company.app",
[](#%5F%5Fcodelineno-8-5)  appName: "Example App",
[](#%5F%5Fcodelineno-8-6)  webDir: "build"
[](#%5F%5Fcodelineno-8-7)};
[](#%5F%5Fcodelineno-8-8)
[](#%5F%5Fcodelineno-8-9)export default config;
`

Use `@sveltejs/adapter-static` so the build output is a fully static directory that Capacitor can package.

If you prefer JSON, you can use `capacitor.config.json` with the same fields. If `webDir` doesn't match your real build output, you'll see a blank screen on launch — see [Common Pitfalls](#common-pitfalls-and-fixes) below.

## Connecting Your Project to Xcode and Android Studio[¶](#connecting-your-project-to-xcode-and-android-studio "Permanent link")

After `cap add`, Capacitor creates two native projects:

* `ios/` for Xcode
* `android/` for Android Studio

Your frontend stays the source of truth for UI and business logic. The native projects handle permissions, signing, native configuration, and app store packaging.

A practical daily workflow looks like this:

1. Change web code.
2. Run `npm run build`.
3. Run `npx cap sync`.
4. Run and debug from Xcode or Android Studio.

When native settings change (permissions, Gradle config, Xcode signing), edit the native project directly. When web assets change, always rebuild and sync to avoid platform drift.

## Live Reload Workflow During Development[¶](#live-reload-workflow-during-development "Permanent link")

To speed up feedback during development, you can use live reload on a real device:

`[](#%5F%5Fcodelineno-9-1)npx cap run android -l --external
[](#%5F%5Fcodelineno-9-2)npx cap run ios -l --external
`

A few prerequisites and gotchas:

* Start your framework's dev server first (`npm run start`, `npm run dev`, etc.) and make sure your computer and device are on the same network.
* `--external` binds the dev server to all network interfaces, so allow incoming connections on the dev server port if your firewall asks.
* Live reload is a development workflow, not a production deployment strategy — disable it before shipping a real build.

## App Icons and Splash Screens[¶](#app-icons-and-splash-screens "Permanent link")

Instead of manually resizing assets, generate platform assets with the official tool:

`[](#%5F%5Fcodelineno-10-1)npm install -D @capacitor/assets@latest
[](#%5F%5Fcodelineno-10-2)npx capacitor-assets generate --ios
[](#%5F%5Fcodelineno-10-3)npx capacitor-assets generate --android
`

Recommended workflow:

1. Keep your icon and splash screen original files in a `resources/` directory.
2. Generate iOS and Android assets from those sources.

Tool reference: [@capacitor/assets](https://github.com/ionic-team/capacitor-assets).

## Adding Native Functionality with Plugins[¶](#adding-native-functionality-with-plugins "Permanent link")

Use plugins when your app needs device features that a browser alone can't provide reliably.

In many cases, native plugins are also the more performant option. Browser APIs are powerful, but plugins can use native execution paths and platform-specific capabilities that are better suited for heavy mobile workloads.

A few examples:

* Capture photos and pick from the gallery with the [Camera](https://capacitorjs.com/docs/apis/camera) plugin.
* Build typical attach-and-upload flows with the [File Picker](/docs/plugins/file-picker/) plugin and [File Compressor](/docs/plugins/file-compressor/) plugin.
* Add secure authentication with the [OAuth](/docs/plugins/oauth/) plugin and [Biometrics](/docs/plugins/biometrics/) plugin.
* Receive content from other apps with the [Share Target](/docs/plugins/share-target/) plugin, or send push notifications by following [The Push Notifications Guide for Capacitor](/blog/capacitor-push-notifications-guide/).

Plugin usage is intentionally minimal — call a method, get a typed result. Here's how taking a photo with the Camera plugin looks from your web code:

`[](#%5F%5Fcodelineno-11-1)import { Camera, CameraResultType } from "@capacitor/camera";
[](#%5F%5Fcodelineno-11-2)
[](#%5F%5Fcodelineno-11-3)const takePhoto = async () => {
[](#%5F%5Fcodelineno-11-4)  const photo = await Camera.getPhoto({
[](#%5F%5Fcodelineno-11-5)    quality: 90,
[](#%5F%5Fcodelineno-11-6)    allowEditing: false,
[](#%5F%5Fcodelineno-11-7)    resultType: CameraResultType.Uri
[](#%5F%5Fcodelineno-11-8)  });
[](#%5F%5Fcodelineno-11-9)
[](#%5F%5Fcodelineno-11-10)  return photo.webPath;
[](#%5F%5Fcodelineno-11-11)};
`

The returned `webPath` can be assigned directly to an `<img>` `src`, so the same call works whether the user took a fresh shot or picked an existing photo from their gallery.

## Live Updates: Benefits, Limits, and Best Use Cases[¶](#live-updates-benefits-limits-and-best-use-cases "Permanent link")

Live Updates let you ship web-layer changes (HTML, CSS, JavaScript) without waiting for app store review on every bug fix. This shortens release cycles and improves response time for production issues.

But the limits matter:

* Live Updates don't replace native binary updates.
* Native changes (a new plugin, a native SDK update, an entitlement change) still require app store builds.

Use Live Updates for fast iteration on the web layer, and native releases for native code changes.

For deeper context, read [How Live Updates for Capacitor Work](/blog/how-live-updates-for-capacitor-work/) and [How Live Updates Are Changing Mobile App Deployment](/blog/how-live-updates-are-changing-mobile-app-deployment/).

## Native vs Web Changes Decision Matrix[¶](#native-vs-web-changes-decision-matrix "Permanent link")

Use this quick matrix to decide whether you should ship through Live Updates or create a new native store build:

| Change type                               | Live Update | New native build |
| ----------------------------------------- | ----------- | ---------------- |
| CSS/UI text/layout fixes                  | Yes         | No               |
| Business logic in web layer               | Yes         | No               |
| New route/page in frontend                | Yes         | No               |
| Add or update Capacitor plugin            | No          | Yes              |
| iOS Info.plist or Android manifest change | No          | Yes              |
| New native SDK dependency                 | No          | Yes              |
| Entitlements, signing, push capabilities  | No          | Yes              |

If a change touches native code or native project configuration, plan for a store release. If it's only web assets, Live Updates is typically the faster path.

## Common Pitfalls and Fixes[¶](#common-pitfalls-and-fixes "Permanent link")

Teams usually hit the same issues during the first week of integration. These are the most common ones and how to fix them quickly:

* **Blank screen on app launch:** `webDir` doesn't match your real build output. Run `npm run build`, confirm the folder exists, update `capacitor.config.*`, then run `npx cap sync`.
* **Web changes not visible in the native app:** you changed web code but skipped rebuild and sync. Always run `npm run build && npx cap sync` before testing in Xcode or Android Studio.
* **Plugin works on one platform only:** platform setup, permissions, or native project files are incomplete. Recheck the plugin installation docs, update the iOS and Android configs, then run `npx cap sync`.
* **iOS signing errors in Xcode:** team, bundle ID, provisioning profile, and certificate are misaligned. Verify those values in Xcode and your Apple Developer account.
* **Android build failures after SDK updates:** Gradle and Android SDK versions drift apart. Align toolchain versions and run a clean rebuild in Android Studio.

## Performance Tips in the WebView[¶](#performance-tips-in-the-webview "Permanent link")

Performance issues in mobile WebViews usually come from oversized assets and heavy startup work. These practices consistently improve startup time and runtime responsiveness:

* Prefer native plugins for device-heavy operations when possible. For example, the [Audio Player](/docs/plugins/audio-player/) plugin uses native playback capabilities and supports background audio, which is important for uninterrupted playback when the app isn't in the foreground. In real projects, native integrations can also improve reliability and throughput for large file operations, as described in [How to Wrap an Angular App with Capacitor and Firebase](/blog/how-to-wrap-an-angular-app-with-capacitor-and-firebase/).
* Keep your initial JavaScript bundle small with route-based code splitting, and defer non-critical scripts until after first render.
* Optimize images and use modern formats where possible — they're cheap on a dev machine and expensive on a phone.
* Avoid large synchronous tasks during app startup, since they block the WebView from rendering the first paint.
* Test on lower-end Android devices (not just current flagships) and watch memory-heavy screens like file previews and long lists, which are where mobile WebViews crack first.

## Automating Build and Deploy with Capawesome Cloud[¶](#automating-build-and-deploy-with-capawesome-cloud "Permanent link")

Once your app runs reliably on real devices, the next step is automating delivery. Capawesome Cloud handles the parts that would otherwise eat your time: [Native Builds](/docs/cloud/native-builds/setup/) produces reproducible iOS and Android binaries in a consistent environment, [Live Updates](/docs/cloud/live-updates/setup/) ships web-layer releases between store submissions, and [App Store Publishing](/docs/cloud/app-store-publishing/) delivers builds straight to TestFlight or Google Play.

A pattern that works well in practice is combining the two release tracks — ship stable native builds through the stores, and use Live Updates for fast iteration on the web layer in between. Wire it all together with [Automations](/docs/cloud/automations/) so the build and deploy pipeline triggers automatically on commit, branch, or tag.

## Try Capawesome Cloud[¶](#try-capawesome-cloud "Permanent link")

Automate native builds, Live Updates, and app store delivery so your team can focus on product work instead of release chores.

[Try Capawesome Cloud Free](https://capawesome.io)

## Conclusion[¶](#conclusion "Permanent link")

Capacitor gives teams a practical way to ship iOS and Android apps from a single modern web codebase. The core workflow stays consistent across React, Angular, Vue, Svelte, and other frameworks: build web assets, sync the native shells, validate on devices, and automate delivery.

If you have questions, join the [Capawesome Discord server](https://discord.gg/VCXxSVjefW) and ask us anything related to Capacitor. To stay up to date on new guides and releases, subscribe to the [Capawesome newsletter](https://capawesome.io/newsletter/).

May 21, 2026 

 Back to top 