With Firebase Hosting, you can configure customized hosting behavior for requests to your site.
What can you configure for Hosting?
Specify which files in your local project directory you want to deploy to Firebase Hosting. Learn how.
Serve a customized 404/Not Found page. Learn how.
Set up
redirectsfor pages that you've moved or deleted. Learn how.Set up
rewritesfor any of these purposes:Show the same content for multiple URLs. Learn how.
Serve a function or access a Cloud Run container from a Hosting URL. Learn how: function or container.
Create a custom domain Dynamic Link. Learn how.
Add
headersto pass along additional information about a request or a response, such as how browsers should handle the page and its content (authentication, caching, encoding, etc.). Learn how.Set up internationalization (i18n) rewrites to serve specific content based on a user's language preference and/or country. Learn how (different page).
Where do you define your Hosting configuration?
You define your Firebase Hosting configuration in your
firebase.json file. Firebase
automatically creates your firebase.json file at the root of your project
directory when you run the
firebase init command.
You can find a
full firebase.json configuration example
(covering only Firebase Hosting) at the bottom of this page. Note that a
firebase.json file can also contain
configurations for other Firebase services.
You can check the deployed firebase.json content using the
Hosting REST API.
Priority order of Hosting responses
The different Firebase Hosting configuration options described on this page can sometimes overlap. If there is a conflict, Hosting determines its response using the following priority order:
- Reserved namespaces that begin with a
/__/*path segment - Configured redirects
- Exact-match static content
- Configured rewrites
- Custom 404 page
- Default 404 page
If you're using i18n rewrites, the exact-match and 404 handling priority order are expanded in scope to accommodate your "i18n content".
Specify which files to deploy
The default attributes — public and ignore — included
in the default firebase.json file define which files in your project directory
should be deployed to your Firebase project.
The default hosting configuration in a firebase.json file looks like this:
"hosting": {
"public": "public", // the only required attribute for Hosting
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
]
}
public
Required
The public attribute specifies which directory to deploy to
Firebase Hosting. The default value is a directory named public, but you
can specify any directory's path, as long as it exists in your project
directory.
The following is the default specified name of the directory to deploy:
"hosting": {
"public": "public"
// ...
}
You can change the default value to the directory that you want to deploy:
"hosting": {
"public": "dist/app"
// ...
}
ignore
Optional
The ignore attribute specifies the files to ignore on deploy. It can take
globs the same way that
Git handles .gitignore.
The following are the default values for the files to ignore:
"hosting": {
// ...
"ignore": [
"firebase.json", // the Firebase configuration file (the file described on this page)
"**/.*", // files with a leading period should be hidden from the system
"**/node_modules/**" // contains dependencies used to create your site but not run it
]
}
Customize a 404/Not Found page
Optional
You can serve a custom 404 Not Found error when a user tries to access a page
that doesn't exist.
Create a new file in your project's public directory, name it
404.html, then add your custom 404 Not Found content to the file.
Firebase Hosting will display the content of this custom 404.html page if
a browser triggers a 404 Not Found error on your domain or subdomain.
Configure redirects
Optional
Use a URL redirect to prevent broken links if you've moved a page
or to shorten URLs. For example, you could redirect a browser from
example.com/team to example.com/about.html.
Specify URL redirects by creating a redirects attribute that contains an array
of objects (called "redirect rules"). In each rule, specify a URL pattern that,
if matched to the request URL path, triggers Hosting to respond with a redirect
to the specified destination URL.
Here's the basic structure for a redirects attribute. This example redirects
requests to /foo by making a new request to /bar.
"hosting": {
// ...
// Returns a permanent redirect to "/bar" for requests to "/foo" (but not "/foo/**")
"redirects": [ {
"source": "/foo",
"destination": "/bar",
"type": 301
} ]
}
"hosting": {
// ...
// Add the "redirects" attribute within "hosting"
"redirects": [ {
// Returns a permanent redirect to "/bar" for requests to "/foo" (but not "/foo/**")
"source": "/foo",
"destination": "/bar",
"type": 301
}, {
// Returns a permanent redirect to "/bar" for requests to both "/foo" and "/foo/**"
"source": "/foo{,/**}"
"destination": "/bar"
"type": 301
}, {
// Returns a temporary redirect for all requests to files or directories in the "firebase" directory
"source": "/firebase/**",
"destination": "https://firebase.google.com/",
"type": 302
}, {
// A regular expression-based redirect equivalent to the above behavior
"regex": "/firebase/.*",
"destination": "https://firebase.google.com/",
"type": 302
} ]
}
The redirects attribute contains an array of redirect rules, where each rule
must include the fields in the table below.
Firebase Hosting compares the source or regex value against all URL
paths at the start of every request (before the browser determines whether a
file or folder exists at that path). If a match is found, then the
Firebase Hosting origin server sends an HTTPS redirect response telling the
browser to make a new request at the destination URL.
| Field | Description | |
|---|---|---|
redirects |
||
source (recommended) or regex
|
A URL pattern that, if matched to the initial request URL, triggers Hosting to apply the redirect
|
|
destination |
A static URL where the browser should make a new request This URL can be a relative or an absolute path. |
|
type |
The HTTPS response code
|
|
Capture URL segments for redirects
Optional
Sometimes, you might need to capture specific segments of a redirect rule's URL
pattern (source or regex value), then re-use these segments in the
rule's destination path.
If you're using a source field (that is, specifying a glob for your URL
pattern), you can capture segments by including a : prefix to identify the
segment. If you also need to capture the remaining URL path after the segment,
include a * immediately after the segment. For example:
"hosting": { // ... "redirects": [ { "source": "/blog/:post*", // captures the entire URL segment beginning at "post" "destination": "https://blog.myapp.com/:post", // includes the entire URL segment identified and captured by the "source" value "type": 301 }, { "source": "/users/:id/profile", // captures only the URL segment "id", but nothing following "destination": "/users/:id/newProfile", // includes the URL segment identified and captured by the "source" value "type": 301 } ] }
If you're using a regex field (that is, specifying a RE2 regular expression
for your URL pattern), you can capture segments using either named or unnamed
RE2 capture groups. Named capture groups can be used in the destination field
with a : prefix, while unnamed capture groups can be referenced by their
numerical index in the regex value, indexed from 1. For example:
"hosting": { // ... "redirects": [ { "regex": "/blog/(?P<post>.+)", // if you're familiar with PCRE, be aware that RE2 requires named capture groups to begin with ?P "destination": "https://blog.myapp.com/:post", // includes the entire URL segment identified and captured by the `regex` value "type": 301 }, { "regex": "/users/(\d+)/profile", // uses the \d directive to only match numerical path segments "destination": "/users/:1/newProfile", // the first capture group to be seen in the `regex` value is named 1, and so on "type": 301 } ] }
Configure rewrites
Optional
Use a rewrite to show the same content for multiple URLs. Rewrites are
particularly useful with pattern matching, as you can accept any URL that
matches the pattern and let the client-side code decide what to display.
You can also use rewrites to support apps that use
HTML5 pushState
for navigation. When a browser attempts to open a URL path that matches the
specified source or regex URL pattern, the browser will be given the
contents of the file at the destination URL instead.
Specify URL rewrites by creating a rewrites attribute that contains an array
of objects (called "rewrite rules"). In each rule, specify a URL pattern that,
if matched to the request URL path, triggers Hosting to respond as if the
service were given the specified destination URL.
Here's the basic structure for a rewrites attribute. This example serves
index.html for requests to files or directories that don't exist.
"hosting": {
// ...
// Serves index.html for requests to files or directories that do not exist
"rewrites": [ {
"source": "**",
"destination": "/index.html"
} ]
}
"hosting": { // ... // Add the "rewrites" attribute within "hosting" "rewrites": [ { // Serves index.html for requests to files or directories that do not exist "source": "**", "destination": "/index.html" }, { // Serves index.html for requests to both "/foo" and "/foo/**" // Using "/foo/**" only matches paths like "/foo/xyz", but not "/foo" "source": "/foo{,/**}", "destination": "/index.html" }, { // A regular expression-based rewrite equivalent to the above behavior "regex": "/foo(/.*)?", "destination": "/index.html" }, { // Excludes specified pathways from rewrites "source": "!/@(js|css)/**", "destination": "/index.html" } ] }
The rewrites attribute contains an array of rewrite rules, where each rule
must include the fields in the table below.
Firebase Hosting only applies a rewrite rule if a file or directory does not
exist at a URL path that matches the specified source or regex URL pattern.
When a request triggers a rewrite rule, the browser returns the actual content
of the specified destination file instead of an HTTP redirect.
| Field | Description | |
|---|---|---|
rewrites |
||
source (recommended) or regex
|
A URL pattern that, if matched to the initial request URL, triggers Hosting to apply the rewrite
|
|
destination |
A local file that must exist This URL can be a relative or an absolute path. |
|
Direct requests to a function
You can use rewrites to serve a function from a Firebase Hosting URL. The
following example is an excerpt from
serving dynamic content using Cloud Functions.
For example, to direct all requests from the page /bigben on your
Hosting site to execute the bigben function:
"hosting": {
// ...
// Directs all requests from the page `/bigben` to execute the `bigben` function
"rewrites": [ {
"source": "/bigben",
"function": {
"functionId": "bigben",
"region": "us-central1" // optional (see note below)
"pinTag": true // optional (see note below)
}
} ]
}
If
regionis omitted from afunctionblock of thehosting.rewritesconfig, the Firebase CLI attempts to automatically detect the region from the function's source code which, if unspecified, defaults tous-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 requiresregionto be specified in thehosting.rewritesconfig.
The
pinTagfeature 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": trueto afunctionblock of thehosting.rewritesconfig, then the "pinned" function will be deployed along with your static Hosting resources and configuration, even when running. If you roll back a version of your site, the "pinned" function is also rolled back.firebase deploy --only hosting This feature relies on Cloud Run 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.
After adding this rewrite rule and deploying to Firebase (using
firebase deploy), your function is reachable via the following URLs:
Your Firebase subdomains:
PROJECT_ID.web.app/bigbenandPROJECT_ID.firebaseapp.com/bigbenAny connected custom domains:
CUSTOM_DOMAIN/bigben
When Firebase Hosting forwards traffic to a function, the function receives the
full original request path and query string. For example, a request to
/bigben/hello/world?foo=bar on your Hosting site is passed to the function
with the complete path and query intact. Make sure your function handler is
written to handle the entire absolute URL, not just the base path defined in
the rewrite.
When redirecting requests to functions with Hosting, supported HTTP request
methods are GET, POST, HEAD, PUT, DELETE, PATCH, and OPTIONS.
Other methods like REPORT or PROFIND are not supported.
Direct requests to a Cloud Run container
You can use rewrites to access a Cloud Run container from a
Firebase Hosting URL. The following example is an excerpt from
serving dynamic content using Cloud Run.
For example, to direct all requests from the page /helloworld on your
Hosting site to trigger the startup and running of a helloworld container
instance:
"hosting": {
// ...
// Directs all requests from the page `/helloworld` to trigger and run a `helloworld` container
"rewrites": [ {
"source": "/helloworld",
"run": {
"serviceId": "helloworld", // "service name" (from when you deployed the container image)
"region": "us-central1" // optional (if omitted, default is us-central1)
}
} ]
}
With this feature, you can ensure that the revision of your Cloud Run service 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 Cloud Run on Hosting preview channels.
If you add
"pinTag": trueto arunblock of thehosting.rewritesconfig, your static Hosting resources and configuration will be pinned to the most recent revision of the Cloud Run service, at the time of deploy. If you roll back a version of your site, the revision of the "pinned" Cloud Run service is also rolled back.This feature relies on Cloud Run 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.
After adding this rewrite rule and deploying to Firebase (using
firebase deploy), your container image is reachable via the following URLs:
Your Firebase subdomains:
PROJECT_ID.web.app/helloworldandPROJECT_ID.firebaseapp.com/helloworldAny connected custom domains:
CUSTOM_DOMAIN/helloworld
When redirecting requests to Cloud Run containers with Hosting,
supported HTTP request methods are GET, POST, HEAD, PUT, DELETE,
PATCH, and OPTIONS. Other methods like REPORT or PROFIND are not
supported.
For the best performance, colocate your Cloud Run service with Hosting using the following regions:
us-west1us-central1us-east1europe-west1asia-east1
Rewrites to Cloud Run from Hosting are supported in the following regions:
asia-east1asia-east2asia-northeast1asia-northeast2asia-northeast3asia-south1asia-south2asia-southeast1asia-southeast2australia-southeast1australia-southeast2europe-central2europe-north1europe-southwest1europe-west1europe-west12europe-west2europe-west3europe-west4europe-west6europe-west8europe-west9me-central1me-west1northamerica-northeast1northamerica-northeast2southamerica-east1southamerica-west1us-central1us-east1us-east4us-east5us-south1us-west1us-west2us-west3us-west4us-west1us-central1us-east1europe-west1asia-east1
Create custom domain Dynamic Links
You can use rewrites to create custom domain Dynamic Links. Visit the Dynamic Links
documentation for detailed information about
setting up a custom domain for Dynamic Links.
Use your custom domain only for Dynamic Links
"hosting": { // ... "appAssociation": "AUTO", // required for Dynamic Links (default is AUTO if not specified) // Add the "rewrites" attribute within "hosting" "rewrites": [ { "source": "/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/" "dynamicLinks": true } ] }Specify custom domain path prefixes to use for Dynamic Links
"hosting": { // ... "appAssociation": "AUTO", // required for Dynamic Links (default is AUTO if not specified) // Add the "rewrites" attribute within "hosting" "rewrites": [ { "source": "/promos/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/promos/" "dynamicLinks": true }, { "source": "/links/share/**", // the Dynamic Links start with "https://CUSTOM_DOMAIN/links/share/" "dynamicLinks": true } ] }
Configuring Dynamic Links in your firebase.json file requires the following:
| Field | Description | |
|---|---|---|
appAssociation |
Must be set to
|
|
rewrites |
||
source |
A path that you want to use for Dynamic Links Unlike rules that rewrite paths to URLs, rewrite rules for Dynamic Links can't contain regular expressions. |
|
dynamicLinks |
Must be set to true
|
|
Configure headers
Optional
Headers allow the client and the server to pass additional information along
with a request or a response. Some sets of headers can affect how the browser
handles the page and its content, including access control, authentication,
caching, and encoding.
Specify custom, file-specific response headers by creating a headers attribute
that contains an array of header objects. In each object, specify a URL pattern
that, if matched to the request URL path, triggers Hosting to apply the
specified custom response headers.
Here's the basic structure for a headers attribute. This example applies a
CORS header for all font files.
"hosting": {
// ...
// Applies a CORS header for all font files
"headers": [ {
"source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
"headers": [ {
"key": "Access-Control-Allow-Origin",
"value": "*"
} ]
} ]
}
"hosting": { // ... // Add the "headers" attribute within "hosting" "headers": [ { // Applies a CORS header for all font files "source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)", "headers": [ { "key": "Access-Control-Allow-Origin", "value": "*" } ] }, { // Overrides the default 1 hour browser cache with a 2 hour cache for all image files "source": "**/*.@(jpg|jpeg|gif|png)", "headers": [ { "key": "Cache-Control", "value": "max-age=7200" } ] }, { // A regular expression-based rewrite equivalent to the above behavior "regex": ".+/\w+\.(jpg|jpeg|gif|png)$", "headers": [ { "key": "Cache-Control", "value": "max-age=7200" } ] }, { // Sets the cache header for 404 pages to cache for 5 minutes "source": "404.html", "headers": [ { "key": "Cache-Control", "value": "max-age=300" } ] } ] }
The headers attribute contains an array of definitions, where each definition
must include the fields in the table below.
| Field | Description | ||
|---|---|---|---|
headers |
|||
source (recommended) or regex
|
A URL pattern that, if matched to the initial request URL, triggers Hosting to apply the custom header
To create a header to match against your
custom 404 page, use |
||
array of (sub-)headers |
The custom headers that Hosting applies to the request path Each sub-header must include a
|
||
key |
The name of the header, for example Cache-Control |
||
value |
The value for the header, for example max-age=7200 |
||
You can learn more about Cache-Control in the
Hosting section that describes serving dynamic content and hosting
microservices. You can also learn more about
CORS headers.
Control .html extensions
Optional
The cleanUrls attribute allows you to control whether or not URLs
should include the .html extension.
When true, Hosting automatically drops the .html extension from uploaded
file URLs. If an .html extension is added in the request, Hosting performs
a 301 redirect to the same path but eliminates the .html extension.
Here's how to control the inclusion of .html in URLs by including a
cleanUrls attribute:
"hosting": {
// ...
// Drops `.html` from uploaded URLs
"cleanUrls": true
}
Control trailing slashes
Optional
The trailingSlash attribute allows you to control whether or not static
content URLs should include trailing slashes.
- When
true, Hosting redirects URLs to add a trailing slash. - When
false, Hosting redirects URLs to remove a trailing slash. - When unspecified, Hosting only uses trailing slashes for directory index
files (for example,
about/index.html).
Here's how to control trailing slashes by adding a trailingSlash attribute:
"hosting": {
// ...
// Removes trailing slashes from URLs
"trailingSlash": false
}
The trailingSlash attribute does not affect rewrites to dynamic content
served by Cloud Functions or Cloud Run.
Glob pattern matching
Firebase Hosting configuration options make extensive use of the
glob pattern matching
notation with extglob, similar to how Git handles
gitignore rules and
Bower handles ignore rules.
This wiki page is a more detailed reference,
but the following are explanations of examples used on this page:
firebase.json— Only matches thefirebase.jsonfile in the root of thepublicdirectory**— Matches any file or folder in an arbitrary sub-directory*— Only matches files and folders in the root of thepublicdirectory**/.*— Matches any file beginning with.(usually hidden files, like in the.gitfolder) in an arbitrary sub-directory**/node_modules/**— Matches any file or folder in an arbitrary sub-directory of anode_modulesfolder, which can itself be in an arbitrary sub-directory of thepublicdirectory**/*.@(jpg|jpeg|gif|png)— Matches any file in an arbitrary sub-directory that ends with exactly one of the following:.jpg,.jpeg,.gif, or.png
Full Hosting configuration example
The following is a full firebase.json configuration example for
Firebase Hosting. Note that a firebase.json file can also contain
configurations for other Firebase services.
{
"hosting": {
"public": "dist/app", // "public" is the only required attribute for Hosting
"ignore": [
"firebase.json",
"**/.*",
"**/node_modules/**"
],
"redirects": [ {
"source": "/foo",
"destination": "/bar",
"type": 301
}, {
"source": "/firebase/**",
"destination": "https://www.firebase.com",
"type": 302
} ],
"rewrites": [ {
// Shows the same content for multiple URLs
"source": "/app/**",
"destination": "/app/index.html"
}, {
// Configures a custom domain for Dynamic Links
"source": "/promos/**",
"dynamicLinks": true
}, {
// Directs a request to Cloud Functions
"source": "/bigben",
"function": "bigben"
}, {
// Directs a request to a Cloud Run containerized app
"source": "/helloworld",
"run": {
"serviceId": "helloworld",
"region": "us-central1"
}
} ],
"headers": [ {
"source": "**/*.@(eot|otf|ttf|ttc|woff|font.css)",
"headers": [ {
"key": "Access-Control-Allow-Origin",
"value": "*"
} ]
}, {
"source": "**/*.@(jpg|jpeg|gif|png)",
"headers": [ {
"key": "Cache-Control",
"value": "max-age=7200"
} ]
}, {
"source": "404.html",
"headers": [ {
"key": "Cache-Control",
"value": "max-age=300"
} ]
} ],
"cleanUrls": true,
"trailingSlash": false,
// Required to configure custom domains for Dynamic Links
"appAssociation": "AUTO",
}
}