
Next-routes with Firebase Hosting on Cloud Functions
Hey everyone!
Let’s give some context here! I’m working on a boilerplate for myself with Next.js, Apollo, and make it run on Firebase. So with some research I found this Github repository from James Hegedus where I saw how to make the Next.js app running on Firebase hosting with Firebase functions and I wanted to work with this base and see where it’s going.
For one project, I need a routing management and Next-routes is really popular and work really well with Next.js, especially when you have an express server running. In this article, we are going to use Firebase functions.
So let’s see how we can make Next-routes working with Firebase functions.
👭 Clone the repository and install the dependency
git clone https://github.com/jthegedus/firebase-functions-next-example
cd firebase-functions-next-example
yarn install
Or if you want to work on the final version of this tutorial
git clone https://github.com/JulienHe/firebase-next-routes-example.git
cd firebase-next-routes-example
yarn install
🏃 Run the project
yarn dev
On http://localhost:3000/ you should see something like this :

From here everything is pretty straightforward! It’s cool and it’s running.
I assume that you already create an account on Firebase and init your project too like it’s explained in the article from James Hegedus!
🤓 Let’s
😺 Update our package.json
We are going to use Next.js v5 & module-resolver.
yarn add next@latest
yarn add babel-plugin-module-resolver
yarn add babel-runtime
💁 .babelrc
Now we create a .babelrc
file at the root of our project to use module-resolver and allow us to add new “root” directories that contain our modules (Yes I stole the text from the repo 🙌).
✋ Routes
Time to create some routes! First install Next-routes :
yarn add next-routes
Inside your src
folder create a file routes.js
:
As you can see we are calling next-routes and we export the routes we create in our file. Let’s look how to add a route.
.add('home', '/', 'index')
.add()
can have 3 parameters, a name, a pattern and the page name.
The name will work like your href
link, so instead of calling /something
you can call the name of your route directly. I think it’s a good way to keep the project organized, if one day you change the path, you only need to change in one place.
The pattern is actually the url where you can access the page, like for index it will be /
for about /about
etc. Note: you can also use /about/:id
and retrieve the information from your slug inside your page.
The page name is the page you want to target inside your project. The ones who are inside your /pages
folder.
Note : If you want, you can create a _document.js
to override the default page behavior. It’s also good if you want to use a custom package to manage your css for example. If you want to see how it’s working : here is the example from Next.js and for an example with styled-components 💅 you can check the example here.
Our routes are created. Let’s make it work on the client-side.
👉 Client-side
Inside our /app/components/Header.js
file let’s do some modification :
// Replace ->
import Link from "next/link"// With
import { Link } from 'src/routes.js';
The available properties from { Link }
are the exact same as the one with "next/Link"
.
We also going to change our links :
// From ->
<Link href="/">
<a className={pathname === "/" ? "is-active" : ""}>Home</a>
</Link>// To
<Link route='home' passHref>
<a>Home</a>
</Link>
As you can see, the href is now a route and instead of a path we have our route name, the one we defined before.
Also, I added passHref to pass the href to the my <a>
tag, it’s not mandatory and the link will work perfectly without, I just want to make sure I can visually see that it’s a link. Also by passing the href to the <a>
, robots can crawl it too!
Let’s see how it’s look like at the end :
Check the result on http://localhost:3000/ and click on the link to see the routing working.
👈 Server-side
Now let’s make the server-side part. Inside your functions/app/app.js
we’re gonna add our routes.
If you look at the file you had before and the one you have now, the difference is not big. We import our routes import routes from './routes'
and we changed our getRequestHandler
.
That’s all for our Firebase function.
👊 Update our package.json
Before deploying everything on Firebase, we need to do a small update in our package.json file. We’ll need to copy our route.js file inside our dist/functions
folder to make sure that our Firebase function can access it because we do not export it yet.
// after build-app add
"copy-routes": "cpx \"src/routes.js\" \"dist/functions/app\" -C",
This will copy our routes.js in the folder where our app.js is build. And to be sure that every time we deploy our app we copy our route.js file we need to update our Firebase predeploy function :
// From
"functions": {
"source": "dist/functions",
"predeploy":
"yarn build-funcs && yarn build-app && yarn copy-deps && yarn install-deps"
}// To
"functions": {
"source": "dist/functions",
"predeploy":
"yarn build-funcs && yarn build-app && yarn copy-deps && yarn copy-routes && yarn install-deps"
}
Everything together you should have something like this :
🔥 Deploy
Now everything is ready to deploy. If you have any error message when you visit your app, go check the console who will give you a lot of information to know where is the problem.
yarn deploy-all
You can now visit your page on Firebase. Demo.
🚨🚨🚨 WARNING 🚨🚨🚨
If you test the app with your development environment, you’ll probably see the /blog
page when you click on the link inside the header

But if your reload the page you’ll see an error :

This is issue is coming by the fact that we are not able to run our Firebase functions locally as explain here by James Hegedus. If a solution is coming, I’ll update this article and make sure everything run smoothly. Also this issue is only with dev on local cloud functions, when you are refreshing the app on Firebase everything is working perfectly ⭐️!
Final repo
This article is one of my first about development, hope you enjoyed it!
Thank you! And thanks a lot to James Hegedus for your starter repo!
Julien.