With Firebase Hosting, you can configure customized hosting behavior for
requests to your site.
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
} ]
}
View a more detailed example for a
redirects
attribute
"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
- Use a type of
301
for 'Moved Permanently'
- Use a type of
302
for 'Found' (Temporary Redirect)
|
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.
Capture URL segments when using globs
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
} ]
}
Capture URL segments when using RE2 regular expressions
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"
} ]
}
View a more detailed example for a
rewrites
attribute
"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)
}
} ]
}
How
region
works within the
function
block
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.
How
pinTag
works within the
function
block
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.
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:
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)
}
} ]
}
How
pinTag
works within the
run
block
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
"pingTag": true
to a
run
block of the
hosting.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:
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
AUTO
- If you don't include this attribute in your configuration, the
default for
appAssociation
is
AUTO
.
- By setting this attribute to
AUTO
, Hosting can
dynamically generate
assetlinks.json
and
apple-app-site-association
files when
they're requested.
|
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
|
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": "*"
} ]
} ]
}
View a more detailed example for a
headers
attribute
"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
404.html
as your
source
or
regex
value.
|
|
array of (sub-)
headers
|
The custom headers that Hosting applies to the request path
Each sub-header must include a
key
and
value
pair
(see next two rows).
|
|
|
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 the
firebase.json
file in the root
of the
public
directory
**
? Matches any file or folder in an arbitrary sub-directory
*
? Only matches files and folders in the root of the
public
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 a
node_modules
folder, which can itself be in an arbitrary
sub-directory of the
public
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",
}
}