Capstart

Installation

An opinionated Vite React and Capacitor installation setup for mobile apps.

Capacitor is extremely permissive. It does not force a UI framework, a router, a rendering model, or a design system. You can literally build any kind of app with it: a simple Tailwind UI, a fully custom canvas experience, a Vue, Svelte, Solid, Angular, React, or vanilla JavaScript app, or a web-first mobile app with native plugins only where they matter.

That freedom is the point: Capacitor gives you a native shell and access to native APIs, but it does not impose a very specific app architecture. Your app can stay close to the web stack you already like, and you can decide case by case when native capabilities are useful.

You can start from the Capstart boilerplate or follow the manual setup below. The manual path is only one opinionated approach. It is not the Capacitor way, because there is no single Capacitor way. It keeps the app simple: Vite React for the web app, Capacitor for the native shell, Tailwind with optional shadcn/ui, and native libraries when you need them: notifications, RevenueCat integration, social login, or any other mobile capability your app depends on.

Choose your starting point

Capstart boilerplate

Start from a product-ready app with React, Capacitor, Supabase auth, Tailwind v4, shadcn/ui, protected routes, and native iOS/Android projects already wired together.

Use Capstart

Manual setup

Build the stack yourself when you want to understand every layer or adapt the setup to an existing backend, router, design system, or app structure.

Follow the manual steps

Capstart boilerplate

Use Capstart when you want a product app baseline immediately: Supabase session handling, protected routes, shadcn/ui components, and native iOS/Android projects are already in place.

npx degit AdrienADV/capstart/capstart-boilerplate my-app
cd my-app
npm install
cp .env.example .env
npm run dev

After cloning, fill the Supabase values in .env, then update appId and appName in capacitor.config.ts before shipping.

Open Capstart on GitHub

Manual setup

1. Create a Vite React app

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run build

Vite gives you a fast React app with normal web tooling. That is the main advantage of Capacitor: your screens, state, styling, API calls, auth, and AI-assisted UI work stay in the web ecosystem.

2. Add Capacitor

npm install @capacitor/core @capacitor/cli
npx cap init

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

For a Vite app, the production web build usually lives in dist. Make sure your Capacitor config points to that folder:

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

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'My App',
  webDir: 'dist',
};

export default config;

Before adding UI libraries, I recommend installing a small set of baseline Capacitor plugins that almost every mobile app ends up needing:

npm install @capacitor/keyboard @capacitor/network @capacitor/device @capacitor/splash-screen @capacitor/status-bar
npx cap sync

These are not UI libraries by themselves. They are the native app basics I would add early so the app can handle mobile behavior cleanly:

PluginWhy install it by defaultDocs
@capacitor/keyboardHandles keyboard show/hide events, resize behavior, and keyboard-specific UI adjustments.Keyboard docs
@capacitor/networkLets the app react to online/offline state and degraded connectivity.Network docs
@capacitor/deviceReads device information such as platform, model, OS version, and app/device identifiers.Device docs
@capacitor/splash-screenControls when the native splash screen is shown or hidden during app startup.Splash Screen docs
@capacitor/status-barControls status bar color, style, overlays, and light/dark appearance.Status Bar docs

Also install @capgo/vite-capacitor as a dev dependency. It is a Vite plugin, not a Capacitor runtime plugin, but it belongs here because it solves a friction point that shows up immediately after step 2: during development the native apps need to point at Vite's dev server URL, and that URL changes depending on your host and port. This plugin writes it into the native config files when npm run dev starts and restores the originals when it stops, so you never manually edit those files.

npm install --save-dev @capgo/vite-capacitor

After installing them, extend capacitor.config.ts with the native defaults worth locking in. In this set, Keyboard, SplashScreen, and StatusBar are the plugins with configuration values that affect the native shell:

capacitor.config.ts
import type { CapacitorConfig } from '@capacitor/cli';
import { KeyboardResize, KeyboardStyle } from '@capacitor/keyboard';
import { Style } from '@capacitor/status-bar';

const config: CapacitorConfig = {
  appId: 'com.example.app',
  appName: 'My App',
  webDir: 'dist',
  plugins: {
    Keyboard: {
      resize: KeyboardResize.Native,
      style: KeyboardStyle.Default,
      resizeOnFullScreen: true,
    },
    SplashScreen: {
      launchAutoHide: true,
      launchShowDuration: 500,
      launchFadeOutDuration: 200,
      backgroundColor: '#ffffff',
      showSpinner: false,
    },
    StatusBar: {
      overlaysWebView: false,
      style: Style.Default,
      backgroundColor: '#ffffff',
    },
  },
};

export default config;

Network and Device do not need entries in capacitor.config.ts; they are runtime APIs you call from your app code. On recent Android versions, StatusBar.overlaysWebView and StatusBar.backgroundColor can be limited by enforced edge-to-edge system UI, so still design screens with safe areas in mind.

4. Configure Tailwind and aliases

npm install tailwindcss @tailwindcss/vite

Update vite.config.ts so Vite loads Tailwind and resolves the @/ import alias used by shadcn/ui:

vite.config.ts
import viteCapacitor from '@capgo/vite-capacitor';
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import path from 'node:path';
import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [react(), tailwindcss(), viteCapacitor({ platforms: ['ios', 'android'] })],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
});

Then update tsconfig.app.json so TypeScript understands the same alias. Keep the rest of the file as generated by Vite:

tsconfig.app.json
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}

5. Add shadcn/ui, optionally

This starter configures Tailwind and the @/ alias, but it does not duplicate the shadcn/ui installation flow. If you want to add shadcn/ui, follow the official Vite guide: shadcn/ui Vite installation.

Use that page as the source of truth for the current shadcn commands and component setup.

6. Sync and open the native projects

At this point, keep the installation focused on the stable base: the web app, Capacitor, Tailwind, aliases, and the small set of native plugins you know you need.

Build the web bundle, sync it into the native projects, then open the platform you want to test:

npm run build
npx cap sync
npx cap open ios
npx cap open android

You do not have to make every surface native from day one. A Tailwind bottom bar is enough for many apps, and you can add native-feeling transitions, native bars, social login, purchases, widgets, or other mobile-specific pieces later when the product actually needs them.

After installation, read the Deployment page before your first release. It explains when to submit a new store build and when a web-only update can be enough.

On this page

Need help with your app?

Our team can help you integrate Capstart.