<br />

Pair Cloud Functions with Firebase Hosting to generate and serve your
dynamic content or build REST APIs as microservices.

[Cloud Functions for Firebase](https://firebase.google.com/docs/functions.md.txt) lets you automatically run backend
code in response to HTTPS requests. Your code is stored in Google's cloud and
runs in a managed environment. There's no need to manage and scale your own
servers.

**For example use cases and samples for Cloud Functions integrated with
Firebase Hosting, visit our
[serverless overview](https://firebase.google.com/docs/hosting/serverless-overview.md.txt).**

## Connect Cloud Functions to Firebase Hosting

This section provides a walk-through example for connecting a function to
Firebase Hosting.

Note that to improve the performance of serving dynamic content, you can
optionally tune your [cache settings](https://firebase.google.com/docs/hosting/manage-cache.md.txt).

### **Step 1:** Set up Cloud Functions

1. Make sure that you have the latest version of the Firebase CLI and that
   you've initialized Firebase Hosting.

   For detailed instructions about installing the CLI and initializing
   Hosting, see the
   [Get Started guide for Hosting](https://firebase.google.com/docs/hosting/quickstart.md.txt).
2. Make sure that you've set up Cloud Functions:

   - If you've *already* set up Cloud Functions, you can proceed to
     [Step 2: Create and test an HTTPS function](https://firebase.google.com/docs/hosting/functions.md.txt#create-test-function).

   - If you've *not* set up Cloud Functions:

     1. Initialize Cloud Functions by running the following command from
        the root of your project directory:

        ```
        firebase init functions
        ```
     2. When prompted, select JavaScript (this walk-through example uses JS).

     3. Check that you have a `functions` directory in your local project
        directory (created by the Firebase command you just ran). This
        `functions` directory is where the code for Cloud Functions lives.

### **Step 2:** Create and test an HTTPS function for your Hosting site

1. Open `/functions/index.js` in your favorite editor.

2. Replace the file's contents with the following code.

   This code creates an HTTPS function (named `bigben`) that replies to HTTPS
   requests with a `BONG` for each hour of the day, just like a clock.

       const functions = require('firebase-functions/v1');

       exports.bigben = functions.https.onRequest((req, res) => {
         const hours = (new Date().getHours() % 12) + 1  // London is UTC + 1hr;
         res.status(200).send(`<!doctype html>
           <head>
             <title>Time</title>
           </head>
           <body>
             ${'BONG '.repeat(hours)}
           </body>
         </html>`);
       });

3. Test your functions locally using the
   [Firebase Local Emulator Suite](https://firebase.google.com/docs/emulator-suite.md.txt).

   1. From the root of your local project directory, run the following
      command:

      ```
      firebase emulators:start
      ```
   2. Access the function via the local URL returned by the CLI, for
      example:
      `http://localhost:5001/PROJECT_ID/us-central1/bigben`.

Visit the [Cloud Functions documentation](https://firebase.google.com/docs/functions/http-events.md.txt)
to learn more about HTTPS requests.

The next step walks you through how to access this HTTPS function *from a
Firebase Hosting URL* so that it can generate dynamic content for your
Firebase-hosted site.

### **Step 3:** Direct HTTPS requests to your function

With
[rewrite rules](https://firebase.google.com/docs/hosting/full-config.md.txt#rewrites), you can direct requests
that match specific patterns to a single destination. The following steps show
you how to direct all requests from the path `../bigben` on your Hosting
site to execute the `bigben` function.

1. Open your [`firebase.json` file](https://firebase.google.com/docs/cli.md.txt#the_firebasejson_file).

2. Add the following `rewrite` configuration under the `hosting` section:

       "hosting": {
         // ...

         // Add the "rewrites" attribute within "hosting"
         "rewrites": [ {
           "source": "/bigben",
           "function": {
             "functionId": "bigben",
             "region": "us-central1"  // optional (see note below)
             "pinTag": true           // optional (see note below)
           }
         } ]
       }

3. Confirm that your redirect works as expected by testing again with the
   Firebase emulators.

   1. From the root of your local project directory, run the following
      command:

      ```
      firebase emulators:start
      ```
   2. Visit the locally hosted URL for your site as returned by the CLI
      (usually `localhost:5000`), but append the URL with `bigben`, like so:
      `http://localhost:5000/bigben`

4. Iterate on your function and its functionality for your site. Use the
   Firebase emulators to test these iterations.

<br />

**How `region`
works within the `function` block**

<br />

> If `region` is omitted from a `function` block of the `hosting.rewrites`
> config, the Firebase CLI attempts to automatically detect the region from
> the function's source code which, if unspecified, defaults to `us-central1`.
> If the function's source code is unavailable, the CLI attempts to detect
> the region from the deployed function. If the function is in multiple regions,
> the CLI requires `region` to be specified in the `hosting.rewrites`
> config.

<br />

<br />

<br />

**How
`pinTag` works within the `function` block**

<br />

> The `pinTag` feature is only available in Cloud Functions for Firebase (2nd gen).
> With this feature, you can ensure that each function for generating your
> site's dynamic content is kept in sync with your static Hosting resources
> and Hosting config. Also, this feature allows you to preview your rewrites
> to functions on Hosting preview channels.
>
> If you add `"pinTag": true` to a `function` block of the `hosting.rewrites`
> config, then the "pinned" function will be deployed along with your static
> Hosting resources and configuration, even when running
> `firebase deploy --only hosting`. If you roll back a
> version of your site, the "pinned" function is also rolled back.
>
> > [!NOTE]
> > **Note:** If you add a `pinTag` to an *existing* rewrite, you must first deploy the updated rewrite to your "live" channel. After that deploy, you can then preview changes to your function's code in Hosting preview channels without affecting production.
>
> This feature relies on
> [Cloud Run tags](https://cloud.google.com/run/docs/rollouts-rollbacks-traffic-migration#tags),
> which have a limit of 1000 tags per service and 2000 tags per region. This
> means that after hundreds of deploys, the oldest versions of a site may stop
> working.

<br />

<br />

For the best performance, colocate your functions with Hosting by
choosing one of the following regions:

- `us-west1`
- `us-central1`
- `us-east1`
- `europe-west1`
- `asia-east1`

> [!NOTE]
> **Note:** Firebase Hosting is subject to a 60-second request timeout. Even if you configure your HTTPS function with a longer request timeout, you'll still receive an HTTPS status code `504` (request timeout) if your function requires more than 60 seconds to run. To support dynamic content that requires longer compute time, consider using an [App Engine flexible environment](https://cloud.google.com/appengine/docs/flexible/).

Visit the Hosting configuration page for
[more details about rewrite rules](https://firebase.google.com/docs/hosting/full-config.md.txt#rewrites). You can
also learn about the
[priority order of responses](https://firebase.google.com/docs/hosting/full-config.md.txt#hosting_priority_order)
for various Hosting configurations.

Note that to improve the performance of serving dynamic content, you can
optionally tune your [cache settings](https://firebase.google.com/docs/hosting/manage-cache.md.txt).

### **Step 4:** Deploy your function

Once your function is working as desired in the emulator, you can proceed to
deploying, testing, and running it with *real* project resources. This is a
good time to consider setting runtime options to
[control scaling behavior](https://firebase.google.com/docs/functions/manage-functions.md.txt#min-max-instances)
for functions running in production.

> [!NOTE]
> **Note:** To deploy to a runtime environment of Node.js 10 and higher, your Firebase project must be on the [Blaze pricing plan](https://firebase.google.com/pricing.md.txt). For more details, refer to [Cloud Functions pricing](https://firebase.google.com/docs/functions/faq-and-troubleshooting.md.txt#functions-pricing).

1. Deploy your function as well as your Hosting content and config to your
   site by running the following command from the root of your local project
   directory:

   ```
   firebase deploy --only functions,hosting
   ```
2. Access your live site and your function at the following URLs:

   - Your Firebase subdomains:  

     `PROJECT_ID.web.app/bigben` and
     `PROJECT_ID.firebaseapp.com/bigben`

   - Any connected [custom domains](https://firebase.google.com/docs/hosting/custom-domain.md.txt):  

     `CUSTOM_DOMAIN/bigben`

> [!CAUTION]
> **Caution:** New HTTP and HTTP callable functions deployed with any Firebase CLI lower than version 7.7.0 are private by default and throw HTTP 403 errors when invoked. Either explicitly [make these functions public](https://cloud.google.com/functions/docs/securing/managing-access-iam#allowing_unauthenticated_http_function_invocation) or [update your Firebase CLI](https://firebase.google.com/docs/cli.md.txt#setup_update_cli) before you deploy any new functions.

## Use a web framework

You can use web frameworks, like
[Express.js](https://expressjs.com/), in Cloud Functions to
serve your app's dynamic content and write complex web apps more easily.

> [!NOTE]
> Firebase Hosting also supports HTTPS requests to Cloud Run containers. Learn more about this serverless, highly scalable service in the [Hosting paired
> with Cloud Run documentation](https://firebase.google.com/docs/hosting/cloud-run).

The following section provides a walk-through example for using Express.js with
Firebase Hosting and Cloud Functions.

1. Install Express.js in your local project by running the following command
   from your `functions` directory:

   ```
   npm install express --save
   ```
2. Open your `/functions/index.js` file, then import and initialize Express.js:

   ```
   const functions = require('firebase-functions/v1');
   const express = require('express');
   const app = express();
   ```
3. Add the following two endpoints:

   1. Add the first endpoint to serve the index of our website at `/`.

      > [!NOTE]
      > **Note:** This walk-through example requires a couple of static files ([script.js and style.css](https://github.com/firebase/functions-samples/tree/Node-8/quickstarts/big-ben/public)).

          app.get('/', (req, res) => {
            const date = new Date();
            const hours = (date.getHours() % 12) + 1;  // London is UTC + 1hr;
            res.send(`
              <!doctype html>
              <head>
                <title>Time</title>
                <link rel="stylesheet" href="/style.css">
                <script src="/script.js"></script>
              </head>
              <body>
                <p>In London, the clock strikes:
                  <span id="bongs">${'BONG '.repeat(hours)}</span></p>
                <button onClick="refresh(this)">Refresh</button>
              </body>
            </html>`);
          });

   2. And another endpoint to return the `BONG` count as an API, in JSON
      format, under `/api`:

          app.get('/api', (req, res) => {
            const date = new Date();
            const hours = (date.getHours() % 12) + 1;  // London is UTC + 1hr;
            res.json({bongs: 'BONG '.repeat(hours)});
          });

4. Export the Express.js app as an HTTPS function:

   ```
   exports.app = functions.https.onRequest(app);
   ```
5. In your `firebase.json` file, direct all requests to the `app` function.
   This rewrite allows Express.js to serve the different subpath that we
   configured (in this example, `/` and `/api`).

   ```
   {
    "hosting": {
      // ...

      // Add the "rewrites" attribute within "hosting"
      "rewrites": [ {
        "source": "**",
        "function": "app"
      } ]
    }
   }
   ```

> [!NOTE]
> **Note:** The static files in the [`public` directory](https://firebase.google.com/docs/hosting/full-config.md.txt#specify-files-to-deply) take precedence over the rewrites, so any static files will be served alongside the Cloud Functions endpoints.

### Add middleware

Continuing our example, now that you're using Express.js, you can add
[Express.js middleware](https://expressjs.com/en/resources/middleware.html)
in the typical way. For example, you can enable
[CORS](https://expressjs.com/en/resources/middleware/cors.html)
requests on our endpoints.

1. Install the `cors` middleware by running the following command:

   ```
   npm install --save cors
   ```
2. Open your `/functions/index.js` file, then add `cors` to your Express.js app,
   like so:

   ```
   const cors = require('cors')({origin: true});
   app.use(cors);
   ```

Visit the [Cloud Functions documentation](https://firebase.google.com/docs/functions/http-events.md.txt)
to learn more about using Firebase with Express apps and middleware modules.

## Next steps

- [Set up caching](https://firebase.google.com/docs/hosting/manage-cache.md.txt) for your dynamic content on a
  global CDN.

- Interact with other Firebase services using the
  [Firebase Admin SDK](https://firebase.google.com/docs/functions/get-started.md.txt#import-the-required-modules-and-initialize-an-app).

- Review the [pricing](https://firebase.google.com/pricing.md.txt#cloud-functions) and the
  [quotas and limits](https://firebase.google.com/docs/functions/quotas.md.txt) for Cloud Functions.