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.