Serve Dynamic Content with Cloud Functions

Firebase Hosting allows you to use Cloud Functions to perform server-side processing. This means that you can support dynamic generation of content for your Firebase Hosting site. Here are some examples of what this allows you to do:

  • Serve dynamic content. Instead of only serving static content, you can perform server-side logic through a function to return a dynamically generated response. For example, you can have a URL like /blog/<id-for-blog-post>. This URL pattern can be pointed to a function that dynamically uses the URL blog post ID parameter to retrieve content dynamically from your Firebase Realtime Database.
  • Prerender your single-page apps to improve SEO. This allows you to create dynamic meta tags for sharing across various social networks.
  • Keep your web app lightweight. You can create an API through Cloud Functions for your Firebase Hosting site to asynchronously retrieve content. This allows you to reduce initial load times for your web app by keeping the client code lightweight and loading content asynchronously through a function.

Note that Firebase Hosting is subject to a 60‑second request timeout. For dynamic content that might take longer than 60 seconds to generate, consider using the App Engine flexible environment.

Connect Cloud Functions to Firebase Hosting

To connect a function to Firebase Hosting, you'll need to set up Cloud Functions, write your function, create rewrite rules, then deploy your changes. To improve the performance of your dynamic content, you can optionally tune your cache settings.

Set up Cloud Functions for Firebase Hosting

If you've already set up Cloud Functions for Firebase, you can skip this step and proceed to create an HTTP function.

To set up Cloud Functions for your project, you'll need the latest version of the Firebase CLI, which requires Node.js v6.3.1 or greater. You can install Node.js by following the instructions on https://nodejs.org/. Installing Node.js will also install npm.

To check which version of Node.js that you have installed, run the following command in your terminal:

node --version

To install the latest version of the Firebase CLI, run the following command in your terminal:

npm install -g firebase-tools

To connect your local machine to your Firebase account and obtain access to your Firebase projects, run the following command:

firebase login

Next, you'll need to initialize Cloud Functions.

If you've not yet initialized your Firebase project with Hosting, run the following command within your project directory. When prompted, choose to initialize Hosting and Cloud Functions.

firebase init

However, if you have an existing Firebase project with Hosting, run the following command within your project directory to only initialize Cloud Functions.

firebase init functions

Create an HTTP function to your Hosting site

Open /functions/index.js in your favorite editor, then replace its contents with the following code. This code creates an HTTP function named bigben.

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

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>`);
});

Direct hosting requests to your function

With rewrite rules, you can direct requests that match specific patterns to a single destination. For example, to direct all requests from the page /bigben on your Hosting site to execute the bigben function, open firebase.json, then add the following rewrite configuration under the hosting section.

{
  "hosting": {
    "public": "public",

    // Add the following rewrites section *within* "hosting"
    "rewrites": [ {
      "source": "/bigben", "function": "bigben"
    } ]
  }
}

Note that Firebase Hosting is subject to a 60‑second request timeout. So even if you configure your HTTP function with a longer request timeout, you'll still receive an HTTP status code 504 (request timeout) if your function requires more than 60 seconds to run. To support this kind of dynamic content, consider using the App Engine flexible environment.

Visit the Hosting configuration page for more details about rewrite rules. You can also learn about the priority order of responses for various Hosting configurations.

Run dynamic content locally

You can serve and run your HTTP functions locally using the Firebase CLI. This allows you to view and test your Firebase project before deploying to production.

To use this feature, make sure both firebase-tools and firebase-functions SDK are the latest versions available. To update both, run the following two commands in the functions/ directory of your project:

npm install --save firebase-functions@latest
npm install -g firebase-tools

To serve your Firebase project locally, run the following command from your project directory. This command will emulate hosting and functions on locally hosted URLs.

firebase serve
When you're using Cloud Functions to generate dynamic content for Firebase Hosting, firebase serve, by default, uses your local HTTP functions as proxies for hosting. For more configuration options for Firebase Hosting and Cloud Functions, see the Firebase CLI Reference.

If you're using custom functions configuration variables, run the following command in the functions directory of your project before running firebase serve.

firebase functions:config:get > .runtimeconfig.json

However, if you're using Windows PowerShell, replace the above command with:

firebase functions:config:get | ac .runtimeconfig.json

Deploy

After creating a function and setting your rewrite rules, deploy your Firebase project by running the following command in your terminal:

firebase deploy

After deployment, you'll notice that your function is normally accessible through a URL, for example:

https://us-central1-your-firebase-project-id.cloudfunctions.net/bigben

All traffic on your Firebase Hosting site that matches the path specified in the rewrite rules will be proxied to the appropriate function.

Try out the sample

After everything is deployed, you can go to /bigben on your Firebase Hosting site to see it in action.

https://your-firebase-project-id.firebaseapp.com/bigben

Using cookies

When using Firebase Hosting together with Cloud Functions, cookies are generally stripped from incoming requests. This is necessary to allow for efficient CDN cache behavior. Only the specially-named __session cookie is permitted to pass through to the function execution.

When present, the __session cookie is automatically made a part of the cache key, meaning that it is impossible for two users with different cookies to receive the other's cached response. You should only use the __session cookie if your function serves different content depending on user authorization.

Manage cache behavior

Firebase Hosting uses a powerful global CDN to make your site as fast as possible. Static content on Firebase Hosting is cached until you deploy a new version of the content. Because functions generate content dynamically, requests that are handled by a function do not cache in the CDN by default. You can configure caching behavior yourself to speed up your app and reduce function execution costs.

Set Cache-Control

The main tool that you'll use to manage cache is the Cache-Control header. By setting it, you can communicate both to the browser and the CDN how long your content should be cached. In your function, you set Cache-Control like so:

res.set('Cache-Control', 'public, max-age=300, s-maxage=600');

The above header does three things:

  • Marks the cache as public. This means that this content is okay to be cached by intermediate servers (in our case, the CDN). By default, though, Cache-Control is set to private which means that only the user's browser is allowed to cache it.
  • Tells the browser for how many seconds it can cache the content with max-age. In the example above, we're telling the browser to cache for five minutes.
  • Tells the CDN for how many seconds it can cache the content with s-maxage. In the example above, we're telling the CDN to cache for ten minutes.

For max-age, set its value to the largest amount of time with which you're comfortable having users receive stale content. If a page changes every few seconds, max-age should be a small number. Other types of content, however, can safely be cached for hours, days, or even months.

You can learn more about the Cache-Control header on the Mozilla Developer Network.

When is cached content served?

If you've set a public Cache-Control header, your content is cached in the CDN based on:

  • The hostname
  • The path
  • The query string
  • The content of the headers specified in Vary

The Vary header is how to signal which parts of the request are important in determining your response. Most of the time, you don't need to worry about this. Firebase Hosting automatically ensures that an appropriate Vary header is set on your response for common situations. This includes making sure that any session cookie or authorization header that you're using is made part of the cache key, which prevents accidental leaks of content.

In some advanced use cases, you might have other headers that you need to affect the cache. When that's the case, you can simply set the Vary header on your response:

res.set('Vary', 'Accept-Encoding, X-My-Custom-Header');

With these settings, two otherwise identical requests with different X-My-Custom-Header headers are cached separately.

Send feedback about...

Need help? Visit our support page.