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
redirects
for pages that you've moved or deleted. Learn how.Set up
rewrites
for 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
headers
to 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
region
is omitted from afunction
block of thehosting.rewrites
config, 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 requiresregion
to be specified in thehosting.rewrites
config.
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 afunction
block of thehosting.rewrites
config, 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/bigben
andPROJECT_ID.firebaseapp.com/bigben
Any connected custom domains:
CUSTOM_DOMAIN/bigben
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": true
to arun
block of thehosting.rewrites
config, 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/helloworld
andPROJECT_ID.firebaseapp.com/helloworld
Any 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-west1
us-central1
us-east1
europe-west1
asia-east1
Rewrites to Cloud Run from Hosting are supported in the following regions:
asia-east1
asia-east2
asia-northeast1
asia-northeast2
asia-northeast3
asia-south1
asia-south2
asia-southeast1
asia-southeast2
australia-southeast1
australia-southeast2
europe-central2
europe-north1
europe-southwest1
europe-west1
europe-west12
europe-west2
europe-west3
europe-west4
europe-west6
europe-west8
europe-west9
me-central1
me-west1
northamerica-northeast1
northamerica-northeast2
southamerica-east1
southamerica-west1
us-central1
us-east1
us-east4
us-east5
us-south1
us-west1
us-west2
us-west3
us-west4
us-west1
us-central1
us-east1
europe-west1
asia-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.json
file in the root of thepublic
directory**
— Matches any file or folder in an arbitrary sub-directory*
— Only matches files and folders in the root of thepublic
directory**/.*
— Matches any file beginning with.
(usually hidden files, like in the.git
folder) in an arbitrary sub-directory**/node_modules/**
— Matches any file or folder in an arbitrary sub-directory of anode_modules
folder, which can itself be in an arbitrary sub-directory of thepublic
directory**/*.@(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",
}
}