The gcp:firebase/hostingRelease:HostingRelease resource, part of the Pulumi GCP provider, controls which Firebase Hosting version is publicly accessible, either on the live site or in preview channels. This guide focuses on three capabilities: publishing versions to live sites, deploying to preview channels, and disabling site content.
Releases reference HostingSite and HostingVersion resources that define the site identity and content configuration. The examples are intentionally small. Combine them with your own version content and channel strategy.
Deploy a version to the live site
Most deployments publish content to the default “live” channel, making it immediately visible at the main site URL.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.firebase.HostingSite("default", {
project: "my-project-name",
siteId: "site-id",
});
const defaultHostingVersion = new gcp.firebase.HostingVersion("default", {
siteId: _default.siteId,
config: {
redirects: [{
glob: "/google/**",
statusCode: 302,
location: "https://www.google.com",
}],
},
});
const defaultHostingRelease = new gcp.firebase.HostingRelease("default", {
siteId: _default.siteId,
versionName: defaultHostingVersion.name,
message: "Test release",
});
import pulumi
import pulumi_gcp as gcp
default = gcp.firebase.HostingSite("default",
project="my-project-name",
site_id="site-id")
default_hosting_version = gcp.firebase.HostingVersion("default",
site_id=default.site_id,
config={
"redirects": [{
"glob": "/google/**",
"status_code": 302,
"location": "https://www.google.com",
}],
})
default_hosting_release = gcp.firebase.HostingRelease("default",
site_id=default.site_id,
version_name=default_hosting_version.name,
message="Test release")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/firebase"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := firebase.NewHostingSite(ctx, "default", &firebase.HostingSiteArgs{
Project: pulumi.String("my-project-name"),
SiteId: pulumi.String("site-id"),
})
if err != nil {
return err
}
defaultHostingVersion, err := firebase.NewHostingVersion(ctx, "default", &firebase.HostingVersionArgs{
SiteId: _default.SiteId,
Config: &firebase.HostingVersionConfigArgs{
Redirects: firebase.HostingVersionConfigRedirectArray{
&firebase.HostingVersionConfigRedirectArgs{
Glob: pulumi.String("/google/**"),
StatusCode: pulumi.Int(302),
Location: pulumi.String("https://www.google.com"),
},
},
},
})
if err != nil {
return err
}
_, err = firebase.NewHostingRelease(ctx, "default", &firebase.HostingReleaseArgs{
SiteId: _default.SiteId,
VersionName: defaultHostingVersion.Name,
Message: pulumi.String("Test release"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.Firebase.HostingSite("default", new()
{
Project = "my-project-name",
SiteId = "site-id",
});
var defaultHostingVersion = new Gcp.Firebase.HostingVersion("default", new()
{
SiteId = @default.SiteId,
Config = new Gcp.Firebase.Inputs.HostingVersionConfigArgs
{
Redirects = new[]
{
new Gcp.Firebase.Inputs.HostingVersionConfigRedirectArgs
{
Glob = "/google/**",
StatusCode = 302,
Location = "https://www.google.com",
},
},
},
});
var defaultHostingRelease = new Gcp.Firebase.HostingRelease("default", new()
{
SiteId = @default.SiteId,
VersionName = defaultHostingVersion.Name,
Message = "Test release",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.firebase.HostingSite;
import com.pulumi.gcp.firebase.HostingSiteArgs;
import com.pulumi.gcp.firebase.HostingVersion;
import com.pulumi.gcp.firebase.HostingVersionArgs;
import com.pulumi.gcp.firebase.inputs.HostingVersionConfigArgs;
import com.pulumi.gcp.firebase.HostingRelease;
import com.pulumi.gcp.firebase.HostingReleaseArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HostingSite("default", HostingSiteArgs.builder()
.project("my-project-name")
.siteId("site-id")
.build());
var defaultHostingVersion = new HostingVersion("defaultHostingVersion", HostingVersionArgs.builder()
.siteId(default_.siteId())
.config(HostingVersionConfigArgs.builder()
.redirects(HostingVersionConfigRedirectArgs.builder()
.glob("/google/**")
.statusCode(302)
.location("https://www.google.com")
.build())
.build())
.build());
var defaultHostingRelease = new HostingRelease("defaultHostingRelease", HostingReleaseArgs.builder()
.siteId(default_.siteId())
.versionName(defaultHostingVersion.name())
.message("Test release")
.build());
}
}
resources:
default:
type: gcp:firebase:HostingSite
properties:
project: my-project-name
siteId: site-id
defaultHostingVersion:
type: gcp:firebase:HostingVersion
name: default
properties:
siteId: ${default.siteId}
config:
redirects:
- glob: /google/**
statusCode: 302
location: https://www.google.com
defaultHostingRelease:
type: gcp:firebase:HostingRelease
name: default
properties:
siteId: ${default.siteId}
versionName: ${defaultHostingVersion.name}
message: Test release
When you create a release with a versionName, Firebase Hosting makes that version’s content publicly accessible. The siteId identifies which site receives the deployment, and the message property records deployment context for tracking. Without a channelId, the release targets the default “live” channel.
Deploy a version to a preview channel
Teams use preview channels to test changes at separate URLs before promoting to production.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.firebase.HostingSite("default", {
project: "my-project-name",
siteId: "site-with-channel",
});
const defaultHostingVersion = new gcp.firebase.HostingVersion("default", {
siteId: _default.siteId,
config: {
redirects: [{
glob: "/google/**",
statusCode: 302,
location: "https://www.google.com",
}],
},
});
const defaultHostingChannel = new gcp.firebase.HostingChannel("default", {
siteId: _default.siteId,
channelId: "channel-id",
});
const defaultHostingRelease = new gcp.firebase.HostingRelease("default", {
siteId: _default.siteId,
channelId: defaultHostingChannel.channelId,
versionName: defaultHostingVersion.name,
message: "Test release in channel",
});
import pulumi
import pulumi_gcp as gcp
default = gcp.firebase.HostingSite("default",
project="my-project-name",
site_id="site-with-channel")
default_hosting_version = gcp.firebase.HostingVersion("default",
site_id=default.site_id,
config={
"redirects": [{
"glob": "/google/**",
"status_code": 302,
"location": "https://www.google.com",
}],
})
default_hosting_channel = gcp.firebase.HostingChannel("default",
site_id=default.site_id,
channel_id="channel-id")
default_hosting_release = gcp.firebase.HostingRelease("default",
site_id=default.site_id,
channel_id=default_hosting_channel.channel_id,
version_name=default_hosting_version.name,
message="Test release in channel")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/firebase"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := firebase.NewHostingSite(ctx, "default", &firebase.HostingSiteArgs{
Project: pulumi.String("my-project-name"),
SiteId: pulumi.String("site-with-channel"),
})
if err != nil {
return err
}
defaultHostingVersion, err := firebase.NewHostingVersion(ctx, "default", &firebase.HostingVersionArgs{
SiteId: _default.SiteId,
Config: &firebase.HostingVersionConfigArgs{
Redirects: firebase.HostingVersionConfigRedirectArray{
&firebase.HostingVersionConfigRedirectArgs{
Glob: pulumi.String("/google/**"),
StatusCode: pulumi.Int(302),
Location: pulumi.String("https://www.google.com"),
},
},
},
})
if err != nil {
return err
}
defaultHostingChannel, err := firebase.NewHostingChannel(ctx, "default", &firebase.HostingChannelArgs{
SiteId: _default.SiteId,
ChannelId: pulumi.String("channel-id"),
})
if err != nil {
return err
}
_, err = firebase.NewHostingRelease(ctx, "default", &firebase.HostingReleaseArgs{
SiteId: _default.SiteId,
ChannelId: defaultHostingChannel.ChannelId,
VersionName: defaultHostingVersion.Name,
Message: pulumi.String("Test release in channel"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.Firebase.HostingSite("default", new()
{
Project = "my-project-name",
SiteId = "site-with-channel",
});
var defaultHostingVersion = new Gcp.Firebase.HostingVersion("default", new()
{
SiteId = @default.SiteId,
Config = new Gcp.Firebase.Inputs.HostingVersionConfigArgs
{
Redirects = new[]
{
new Gcp.Firebase.Inputs.HostingVersionConfigRedirectArgs
{
Glob = "/google/**",
StatusCode = 302,
Location = "https://www.google.com",
},
},
},
});
var defaultHostingChannel = new Gcp.Firebase.HostingChannel("default", new()
{
SiteId = @default.SiteId,
ChannelId = "channel-id",
});
var defaultHostingRelease = new Gcp.Firebase.HostingRelease("default", new()
{
SiteId = @default.SiteId,
ChannelId = defaultHostingChannel.ChannelId,
VersionName = defaultHostingVersion.Name,
Message = "Test release in channel",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.firebase.HostingSite;
import com.pulumi.gcp.firebase.HostingSiteArgs;
import com.pulumi.gcp.firebase.HostingVersion;
import com.pulumi.gcp.firebase.HostingVersionArgs;
import com.pulumi.gcp.firebase.inputs.HostingVersionConfigArgs;
import com.pulumi.gcp.firebase.HostingChannel;
import com.pulumi.gcp.firebase.HostingChannelArgs;
import com.pulumi.gcp.firebase.HostingRelease;
import com.pulumi.gcp.firebase.HostingReleaseArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HostingSite("default", HostingSiteArgs.builder()
.project("my-project-name")
.siteId("site-with-channel")
.build());
var defaultHostingVersion = new HostingVersion("defaultHostingVersion", HostingVersionArgs.builder()
.siteId(default_.siteId())
.config(HostingVersionConfigArgs.builder()
.redirects(HostingVersionConfigRedirectArgs.builder()
.glob("/google/**")
.statusCode(302)
.location("https://www.google.com")
.build())
.build())
.build());
var defaultHostingChannel = new HostingChannel("defaultHostingChannel", HostingChannelArgs.builder()
.siteId(default_.siteId())
.channelId("channel-id")
.build());
var defaultHostingRelease = new HostingRelease("defaultHostingRelease", HostingReleaseArgs.builder()
.siteId(default_.siteId())
.channelId(defaultHostingChannel.channelId())
.versionName(defaultHostingVersion.name())
.message("Test release in channel")
.build());
}
}
resources:
default:
type: gcp:firebase:HostingSite
properties:
project: my-project-name
siteId: site-with-channel
defaultHostingVersion:
type: gcp:firebase:HostingVersion
name: default
properties:
siteId: ${default.siteId}
config:
redirects:
- glob: /google/**
statusCode: 302
location: https://www.google.com
defaultHostingChannel:
type: gcp:firebase:HostingChannel
name: default
properties:
siteId: ${default.siteId}
channelId: channel-id
defaultHostingRelease:
type: gcp:firebase:HostingRelease
name: default
properties:
siteId: ${default.siteId}
channelId: ${defaultHostingChannel.channelId}
versionName: ${defaultHostingVersion.name}
message: Test release in channel
The channelId property routes the release to a specific preview channel rather than the live site. This creates a unique URL (typically https://SITE_ID--CHANNEL_ID.web.app) where stakeholders can review content. The version remains isolated from live traffic until you create a separate release targeting the live channel.
Take a site offline without deleting it
During maintenance or decommissioning, you can disable hosting without removing the site resource.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const _default = new gcp.firebase.HostingSite("default", {
project: "my-project-name",
siteId: "site-id",
});
const defaultHostingRelease = new gcp.firebase.HostingRelease("default", {
siteId: _default.siteId,
type: "SITE_DISABLE",
message: "Take down site",
});
import pulumi
import pulumi_gcp as gcp
default = gcp.firebase.HostingSite("default",
project="my-project-name",
site_id="site-id")
default_hosting_release = gcp.firebase.HostingRelease("default",
site_id=default.site_id,
type="SITE_DISABLE",
message="Take down site")
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/firebase"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
_default, err := firebase.NewHostingSite(ctx, "default", &firebase.HostingSiteArgs{
Project: pulumi.String("my-project-name"),
SiteId: pulumi.String("site-id"),
})
if err != nil {
return err
}
_, err = firebase.NewHostingRelease(ctx, "default", &firebase.HostingReleaseArgs{
SiteId: _default.SiteId,
Type: pulumi.String("SITE_DISABLE"),
Message: pulumi.String("Take down site"),
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var @default = new Gcp.Firebase.HostingSite("default", new()
{
Project = "my-project-name",
SiteId = "site-id",
});
var defaultHostingRelease = new Gcp.Firebase.HostingRelease("default", new()
{
SiteId = @default.SiteId,
Type = "SITE_DISABLE",
Message = "Take down site",
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.firebase.HostingSite;
import com.pulumi.gcp.firebase.HostingSiteArgs;
import com.pulumi.gcp.firebase.HostingRelease;
import com.pulumi.gcp.firebase.HostingReleaseArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var default_ = new HostingSite("default", HostingSiteArgs.builder()
.project("my-project-name")
.siteId("site-id")
.build());
var defaultHostingRelease = new HostingRelease("defaultHostingRelease", HostingReleaseArgs.builder()
.siteId(default_.siteId())
.type("SITE_DISABLE")
.message("Take down site")
.build());
}
}
resources:
default:
type: gcp:firebase:HostingSite
properties:
project: my-project-name
siteId: site-id
defaultHostingRelease:
type: gcp:firebase:HostingRelease
name: default
properties:
siteId: ${default.siteId}
type: SITE_DISABLE
message: Take down site
Setting type to SITE_DISABLE stops Firebase Hosting from serving any content, as if the site never existed. This configuration omits versionName because disabling doesn’t reference specific content. The site resource remains intact, allowing you to re-enable hosting later by creating a new release with a versionName.
Beyond these examples
These snippets focus on specific release-level features: live site deployment, preview channel releases, and site disabling. They’re intentionally minimal rather than full hosting configurations.
The examples rely on pre-existing infrastructure such as Firebase projects with Hosting enabled and HostingSite resources. They focus on controlling version visibility rather than defining version content.
To keep things focused, common hosting patterns are omitted, including:
- Version content configuration (redirects, rewrites, headers)
- Rollback to previous versions (ROLLBACK type)
- Channel expiration and retention policies
- Custom domain configuration
These omissions are intentional: the goal is to illustrate how each release feature is wired, not provide drop-in hosting modules. See the Firebase Hosting Release resource reference for all available configuration options.
Let's deploy GCP Firebase Hosting Releases
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Release Types & Deployment
versionName, the type is automatically determined as DEPLOY or ROLLBACK. You only need to explicitly set type when using SITE_DISABLE.type: "SITE_DISABLE" and omit the versionName property. This prevents the site from serving content.versionName parameter must be empty when type is SITE_DISABLE. Disabling a site doesn’t deploy any version.Channels & Targeting
channelId, releases deploy to the default “live” channel (your main site). Providing a channelId deploys to a specific preview channel.channelId property to your target channel’s ID. Create the channel first using gcp.firebase.HostingChannel.Configuration & Constraints
siteId, type, channelId, versionName, message) are immutable and cannot be changed after creation.versionName must belong to the same site as your siteId. Ensure both reference the same Firebase Hosting site.message property can be up to 512 characters.Using a different cloud?
Explore integration guides for other cloud providers: