Skip to content

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

npm install @capacitor/core@latest
npm install -D @capacitor/cli@latest

2. Initialize Capacitor

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 below for typical values per framework.

3. Add Native Platforms

npm install @capacitor/ios@latest @capacitor/android@latest
npx cap add ios
npx cap add android

4. Build Web Assets and Sync

npm run build
npx cap sync

5. Open Native Projects

npx cap open ios
npx cap open android

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:

capacitor.config.ts
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.

capacitor.config.ts
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.

capacitor.config.ts
import { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
  appId: "io.company.app",
  appName: "Example App",
  webDir: "dist"
};

export default config;
capacitor.config.ts
import { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
  appId: "io.company.app",
  appName: "Example App",
  webDir: "build"
};

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 below.

Connecting Your Project to Xcode and Android Studio

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

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

npx cap run android -l --external
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

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:

  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.

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:

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: 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 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.

Try Capawesome Cloud Free

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.