Build Mobile Apps with Any Web Framework and Capacitor¶
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.
Why Capacitor Works with Any Web Framework¶
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¶
Start from your existing web project root.
1. Install Capacitor¶
2. Initialize Capacitor¶
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 below for typical values per framework.
3. Add Native Platforms¶
4. Build Web Assets and Sync¶
5. Open Native Projects¶
This becomes your core dev loop: build -> sync -> open/run.
Framework-Specific Configuration¶
Most of the workflow is identical across frameworks. The main difference is the webDir value in your Capacitor configuration file, which must match your framework's build output directory. Here's a typical capacitor.config.ts for each framework:
import { CapacitorConfig } from "@capacitor/cli";
const config: CapacitorConfig = {
appId: "io.company.app",
appName: "Example App",
webDir: "www"
};
export default config;
Use www if you set outputPath accordingly in angular.json, or dist/<project-name>/browser for Angular's default build output.
import { CapacitorConfig } from "@capacitor/cli";
const config: CapacitorConfig = {
appId: "io.company.app",
appName: "Example App",
webDir: "dist"
};
export default config;
For Create React App projects, use webDir: "build" instead.
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 below.
Connecting Your Project to Xcode and Android Studio¶
After cap add, Capacitor creates two native projects:
ios/for Xcodeandroid/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:
- Change web code.
- Run
npm run build. - Run
npx cap sync. - 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¶
To speed up feedback during development, you can use live reload on a real device:
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. --externalbinds 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¶
Instead of manually resizing assets, generate platform assets with the official tool:
npm install -D @capacitor/assets@latest
npx capacitor-assets generate --ios
npx capacitor-assets generate --android
Recommended workflow:
- Keep your icon and splash screen original files in a
resources/directory. - Generate iOS and Android assets from those sources.
Tool reference: @capacitor/assets.
Adding Native Functionality with Plugins¶
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 plugin.
- Build typical attach-and-upload flows with the File Picker plugin and File Compressor plugin.
- Add secure authentication with the OAuth plugin and Biometrics plugin.
- Receive content from other apps with the Share Target plugin, or send push notifications by following The Push Notifications Guide for Capacitor.
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:
import { Camera, CameraResultType } from "@capacitor/camera";
const takePhoto = async () => {
const photo = await Camera.getPhoto({
quality: 90,
allowEditing: false,
resultType: CameraResultType.Uri
});
return photo.webPath;
};
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 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 and How Live Updates Are Changing Mobile App Deployment.
Native vs Web Changes Decision Matrix¶
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¶
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:
webDirdoesn't match your real build output. Runnpm run build, confirm the folder exists, updatecapacitor.config.*, then runnpx 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 syncbefore 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 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 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.
- 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¶
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 produces reproducible iOS and Android binaries in a consistent environment, Live Updates ships web-layer releases between store submissions, and 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 so the build and deploy pipeline triggers automatically on commit, branch, or tag.
Try Capawesome Cloud¶
Automate native builds, Live Updates, and app store delivery so your team can focus on product work instead of release chores.
Conclusion¶
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 and ask us anything related to Capacitor. To stay up to date on new guides and releases, subscribe to the Capawesome newsletter.