Introducción
¿Ya tienes una web app en Nuxt? En esta guía, aprenderás a transformarla en apps nativas para iOS y Android usando Capacitor 8 — la última versión con mejor rendimiento y nuevas funciones.
Capacitor envuelve tu app web en un contenedor nativo y te da acceso a APIs del dispositivo como cámara, filesystem y notificaciones push, sin cambiar tu codebase de Vue. A diferencia de Flutter o React Native, no tienes que reescribir nada: tu code de Nuxt funciona tal cual.
Lo que aprenderás:
- Configurar tu app Nuxt existente para generación estática
- Añadir Capacitor 8 con plugins nativos esenciales
- Compilar y probar en simuladores de iOS y Android
- Activar live reload para un desarrollo más rápido
- Corregir problemas comunes de layout en iOS (viewport, safe area, horizontal overflow)
- Añade una UI con sensación nativa con Capgo Native Navigation y Transitions
¿Quieres empezar un proyecto nuevo desde cero? Mira nuestra guía sobre Cómo crear una app móvil con Nuxt desde cero.
Beneficios de usar Nuxt y Capacitor
- Reutilización de Code: Comparte tus componentes y lógica de Vue entre apps web y móviles.
- Rendimiento: La generación estática de Nuxt crea bundles optimizados para móviles.
- Capacidades nativas: Accede a funciones del dispositivo como cámara, geolocalización y filesystem mediante plugins de Capacitor.
- Desarrollo simplificado: Usa patrones familiares de Vue/Nuxt sin aprender desarrollo nativo.
Requisitos
Antes de empezar, asegúrate de tener:
- Node.js 18+ instalado
- Un Nuxt 4 aplicación
- Xcode (para desarrollo iOS, solo macOS)
- Android Studio (para desarrollo Android)
Configurar tu app Nuxt para móvil
El primer paso es configurar tu app de Nuxt para generación estática. Capacitor requiere archivos HTML/JS/CSS estáticos para el bundle de la app nativa.
Asegúrate de que tu package.json tiene el script generate:
{
"scripts": {
"dev": "nuxt dev",
"build": "nuxt build",
"generate": "nuxt generate",
"preview": "nuxt preview",
"mobile": "bun run generate && bunx cap sync",
"mobile:ios": "bun run mobile && bunx cap open ios",
"mobile:android": "bun run mobile && bunx cap open android"
}
}
Importante: Si usas funciones de servidor (API routes, middleware de servidor, etc.), deberás refactorizarlas para usar alternativas de cliente o APIs externas.
Prueba la generación estática ejecutando:
bun run generate
Deberías ver un .output/public carpeta con tus archivos estáticos. Esto es lo que Capacitor empaquetará en tu app nativa.
Añadir Capacitor 8 a tu proyecto
Para empaquetar tu app de Nuxt en un contenedor móvil nativo, sigue estos pasos:
- Instala Capacitor core y CLI:
bun add @capacitor/core
bun add -D @capacitor/cli
- Instala los plugins de Capacitor más comunes que probablemente necesites:
bun add @capacitor/app @capacitor/keyboard @capacitor/splash-screen @capacitor/status-bar @capacitor/preferences
Estos plugins ofrecen funciones esenciales:
- @capacitor/app: Gestiona eventos del ciclo de vida (foreground/background, deep links)
- @capacitor/keyboard: Controlar el comportamiento del teclado en móviles
- @capacitor/splash-screen: Gestionar la splash screen nativa
- @capacitor/status-bar: Estilizar la barra de estado del dispositivo
- @capacitor/preferences: Almacenamiento clave-valor (como localStorage pero nativo)
- Inicializa Capacitor con los detalles de tu proyecto:
bunx cap init my-app com.example.myapp --web-dir .output/public
Reemplazar my-app con el nombre de tu app y com.example.myapp con el ID de tu app (notación de dominio inverso).
- Crea o actualiza el
capacitor.config.tsarchivo con la configuración adecuada:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: '.output/public',
plugins: {
SplashScreen: {
launchShowDuration: 2000,
launchAutoHide: true,
androidScaleType: 'CENTER_CROP',
splashFullScreen: true,
splashImmersive: true,
},
Keyboard: {
resize: 'body',
resizeOnFullScreen: true,
},
StatusBar: {
style: 'dark',
},
},
};
export default config;
- Instala las plataformas nativas:
bun add @capacitor/ios @capacitor/android
- Añade las carpetas de las plataformas nativas:
bunx cap add ios
bunx cap add android
Capacitor creará ios y android carpetas en la raíz de tu proyecto con los proyectos nativos.
Para compilar el proyecto de Android, necesitas Android Studio. Para iOS, necesitas un Mac con Xcode.
- Haz el build y sincroniza tu proyecto:
bun run mobile
Esto ejecuta tu script personalizado que genera el build estático de Nuxt y sincroniza los archivos con las plataformas nativas.
Build y despliegue de apps nativas
Para construir y desplegar tu app móvil nativa, sigue estos pasos:
Para desarrollar apps de iOS, necesitas tener Xcode instalado, y para apps de Android, necesitas tener Android Studio instalado. Además, si planeas distribuir tu app en la tienda de apps, debes inscribirte en el Apple Developer Program para iOS y en la Google Play Console para Android.
- Abre los proyectos nativos:
Para iOS:
bun run mobile:ios
Para Android:
bun run mobile:android
O directamente con Capacitor CLI:
bunx cap open ios
bunx cap open android
- Build y ejecuta la app:

- En Android Studio, espera a que el proyecto esté listo y haz clic en el botón “Run” para desplegar la app en un dispositivo conectado o emulador.

- En Xcode, configura tu cuenta de signing para desplegar la app en un dispositivo real. Si es la primera vez, Xcode te guiará en el proceso (ten en cuenta que debes estar inscrito en el Apple Developer Program). Una vez configurado, haz clic en el botón “Play” para ejecutar la app en tu dispositivo.
¡Felicidades! Has desplegado con éxito tu web app de Nuxt en un dispositivo móvil.
Pero espera, también hay una forma más rápida de hacer esto durante el desarrollo…
Live Reload con Capacitor
Durante el desarrollo, puedes aprovechar el live reloading para ver los cambios al instante en tu móvil. Para activar esta función, sigue estos pasos:
- Busca tu dirección IP local:
-
En macOS, ejecuta el siguiente comando en la terminal:
ipconfig getifaddr en0 -
En Windows, ejecuta:
ipconfigBusca la dirección IPv4 en la salida del comando.
- Actualiza tu
capacitor.config.tspara apuntar a tu servidor de desarrollo:
import type { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.example.app',
appName: 'my-app',
webDir: '.output/public',
server: {
url: 'http://YOUR_IP_ADDRESS:3000',
cleartext: true,
},
plugins: {
// ... your plugin config
},
};
export default config;
Reemplazar YOUR_IP_ADDRESS con tu dirección IP local (ej., 192.168.1.100).
- Aplica los cambios a tu proyecto nativo:
bunx cap copy
El copy el comando copia la carpeta web y los cambios de configuración al proyecto nativo sin actualizar todo el proyecto.
- Inicia tu servidor de dev de Nuxt y reconstruye en Xcode/Android Studio:
bun run dev
Ahora, cada vez que hagas cambios en tu app de Nuxt, la app móvil se recargará automáticamente para reflejarlos.
Nota: Si instalas nuevos plugins o modificas archivos nativos, tendrás que reconstruir el proyecto nativo, ya que el live reloading solo aplica a cambios en el code web.
Uso de Capacitor Plugins
Los plugins de Capacitor te permiten acceder a funciones nativas del dispositivo desde tu app de Nuxt. Veamos cómo usar el plugin Share como ejemplo:
- Instala el plugin Share:
bun add @capacitor/share
- Crea o actualiza una página para usar el plugin Share. En Nuxt 4, las páginas van en
app/pages/:
<template>
<div class="p-6">
<h1 class="text-2xl font-bold mb-4">Welcome to Nuxt + Capacitor!</h1>
<button
@click="shareContent"
class="px-6 py-3 bg-blue-600 text-white rounded-lg font-semibold"
>
Share now!
</button>
</div>
</template>
<script setup lang="ts">
import { Share } from '@capacitor/share';
async function shareContent() {
await Share.share({
title: 'Check this out!',
text: 'Built with Nuxt and Capacitor',
url: 'https://capacitorjs.com',
dialogTitle: 'Share with friends',
});
}
</script>
- Sincroniza los cambios con el proyecto nativo:
bun run mobile
O simplemente sincroniza sin reconstruir:
bunx cap sync
- Reconstruye y ejecuta la app en tu dispositivo.
Ahora, al pulsar el botón “Share now!”, aparecerá el diálogo nativo para compartir.
Después, puedes hacer que la app se sienta más nativa en iOS y Android con la navegación y las transiciones de Capgo, y solucionar problemas comunes de layout en iOS que causan desbordamiento horizontal o áreas seguras recortadas.
UI con sensación nativa, navegación y transiciones nativas de Capgo
He trabajado durante años con Ionic para crear aplicaciones multiplataforma, pero integrarlo con Nuxt es complicado y rara vez vale la pena si ya tienes Tailwind CSS.
Para una experiencia nativa en una app de Nuxt + Capacitor, usa plugins de Capgo en lugar de UI kits web como Konsta UI:
- @capgo/capacitor-native-navigation — navbar nativa, Liquid Glass tab bar en iOS y un estilo de tab bar con desenfoque en Android. El router de Nuxt gestiona el estado de las rutas; el plugin controla el chrome nativo.
- @capgo/capacitor-transitions — transiciones de página estilo Ionic y swipe-back desde el borde en iOS en la capa WebView, sin adoptar Ionic UI.
Instala ambos:
bun add @capgo/capacitor-native-navigation @capgo/capacitor-transitions
bunx cap sync
Configura la navegación nativa con CSS inset mode para que el contenido web respete las barras nativas:
import { NativeNavigation } from '@capgo/capacitor-native-navigation';
await NativeNavigation.configure({
contentInsetMode: 'css',
animationDuration: 360,
glass: {
effect: 'liquidGlass',
},
});
Renderiza una tab bar Liquid Glass (iOS usa renderizado del sistema; Android usa un fondo WebView con desenfoque):
await NativeNavigation.setTabbar({
selectedId: 'home',
labelVisibilityMode: 'labeled',
icons: true,
colors: { dynamic: true },
tabs: [
{ id: 'home', title: 'Home', icon: { svg: '...' } },
{ id: 'settings', title: 'Settings', icon: { svg: '...' } },
],
});
await NativeNavigation.addListener('tabSelect', ({ id }) => {
router.push(`/${id}`);
});
Añade transiciones de página nativas en tu app shell:
<script setup>
import { ref, onMounted } from 'vue';
import { useRouter } from 'vue-router';
import '@capgo/capacitor-transitions';
import { initTransitions, setDirection, setupRouterOutlet } from '@capgo/capacitor-transitions/vue';
initTransitions({ platform: 'auto' });
const router = useRouter();
const outletRef = ref(null);
onMounted(() => {
if (outletRef.value) {
setupRouterOutlet(outletRef.value, { platform: 'auto', swipeGesture: 'auto' });
}
});
const openSettings = () => {
setDirection('forward');
router.push('/settings');
};
</script>
<template>
<cap-router-outlet ref="outletRef">
<router-view />
</cap-router-outlet>
</template>
Envuelve las páginas enrutadas en cap-router-outlet, cap-page, y cap-content, y llama a setDirection('forward') o setDirection('back') antes de navegar. No dupliques headers o footers web si la navegación nativa ya gestiona esas áreas.
Consulta las guías completas: Uso de @capgo/capacitor-native-navigation y Uso de @capgo/capacitor-transitions.
Safe areas con Tailwind
Para las safe areas del dispositivo en Tailwind CSS, usa @capgo/tailwind-capacitor (publicado como tailwind-capacitor en npm). Proporciona safe-areas utilidades y otros plugins de Tailwind compatibles con Capacitor:
bun add -D tailwind-capacitor
En app/assets/css/main.css:
@import 'tailwindcss';
@plugin "@capgo/tailwind-capacitor/platform";
@plugin "@capgo/tailwind-capacitor/safe-areas";
Para Nuxt 4 con Tailwind CSS 4, mantén esta importación en el archivo CSS referenciado por nuxt.config.ts.
Usa utilidades como pt-safe, pb-safe, y px-safe en lugar de añadir env(safe-area-inset-*) manualmente. El proyecto está en desarrollo activo; si falta algo para tu configuración de Nuxt, abre un PR en GitHub.
Cómo solucionar problemas de layout en iOS (viewport, safe area y overflow horizontal)
Si el contenido se ve recortado, desplazado o con scroll horizontal en iOS, añadir más overflow-x: hidden o ajustar solo la etiqueta viewport no suele solucionarlo. Revisa estas comprobaciones en orden.
Asegúrate de que la meta tag viewport esté bien aplicada
En nuxt.config.ts, configura el viewport mediante app.head:
export default defineNuxtConfig({
app: {
head: {
meta: [
{
name: 'viewport',
content: 'width=device-width, initial-scale=1, viewport-fit=cover',
},
],
},
},
});
Gestiona el safe area de iOS desde un único wrapper raíz
Crea un único app shell y aplica el padding de safe area ahí, no en múltiples componentes anidados:
html,
body,
#__nuxt {
width: 100%;
min-height: 100%;
margin: 0;
padding: 0;
overflow-x: hidden;
}
* {
box-sizing: border-box;
}
.app-shell {
min-height: 100dvh;
width: 100%;
padding-top: env(safe-area-inset-top);
padding-right: env(safe-area-inset-right);
padding-bottom: env(safe-area-inset-bottom);
padding-left: env(safe-area-inset-left);
}
Envuelve todo el contenido de la página dentro de .app-shell. El padding de safe-area duplicado en headers, modales y wrappers de layout suele hacer que la UI parezca recortada o demasiado grande.
Con @capgo/tailwind-capacitor, puedes aplicar el mismo padding usando utilidades como pt-safe pb-safe px-safe en ese único shell.
Configura Capacitor iOS contentInset a never primero
En capacitor.config.ts, prefiere desactivar el inset nativo y dejar que CSS (o la navegación nativa) contentInsetMode: 'css') se encargue del safe area:
const config: CapacitorConfig = {
appId: 'com.example.myapp',
appName: 'my-app',
webDir: 'out',
ios: {
contentInset: 'never',
},
};
Combinar el content inset automático de Capacitor con CSS env(safe-area-inset-*) es una causa común de espaciado doble.
Encuentra el elemento que realmente desborda
El culpable habitual es un elemento que usa 100vw, Tailwind w-screen, un ancho fijo en píxeles, o un min-width.
En Safari Web Inspector, ejecuta:
[...document.querySelectorAll('*')]
.filter(el => el.scrollWidth > document.documentElement.clientWidth)
.map(el => ({
el,
tag: el.tagName,
class: el.className,
scrollWidth: el.scrollWidth,
clientWidth: document.documentElement.clientWidth,
}));
Con Tailwind, reemplaza w-screen con w-full siempre que sea posible. Muchos problemas de desbordamiento horizontal vienen de 100vw / w-screen, padding de safe-area duplicado o un contenedor de ancho fijo, no del propio meta tag del viewport.
Conclusión
Has convertido con éxito tu aplicación web de Nuxt en apps nativas para iOS y Android usando Capacitor 8. Tu codebase de Vue ahora se ejecuta de forma nativa en dispositivos móviles con acceso a las APIs del dispositivo.
Lo que has logrado:
- Configuración de Nuxt para generación estática
- Añadido Capacitor 8 con plugins esenciales
- Build y despliegue en simuladores iOS y Android
- Live reload habilitado para desarrollo
- Se corrigieron errores comunes de layout en iOS (viewport, safe area, overflow)
- Interfaz con sensación nativa gracias a Capgo Native Navigation y Transitions
Próximos pasos:
- Configura Capgo para actualizaciones over-the-air sin reenviar a la app store
- Añadir más plugins nativos como Camera, Geolocation o Push Notifications
- Configurar los iconos y splash screens para producción
- Preparar la app para enviarla a App Store y Google Play
¿Empiezas un proyecto desde cero? Mira Cómo crear una app móvil con Nuxt desde cero para un tutorial guiado.
Recursos
- Documentación de Nuxt
- Documentación de Capacitor 8
- @capgo/capacitor-native-navigation — Barra de pestañas Liquid Glass y chrome nativo
- @capgo/capacitor-transitions — transiciones de página con estilo nativo
- @capgo/tailwind-capacitor — Utilidades safe-area de Tailwind para Capacitor
- Capgo - Live Updates para apps de Capacitor
Descubre cómo Capgo puede ayudarte a crear mejores apps más rápido: crea una cuenta gratis hoy.
Continúa desde Convierte tu App de Nuxt a iOS y Android con Capacitor 8
Si estás usando Convierte tu app de Nuxt a iOS y Android con Capacitor 8 para planificar el trabajo con plugins nativos, conéctalo con Directorio de plugins de Capgo para el flujo de trabajo del producto en Capgo Plugin Directory, Plugins de Capacitor por Capgo para el detalle de implementación en los Plugins de Capacitor por Capgo, Añadir o actualizar plugins para el detalle de implementación en Agregar o actualizar plugins, Alternativas a plugins de Ionic Enterprise para el flujo de trabajo en Alternativas a plugins de Ionic Enterprise, y Native Builds de Capgo para el flujo de trabajo del producto en Capgo Native Builds.