Nota: Al momento de escribir este artículo (17 de Febrero de 2023), la versión 13 de Next.js fue lanzado, el 25 de Octubre de 2022 para ser exacto.
El equipo detrás de Next.js ha lanzado recientemente Next.js 13, que tiene un montón de características nuevas como un nuevo directorio app
, componentes para el lado del servidor y del cliente, entre otros.
En este artículo, aprenderás cómo usar el nuevo Next.js 13 y la Base de Datos Firebase para crear una aplicación full stack.
Antes de continuar, para poder seguir el artículo necesitas tener un conocimiento básico de JavaScript, React y Next.js. Si necesitas repasar alguno de esos conceptos, aquí tienes algún recursos para principiantes:
- Aprende JavaScript - contenidos y curso interactivo [en inglés]
- Aprende React - curso completo [en inglés]
- Aprende Next.js - cuadernillo completo [en inglés]
Si estás listo, empecemos.
Cómo crear un nuevo proyecto de Next.js 13
Para instalar Next.js, necesitas tener instalado Node.js y npm/yarn instalado en tu computadora. Si no los tienes, puedes bajarlos desde sus sitios oficiales: Node.js website y npm website (aunque npm está incluido al instalar Node).
- En el directorio que quieras, inicia la terminal de tu computadora y ejecuta el siguiente comando:
npx create-next-app@13 --experimental-app
. - Elige el nombre de tu proyecto y presiona enter para crearlo y esperar a que lo instale.
- Se creará un nuevo directorio con el nombre de tu proyecto con todos archivos necesarios.
- Ejecuta el comando cd para cambiar al directorio nuevo:
cd my-project-name
- Y para iniciar el servidor de desarrollo, ejecuta el siguiente comando:
// si estás usando yarn
yarn run dev
// si estás usando npm
npm run dev
6. Ejecutar este comando iniciará el servidor de desarrollo para que puedas ver tu aplicación en tiempo real en http://localhost:3000.

Cómo instalar Firebase en Next.js
Firebase es una plataforma Baas - Backend-as-a-Service, por su sigla en inglés- que ofrece servicios como autenticación, bases de datos en tiempo real, almacenamiento en la nube, análisis de datos, entre otros.
En este tutorial, usaremos Firebase como nuestra base de datos. Sigue estos pasos para crear una aplicación Firebase:
- En https://console.firebase.google.com/, inicia sesión con tu cuenta de Google.
- Haz click en Crear proyecto y ponle un nombre. Luego, haz clic en Continuar.
- En la pantalla siguiente puedes elegir si quieres habilitar métodos de análisis de datos para tu proyecto.
- Haz clic en Crear proyecto.
Luego, necesitas crear una aplicación web. En la página de inicio, haz clic en el ícono de web para crear la aplicación:

Ponle un nombre a tu aplicación y haz clic en Registrar app:

Copia el archivo de configuración ya que vamos a necesitarlo luego. Haz clic en continuar hasta que termines.
Una vez que estés de vuelta en la página de inicio de tu proyecto, elige un producto que quieras agregar en tu aplicación. Para este tutorial, sólo agrega Authentication y Cloud Firestore:

Para Authentication, elige Método de acceso y agrega Correo electrónico/contraseña.
Después de instalar exitosamente Firebase, ya lo podemos usar como back-end en tu aplicación de Next.js 13.
Para usar Firebase con Next.js, sigue estos pasos.
Instala la última versión del SDK de Firebase en tu proyecto Next.js ejecutando el siguiente comando en tu terminal:
yarn add firebase
// o si estás usando npm
npm install firebase
Crea un archivo .env
en el directorio raíz de tu proyecto Next.js y copia tus archivos de configuración de Firebase (los que habías copiado antes). Debería verse así:
NEXT_PUBLIC_FIREBASE_API_KEY=api-key
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=auth-domain
NEXT_PUBLIC_FIREBASE_PROJECT_ID=project-id
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=storage-bucket
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=sender-id
NEXT_PUBLIC_FIREBASE_APP_ID=app-id
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=analytic-id
Luego, para que se vea todo más prolijo, en tu directorio src crea una carpeta con el nombre firebase y crea un archivo config.js
con el siguiente código;
// Importa las funciones que necesites de los SDKs
import { initializeApp, getApps } from "firebase/app";
const firebaseConfig = {
apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY,
authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN,
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID,
measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID,
};
// Inicializa Firebase
let firebase_app = getApps().length === 0 ? initializeApp(firebaseConfig) : getApps()[0];
export default firebase_app;
Con esto ya listo, ya puedes utilizar Firebase como base de datos en tu aplicación Next.js.
Cómo instalar Authentication
Al querer construir aplicaciones fullstack, lo primero en lo que pensamos es la autenticación de usuarios. Con Firebase, podemos crear una forma de registrar usuarios o de que inicien sesión muy fácilmente.
En tu directorio src > firebase, crea una nueva carpeta con el nombre auth. Todo el código relacionado con la autenticación de firebase lo guardaremos aquí.
Luego, crea un archivo signup.js
dentro del directorio src > firebase > auth con el siguiente código:
import firebase_app from "../config";
import { createUserWithEmailAndPassword, getAuth } from "firebase/auth";
const auth = getAuth(firebase_app);
export default async function signUp(email, password) {
let result = null,
error = null;
try {
result = await createUserWithEmailAndPassword(auth, email, password);
} catch (e) {
error = e;
}
return { result, error };
}
Vamos a descrifrar este código. Lo que estamos haciendo aquí es exportando la función signUp()
que usa el método createUserWithEmailAndPassword() de Firebase para poder registrar nuevos usuarios. Luego de hacer esto, vamos a poder usar la función signUp()
en cualquier lado de nuestra app.
En la misma carpeta, agreguemos nuestra función signIn()
. Para hacer esto, crea un archivo signin.js
con el siguiente código:
import firebase_app from "../config";
import { signInWithEmailAndPassword, getAuth } from "firebase/auth";
const auth = getAuth(firebase_app);
export default async function signIn(email, password) {
let result = null,
error = null;
try {
result = await signInWithEmailAndPassword(auth, email, password);
} catch (e) {
error = e;
}
return { result, error };
}
Cómo crear las páginas para el inicio de sesión y el registro de usuarios en Next.js
En Next.js 13 se puede crear nuevas páginas dentro del directorio app
. Cada página es una carpeta con un archivo page.js
. Para aprender más sobre cómo crear páginas, puedes leer la documentación de Next.js al respecto [en inglés].
Para crear un página de registro de usuarios un nuevo archivo page.js
en signup, dentro de tu directorio app. Luego, agrega el siguiente código:
'use client'
import React from "react";
import signUp from "@/firebase/auth/signup";
import { useRouter } from 'next/navigation'
function Page() {
const [email, setEmail] = React.useState('')
const [password, setPassword] = React.useState('')
const router = useRouter()
const handleForm = async (event) => {
event.preventDefault()
const { result, error } = await signUp(email, password);
if (error) {
return console.log(error)
}
// else successful
console.log(result)
return router.push("/admin")
}
return (<div className="wrapper">
<div className="form-wrapper">
<h1 className="mt-60 mb-30">Sign up</h1>
<form onSubmit={handleForm} className="form">
<label htmlFor="email">
<p>Email</p>
<input onChange={(e) => setEmail(e.target.value)} required type="email" name="email" id="email" placeholder="example@mail.com" />
</label>
<label htmlFor="password">
<p>Password</p>
<input onChange={(e) => setPassword(e.target.value)} required type="password" name="password" id="password" placeholder="password" />
</label>
<button type="submit">Sign up</button>
</form>
</div>
</div>);
}
export default Page;`
Por defecto, cada página que se agrega al directorio page.js
es un componente del servidor [enlace a la documentación en inglés] y por lo tanto no permite agregar interactividad de lado del servidor como un onSubmit()
a elementos de formulario. Para poder agregar esta interactividad, tenemos que decirle a Next.js que queremos un componente Cliente. Para hacer esto, añadimos lo siguiente al comienzo del archivo y antes de importar cualquier otro elemento:
'use client'
// código del componente
Del mismo modo vamos a crear nuestra página de inicio de sesión. Para crear esta página, crea un archivo page.js en signin, dentro de tu directorio app, y agrega el siguiente código:
'use client'
import React from "react";
import signIn from "@/firebase/auth/signin";
import { useRouter } from 'next/navigation'
function Page() {
const [email, setEmail] = React.useState('')
const [password, setPassword] = React.useState('')
const router = useRouter()
const handleForm = async (event) => {
event.preventDefault()
const { result, error } = await signIn(email, password);
if (error) {
return console.log(error)
}
// sino exitoso
console.log(result)
return router.push("/admin")
}
return (<div className="wrapper">
<div className="form-wrapper">
<h1 className="mt-60 mb-30">Sign up</h1>
<form onSubmit={handleForm} className="form">
<label htmlFor="email">
<p>Email</p>
<input onChange={(e) => setEmail(e.target.value)} required type="email" name="email" id="email" placeholder="example@mail.com" />
</label>
<label htmlFor="password">
<p>Password</p>
<input onChange={(e) => setPassword(e.target.value)} required type="password" name="password" id="password" placeholder="password" />
</label>
<button type="submit">Sign up</button>
</form>
</div>
</div>);
}
export default Page;
Cómo saber si hubo algún cambio de autenticación
Mientras estás usando la aplicación, siempre vamos a querer saber si el usuario ha iniciado sesión o no. Si el usuario ha iniciado sesión, es posible crear páginas protegidas y mostrarle ciertos contenidos sólo a él. Firebase tiene el método onAuthStateChanged()
para poder saber si hubo cambios.
Para que la información del usuario obtenida con el método mencionado arriba pueda ser usada en todo la aplicación, vamos a usar la API React Context. Crea un carpeta con el nombre context en tu directorio src. Dentro del directorio directory, crea un archivo con el nombre AuthContext.js
y agrega el siguiente código:
import React from 'react';
import {
onAuthStateChanged,
getAuth,
} from 'firebase/auth';
import firebase_app from '@/firebase/config';
const auth = getAuth(firebase_app);
export const AuthContext = React.createContext({});
export const useAuthContext = () => React.useContext(AuthContext);
export const AuthContextProvider = ({
children,
}) => {
const [user, setUser] = React.useState(null);
const [loading, setLoading] = React.useState(true);
React.useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setUser(user);
} else {
setUser(null);
}
setLoading(false);
});
return () => unsubscribe();
}, []);
return (
<AuthContext.Provider value={{ user }}>
{loading ? <div>Loading...</div> : children}
</AuthContext.Provider>
);
};
Con el código de arriba simplemente creamos un Provider que devuelve el objeto usuario si el usuario inició sesión. De lo contrario, sólo devolverá null
.
Para poder usar el valor que se le pasó a <AuthContext.Provider>
vamos a exportar useAuthContext
desde el archivo y así usar el valor de user
.
Antes de poder usar este contexto, necesitamos envolver todos los componentes con AuthContextProvider
. Para hacer esto, abrimos el archivo layout.js dentro del directorio src > app y editamos el código con lo siguiente:
'use client'
import './globals.css'
import { AuthContextProvider } from '@/context/AuthContext'
export default function RootLayout({ children }) {
return (
<html lang="en">
{/*
<head /> contendrá los componentes devueltos por el padre más cercano
head.js. Encuentra más información en https://beta.nextjs.org/docs/api-reference/file-conventions/head
*/}
<head />
<body>
<AuthContextProvider>
{children}
</AuthContextProvider>
</body>
</html>
)
}
Ahora ya podemos crear páginas protegidas y mostrar contenido específico a usuarios distintos.
Cómo crear páginas protegidas
Dentro del directorio app, crea el directorio admin > page.js y agrega el siguiente código:
'use client'
import React from "react";
import { useAuthContext } from "@/context/AuthContext";
import { useRouter } from "next/navigation";
function Page() {
const { user } = useAuthContext()
const router = useRouter()
React.useEffect(() => {
if (user == null) router.push("/")
}, [user])
return (<h1>Solamente los usuarios que iniciaron sesión pueden ver esta página</h1>);
}
export default Page;
Si el usuario es null
, lo redireccionamos a la página inicial. De lo contrario, si no es null
, le mostramos la página protegida.
Cómo comunicarse con nuestra base de datos
Ahora que ya lidiamos con la parte de autenticación, podemos enfocarnos en la comunicación con nuestra base de datos. Como base de datos vamos a usar Firestore.
Para seguir haciendo todo ordenado, vamos a crear un nuevo directorio llamado firebase > firestore. Dentro de este directorio vamos a guardar todo el código relacionado con Firestore.
Cómo agregar documentos a Firestore
Dentro del directorio firestore, crea un archivo con el nombre addData.js
y agrega el siguiente código:
import firebase_app from "../config";
import { getFirestore, doc, setDoc } from "firebase/firestore";
const db = getFirestore(firebase_app)
export default async function addData(colllection, id, data) {
let result = null;
let error = null;
try {
result = await setDoc(doc(db, colllection, id), data, {
merge: true,
});
} catch (e) {
error = e;
}
return { result, error };
}
Este código ya debería serte familiar: estamos exportando una función que permite agregar información a nuestra base de datos firestore.
Ahora ya podemos usar esta función addData()
desde cualquier componente para agregar información a nuestra base de datos:
'use client'
import addData from "@/firebase/firestore/addData";
export default function Home() {
const handleForm = async () => {
const data = {
name: 'John snow',
house: 'Stark'
}
const { result, error } = await addData('users', 'user-id', data)
if (error) {
return console.log(error)
}
}
return (
...
)
}
Cómo podemos obtener un documento desde Firestore
Usando un método similar, podemos obtener un documento desde nuestra base de datos Firebase.
Crea un archivo getData.js
dentro del directorio Firestore y agrega el siguiente código:
import firebase_app from "../config";
import { getFirestore, doc, getDoc } from "firebase/firestore";
const db = getFirestore(firebase_app)
export default async function getDoument(collection, id) {
let docRef = doc(db, collection, id);
let result = null;
let error = null;
try {
result = await getDoc(docRef);
} catch (e) {
error = e;
}
return { result, error };
}
También podemos usar está función en cualquier componente que quieras.
Conclusión
En este artículo, aprendimos cómo construir una aplicación fullstack usando Firebase y Next.js 13 para agregar autenticación e interacción con nuestra base de datos.
¡Feliz codificación!