DEV Community

Cover image for How to deploy Next.js to Firebase
Glenn Viroux
Glenn Viroux

Posted on

How to deploy Next.js to Firebase

Next.js is a powerful framework for building web applications, built on top of React.js and Node.js. As per Stackoverflow’s 2022 Developer Survey, React.js is the second most loved web framework, right after Node.js. Next.js provides a great set of features for building production-ready applications, such as server-side rendering and static site generation.

Firebase, on the other hand, is an easy-to-use platform by Google that helps you build mobile and web applications.

If you're developing a web application using these two technologies, you're in good company. However, when I was developing Ballistic, I stumbled upon a number of issues when trying to deploy the application. In this article, we'll explore these issues and walk through a step-by-step guide to successfully deploy your Next.js application on GCP.

Firebase Framework-Aware Hosting for Next.js

Firebase Hosting is a robust and reliable option for hosting websites, particularly when you require rapid and easy deployment. It is a fully-managed hosting service provided by Google, which allows developers to deploy web applications and static content to a global content delivery network (CDN) with a simple command. Firebase Hosting's free tier is particularly appealing for small projects, as it provides a limited amount of storage and data transfer per day at no cost. If your website grows beyond the free tier limits, you can use pay-as-you-go pricing, which allows you to pay only for the resources that you use.

Firebase's framework-aware hosting is a valuable integration that allows for seamless deployment of popular web frameworks such as Angular and Next.js. If you're using Next.js, Firebase will automatically detect your next.config.js file and recognize that you're running a Next.js web application. This results in Firebase translating your Next.js settings into Firebase settings with minimal configuration needed. Additionally, if your app includes dynamic server-side logic, the integration will translate it into Cloud Functions for Firebase. This integration can significantly streamline the deployment process for developers, making it a convenient and efficient option for hosting web applications.

One of the challenges with these "black box integrations" is that when something goes wrong, it can be difficult to troubleshoot. In the case of Next.js and Firebase hosting, an error message such as "Couldn't find a pages directory. Please create one under the project root" can leave developers scratching their heads. When you've verified that the issue isn't caused by your own code, you may be left with no other option than to create an issue on GitHub (if it's an open source project) or contact support and hope for a quick resolution.

That’s why, in this blog post, we’ll explore how to manually translate the Next.js configuration settings to Firebase settings, so we don’t have to rely on the experimental integration of Next.js in Firebase.

Translating Your Next.js App to Firebase

One of the core advantages of Next.js is its support for Server-Side Rendering (SSR), which allows web pages to be pre-rendered on the server, rather than relying on client-side JavaScript to render the page. This translates to a significant improvement in user experience, as the user can view a fully rendered HTML page almost instantly, without waiting for JavaScript or CSS files to load.

By translating your Next.js app to Firebase, you can further enhance its speed and scalability, as Firebase offers a robust and reliable platform for hosting and serving web content. With Firebase Hosting, you can easily deploy and serve your pre-rendered Next.js app to a global audience, providing them with a fast and seamless browsing experience.

To achieve this, we need to divide our Next.js codebase into two parts: the client and the server. The server part will define a Firebase function that handles SSR, while the client part will contain the rest of our Next.js codebase. In the following steps, we'll cover all the details of creating a Next.js project and deploying it to Firebase, from start to finish.

Setting up the Project

Let's begin by setting up our Next.js project by running the following command:

yarn create next-app next-firebase --typescript --eslint --src-dir --no-tailwind
Enter fullscreen mode Exit fullscreen mode

Accept the default interactive options, and you should see a message saying Success! Created next-firebase.

This will give you a fully functional Next.js codebase that you can test quickly by starting the development server:

yarn dev
Enter fullscreen mode Exit fullscreen mode

Then, open your browser and navigate to http://localhost:3000

Creating Server and Client Separation

After successfully setting up your project in the previous step, let's move on to splitting your codebase into a server function responsible for SSR and a client codebase containing all the Next.js code.

Create a client and server folder inside the src directory. Move the original contents of the src directory to the client directory, along with the public folder, next.config.js file, and tsconfig.json file. This will leave the server folder empty for now. We'll populate it with a Firebase function responsible for SSR in the next steps.

Creating the SSR Server Code

To create the function responsible for server-side rendering, we need to install some dependencies first. Run the following command to install them:

yarn add firebase-admin firebase-functionscd 
yarn add **@babel/core @babel/cli @babel/preset-env cross-env rimraf**
Enter fullscreen mode Exit fullscreen mode

After installing the dependencies, create an index.js file inside the server folder, as shown below:

import * as admin from 'firebase-admin';
import * as functions from 'firebase-functions';
import next from 'next';

admin.initializeApp();

const dev = process.env.NODE_ENV !== 'production';
const app = next({
    dev,
    // the absolute directory from the package.json file that initialises this module
    // IE: the absolute path from the root of the Cloud Function
    conf: { distDir: 'dist/client' },
});
const handle = app.getRequestHandler();

export const nextjsServer = functions.https.onRequest((request, response) => {
    // log the page.js file or resource being requested
    console.log('File: ' + request.originalUrl);
    return app.prepare().then(() => handle(request, response));
});
Enter fullscreen mode Exit fullscreen mode

Since we'll be transpiling this code with Babel, we need to instruct Babel on how to compile the code. We'll create a .babelrc file inside the server folder for this purpose:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {
          "node": "10.15.3"
        }
      }
    ]
  ]
}
Enter fullscreen mode Exit fullscreen mode

Updating package.json

We need to update the scripts in our package.json to reflect the new folder structure we created:

"scripts": {
    "dev:client": "next src/client",
    "dev:server": "babel src/server --out-dir dist/server --source-maps --watch",
    "dev": "yarn run dev:client & yarn run dev:server",
    "build:client": "next build src/client",
    "build:server": "babel src/server --out-dir dist/server --source-maps",
    "build": "yarn run build:client && yarn run build:server"
}
Enter fullscreen mode Exit fullscreen mode

At this point, you can spin up a local development server that hosts your client side code and serves your SSR server. You can also build a production-ready version of your Next.js app.

Also add the following lines to your package.json, in order to override the main entrypoint to your server:

With these changes, you can spin up a local development server that hosts your client-side code and serves your SSR server. You can also build a production-ready version of your Next.js app.

Additionally, add the following lines to your package.json to override the main entry point to your server:

"main": "dist/server/index.js",
"engines": {
  "node": "16"
},
Enter fullscreen mode Exit fullscreen mode

These lines ensure that when you deploy your app to Firebase, it uses the compiled version of your server code instead of the original source code. They also specify that the app requires Node.js version 16 to run.

Setting up Firebase

To integrate Firebase with our Next.js app, we'll need to create a new Firebase project in the Firebase console. If you already have a project set up, you can skip this step. Once you've created your project, you can add Firebase to your web app by navigating to the "Project Settings" page, clicking on the gear icon next to "Project Overview," and selecting "Add to Web App" on the "General" tab. Here, you can register your new web application.

Next, in the root directory of your project, run the following command to initialize Firebase:

firebase init
Enter fullscreen mode Exit fullscreen mode

In the root directory of your project. During Project Setup, select the following options:

  • Firebase Hosting and Firebase Functions
  • use an existing project, and select the firebase project you just created or that you wish to use
  • What language would you like to use to write Cloud Functions? → JavaScript
  • Do you want to install dependencies with npm now? → No
  • Detected an existing Next.js codebase in the current directory, should we use this? → No
  • Do you want to use a web framework? (experimental) → No
  • What do you want to use as your public directory? → Public
  • Configure as a single-page app (rewrite all urls to /index.html)? → No
  • Set up automatic builds and deploys with GitHub? → No

After running this command, a .firebaserc file and a firebase.json file will be created in your root folder. You'll need to modify the firebase.json file to include the following code:

{
  "hosting": {
    "public": "public",
    "rewrites": [
      {
        "source": "**/**",
        "function": "nextjsServer"
      }
    ]
  },
  "functions": {
        "runtime": "nodejs16"
    "source": ".",
    "ignore": [
      ".firebase/**",
      ".firebaserc",
      "firebase.json",
      "**/node_modules/**",
      "**/public/**",
      "**/cache/**"
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

The previous process also generates a public folder with a 404.html file and an index.html file. Make sure to delete the index.html file before continuing.

Test your website and deploy

At this point, you can test your web app locally, share your changes with others, and deploy the app to the public. To test your app locally, you can use the serve script from package.json:

yarn serve
Enter fullscreen mode Exit fullscreen mode

After verifying that your web app works fine locally by running the serve script from package.json, you're ready to deploy it to the public. To do this, you need to add the necessary deployment scripts to your package.json file:

"scripts": {
    "predeploy": "rimraf dist/ && yarn run build",
    "deploy": "cross-env NODE_ENV=production firebase deploy --only functions,hosting",
 }
Enter fullscreen mode Exit fullscreen mode

Now, when you're ready to deploy your app, you can simply run yarn deploy to deploy your app to Firebase hosting.

Conclusion

In conclusion, we have covered the entire process of building and deploying a Next.js web app with Firebase Cloud Functions and Firebase Hosting. By following the steps outlined in this post, you should now be able to create and launch your own Next.js app with Firebase.

The full source code for this project is available on GitHub at: https://github.com/GlennViroux/next-firebase-blog.

Thank you for reading, and I hope this article has been informative and helpful for you.

Top comments (3)

Collapse
 
marcellintacite profile image
Aksanti Bahiga tacite

Hello, i am getting errors while hosting my next app to firebase using the app directory and ssr. Could you help me

Collapse
 
kdalkafoukis profile image
Konstantinos Dalkafoukis

Very nice article. One small comment.
Node.js is a javascript runtime environment, not a framework

Collapse
 
glennviroux profile image
Glenn Viroux

That's right! Stack Overflow just uses it among it most loved web technologies / web frameworks: survey.stackoverflow.co/2022/#web-...