Tutorial10 min read

Convert your Nuxt app to iOS and Android with Capacitor

Turn a Nuxt 3/4 app into native iOS and Android apps with Capacitor using static generation, add device plugins, and ship instant updates over the air with OtaKit.

Nuxt is a full-stack framework, but for a mobile app you only need the front end — a static build that runs client-side inside a native shell. Capacitor takes that build and turns your Nuxt app into real iOS and Android apps, no rewrite required. Your pages, components, composables, and Pinia stores all run as-is.

This guide takes a Nuxt 3/4 app to installable native builds, then wires up OtaKit so you can push web-layer updates over the air in minutes.

Mental model: server-rendered Nuxt features stay on your server; the app that ships to devices is the static client build. OtaKit keeps that build up to date over the air.

1. Configure Nuxt for a static client app

Capacitor needs a folder of static files with no Node server at runtime. Render the app as a client-side SPA and generate it:

// nuxt.config.ts
export default defineNuxtConfig({
  ssr: false, // ship a client-rendered SPA to the device
  app: { baseURL: "./" }, // relative asset paths for file:// context
});
npx nuxi generate   # outputs .output/public

Server routes, Nitro API handlers, and server-only middleware won't run inside the shell — move those to an API your app calls over HTTPS, which is how a mobile client should talk to a backend anyway.

2. Add Capacitor

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

npx cap init "My App" com.example.myapp --web-dir .output/public

npm install @capacitor/ios @capacitor/android
// capacitor.config.ts
import type { CapacitorConfig } from "@capacitor/cli";

const config: CapacitorConfig = {
  appId: "com.example.myapp",
  appName: "My App",
  webDir: ".output/public",
};

export default config;

3. Build and run

npx nuxi generate
npx cap add ios
npx cap add android
npx cap sync
// package.json
"scripts": {
  "mobile": "nuxi generate && npx cap sync"
}

Then npx cap open ios or npx cap open android to run on a simulator or device.

4. Use native device features

npm install @capacitor/share
npx cap sync
import { Share } from "@capacitor/share";

async function shareLink() {
  await Share.share({ title: "Check this out", url: "https://example.com" });
}

5. Add live updates with OtaKit

npm install @otakit/capacitor-updater
npx cap sync
// capacitor.config.ts
const config: CapacitorConfig = {
  appId: "com.example.myapp",
  appName: "My App",
  webDir: ".output/public",
  plugins: {
    OtaKit: { appId: "YOUR_OTAKIT_APP_ID" },
  },
};

Signal a clean boot from your root app component so a bad release rolls back on its own:

// app.vue
<script setup lang="ts">
import { onMounted } from "vue";
import { Capacitor } from "@capacitor/core";
import { OtaKit } from "@otakit/capacitor-updater";

onMounted(() => {
  if (Capacitor.isNativePlatform()) OtaKit.notifyAppReady();
});
</script>
npm install -g @otakit/cli
otakit login

npx nuxi generate
otakit upload --release

Once your app is on the stores with the plugin configured, each otakit upload --release reaches installed devices on the next launch — new UI, content, and fixes the same day. Native changes still require a store submission; your Nuxt client build does not.

OtaKit doesn't meter monthly active users or bandwidth — see how it compares in the 2026 OTA tools roundup.

Where to go next

Read how OTA works for the delivery model, and the Vue guide if you want a plain-Vue variant of this flow.

Related docs