📘 ¿Quieres una base sólida de Ionic desde cero? Si prefieres aprender Ionic (y Firebase) de forma ordenada y de principio a fin, en lugar de ir saltando entre tutoriales sueltos, te dejo mi libro: Desarrollo de aplicaciones móviles con Ionic y Firebase desde cero.
Para navegar entre páginas en Ionic 8 usas el router de Angular: defines las rutas con provideRouter, saltas de una página a otra con routerLink (o por código con NavController) y lees los parámetros de la URL con ActivatedRoute. El ion-router-outlet se encarga de las transiciones nativas (deslizar hacia delante y hacia atrás) para que tu app se sienta como una app de verdad, no como una web. En esta guía lo montamos paso a paso con el enfoque moderno de componentes standalone.
Actualizado: julio 2026 — revisado con Ionic 8.8 y Angular standalone.
Aquí tienes el índice completo del tutorial de Ionic para seguir el hilo:
Índice del tutorial de Ionic >>
- Tutorial de Ionic: Introducción
- Estructura de un proyecto en Ionic
- Mini juego de acertar números
- Navegación entre páginas (estás aquí)
- Menú lateral con ion-menu
- Navegación por tabs (pestañas)
- Componentes personalizados
- Peticiones HTTP a una API REST
- Formularios reactivos
Cómo funciona la navegación en Ionic
Ionic no tiene un sistema de rutas propio: usa directamente el Router de Angular. Lo que aporta Ionic es el ion-router-outlet, una versión del router-outlet de Angular que además aplica las animaciones nativas de transición (empujar la página nueva desde la derecha, volver deslizando hacia la izquierda) y mantiene las páginas en una pila, como hace iOS o Android.
Eso significa que casi todo lo que sabes del router de Angular (rutas, parámetros, guards, lazy loading) te sirve tal cual en Ionic. La diferencia está en un detalle que veremos enseguida: routerDirection, que le dice a Ionic qué animación usar.
Preparar el proyecto y las rutas
Creamos un proyecto con la plantilla blank. Desde Ionic 7 el CLI genera proyectos standalone por defecto (sin NgModule):
ionic start navegacion blank --type=angular cd navegacion
Generamos una segunda página para tener a dónde ir:
ionic generate page pagina2
En un proyecto standalone las rutas se declaran en app.routes.ts y cada página se carga de forma perezosa (solo cuando se visita) con loadComponent, en lugar del antiguo loadChildren con módulos:
// app.routes.ts
import { Routes } from '@angular/router';
export const routes: Routes = [
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{
path: 'home',
loadComponent: () => import('./home/home.page').then(m => m.HomePage),
},
{
path: 'pagina2',
loadComponent: () => import('./pagina2/pagina2.page').then(m => m.Pagina2Page),
},
{
// La misma página, pero recibiendo un parámetro :id
path: 'pagina2/:id',
loadComponent: () => import('./pagina2/pagina2.page').then(m => m.Pagina2Page),
},
];
Y en main.ts registramos el router y, muy importante en Ionic, la IonicRouteStrategy (que es la que hace que las páginas se reutilicen y las animaciones funcionen bien):
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { RouteReuseStrategy, provideRouter, withComponentInputBinding } from '@angular/router';
import { provideIonicAngular, IonicRouteStrategy } from '@ionic/angular/standalone';
import { AppComponent } from './app/app.component';
import { routes } from './app/app.routes';
bootstrapApplication(AppComponent, {
providers: [
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy },
provideIonicAngular(),
provideRouter(routes, withComponentInputBinding()),
],
});
(El withComponentInputBinding() lo usaremos más abajo para recibir los parámetros de la ruta de forma automática; puedes dejarlo puesto desde ya.)
Navegar con routerLink (la forma declarativa)
La manera más sencilla de ir a otra página es desde la plantilla, con routerLink. Le añadimos routerDirection="forward" para que Ionic use la animación de «avanzar»:
<!-- home.page.html -->
<ion-header>
<ion-toolbar>
<ion-title>Home</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<ion-button routerLink="/pagina2" routerDirection="forward">
Ir a la página 2
</ion-button>
</ion-content>
Como cada página es standalone, en su .ts hay que importar los componentes que usa la plantilla, incluido RouterLink:
// home.page.ts
import { Component } from '@angular/core';
import { RouterLink } from '@angular/router';
import {
IonHeader, IonToolbar, IonTitle, IonContent, IonButton,
} from '@ionic/angular/standalone';
@Component({
selector: 'app-home',
standalone: true,
templateUrl: './home.page.html',
imports: [RouterLink, IonHeader, IonToolbar, IonTitle, IonContent, IonButton],
})
export class HomePage {}
Navegar por código con NavController
Cuando la navegación depende de una acción (validar un formulario, una respuesta del servidor…), necesitas navegar desde el TypeScript. Ionic ofrece NavController, que envuelve al router y aplica la animación correcta. En standalone lo importas desde @ionic/angular/standalone y lo inyectas con inject():
// home.page.ts
import { Component, inject } from '@angular/core';
import { NavController, IonButton, IonContent, IonHeader, IonToolbar, IonTitle } from '@ionic/angular/standalone';
@Component({
selector: 'app-home',
standalone: true,
templateUrl: './home.page.html',
imports: [IonButton, IonContent, IonHeader, IonToolbar, IonTitle],
})
export class HomePage {
private nav = inject(NavController);
irAPagina2() {
this.nav.navigateForward('/pagina2');
}
}
Los tres métodos que vas a usar el 99% del tiempo:
navigateForward('/ruta')— avanza a una página nueva (animación hacia delante).navigateBack('/ruta')— vuelve (animación hacia atrás).navigateRoot('/ruta')— reinicia la pila de navegación (útil tras un login: no quieres que el botón «atrás» vuelva a la pantalla de acceso).
Y en la plantilla, el botón llama al método:
<ion-button (click)="irAPagina2()">Ir a la página 2</ion-button>
Volver a la página anterior
Para el típico botón de «volver» de la barra superior, Ionic tiene un componente dedicado: ion-back-button. Muestra la flecha de retroceso adecuada según la plataforma (iOS/Android) y vuelve automáticamente. El defaultHref es la ruta a la que ir si el usuario entró directo a esa página (por ejemplo, desde un enlace externo) y no hay historial:
<!-- pagina2.page.html -->
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-back-button defaultHref="/home"></ion-back-button>
</ion-buttons>
<ion-title>Página 2</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<p>Soy la página 2.</p>
</ion-content>
Recuerda importar IonButtons e IonBackButton en el componente. Si prefieres controlar la vuelta por código, usa this.nav.navigateBack('/home').
Pasar datos entre páginas
El caso más habitual: abres un detalle pasándole un id. Se manda como parte de la URL (ruta pagina2/:id que ya declaramos). Navegar es tan simple como incluir el valor:
<!-- Declarativo --> <ion-button routerLink="/pagina2/42" routerDirection="forward">Ver detalle 42</ion-button>
// O por código
this.nav.navigateForward('/pagina2/42');
Y en la página de destino lo lees. La forma fiable y de siempre es inyectar ActivatedRoute y sacar el parámetro del paramMap:
// pagina2.page.ts
import { Component, inject, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
@Component({ /* ...standalone... */ })
export class Pagina2Page implements OnInit {
private route = inject(ActivatedRoute);
id: string | null = null;
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id'); // "42"
}
}
Alternativa moderna (Angular 16+): si activaste withComponentInputBinding() en provideRouter (lo hicimos en main.ts), el router puede rellenar solo un input con el mismo nombre que el parámetro. Con las signal inputs queda así de limpio:
import { Component, input } from '@angular/core';
@Component({ /* ...standalone... */ })
export class Pagina2Page {
// Se rellena automáticamente con el :id de la ruta
id = input<string>();
}
Y en la plantilla lo lees como una señal: <p>Recibí el id: {{ id() }}</p>. Es más elegante, pero si te da problemas con enlaces directos (deep links), tira del ActivatedRoute clásico, que nunca falla.
¿Y si necesitas pasar un objeto entero, no solo un id? No lo metas en la URL: guárdalo en un servicio compartido (un pequeño store con Angular) o vuelve a pedirlo por su id en el destino con una petición HTTP. Meter objetos serializados en la URL es frágil y feo.
Proteger rutas con un guard
Para impedir el acceso a una página según una condición (por ejemplo, que el usuario haya iniciado sesión) se usan los functional guards, el enfoque actual de Angular (una simple función, sin clases):
// auth.guard.ts
import { inject } from '@angular/core';
import { CanActivateFn, Router } from '@angular/router';
import { AuthService } from './auth.service';
export const authGuard: CanActivateFn = () => {
const auth = inject(AuthService);
const router = inject(Router);
if (auth.estaLogueado()) {
return true;
}
// Redirige al login si no está autenticado
return router.parseUrl('/login');
};
Se aplica en la ruta con canActivate:
{
path: 'privado',
canActivate: [authGuard],
loadComponent: () => import('./privado/privado.page').then(m => m.PrivadoPage),
}
routerDirection y las animaciones
El detalle que diferencia a Ionic de una web normal es routerDirection, que controla la animación de transición:
forward— la página entra desde la derecha (avanzas).back— la página sale hacia la derecha (retrocedes).root— sin animación de pila; sustituye la vista actual (ideal para cambiar de sección desde un menú lateral o unas tabs).
Si no lo indicas, Ionic intenta adivinarlo por el historial, pero especificarlo hace que las transiciones se sientan siempre correctas.
Errores típicos (y cómo evitarlos)
- Olvidar la
IonicRouteStrategy. Sin ella, las páginas no se reutilizan bien y las animaciones y el botón «atrás» se comportan raro. Va sí o sí en losprovidersdemain.ts. - El parámetro llega
null. Casi siempre es que la ruta no tiene el:id(declarastepagina2pero nopagina2/:id), o que el nombre del parámetro no coincide con el que lees enparamMap.get('...'). - Importaste el componente pero no la directiva. Si usas
routerLinken la plantilla, tienes que importarRouterLinken elimportsdel componente standalone; si no, el enlace no hace nada. - La animación va al revés. Especifica
routerDirectionexplícitamente en vez de dejar que Ionic lo adivine.

Seguimos con el tutorial
Ya sabes moverte entre páginas. El siguiente paso es organizar esa navegación con los dos patrones clásicos de una app: el menú lateral con ion-menu y la navegación por tabs. Y cuando quieras traer datos reales a tus páginas, pasa por peticiones HTTP a una API REST y por formularios reactivos.
📘 ¿Quieres aprender Ionic de forma ordenada, no a saltos? Todo esto (navegación, menús, tabs, HTTP, Firebase) y mucho más, paso a paso y con imágenes, en mi libro Desarrollo de aplicaciones móviles con Ionic y Firebase desde cero.
📱 ¿Prefieres que te desarrolle yo la app? Mira mi presupuesto para desarrollo de apps y cuéntame tu idea.
También puedes seguirme en Twitter en @revi_apps y no olvides que me ayudas mucho si compartes este post en las redes sociales.

Hola
He hecho dos app diferentes y al ponerla en el movil, una me sustituye la otra.
Problema supongo del appID.
Lo cambio en el fichero AndroidManifest.xml pero siempre vuelva a ponerse solo el ID anterior.
Como cambiarlo definitivamente?
O como cambiarlo en ionic antes de build android?
Hola Ivo,
Si estás utilizando apache cordova para empaquetar la aplicación tienes que cambiar el id de la aplicacion en config.xml donde pone:
widget id=»io.ionic.starter» version=»0.0.1″ xmlns=»http://www.w3.org/ns/widgets» … tienes que cambiar io.ionic.starter por el id de tu aplicación.
Si estás utilizando capacitor tienes que cambiar el appId en capacitor.config.json
Un saludo
Buenas , necesito ayuda , estoy intentando hacer esto » pasar el id del producto y con el id utilizar un servicio para obtener los datos relacionados con el producto seleccionado » lo he hecho de manera local pero no he logrado hacerlo cuando los datos son traidos de una api , me gustaría tener un poco de ayuda , gracias.