Use feature flags Standalone
Learn how to use App Lifecycle Manager feature flags as a standalone service to manage feature availability in your applications, even if those applications are not deployed or managed by App Lifecycle Manager.
Introduction
This quickstart shows you how to use the robust feature flagging and controlled rollout capabilities of App Lifecycle Manager without needing to use App Lifecycle Manager for infrastructure provisioning (like deploying VMs or Cloud Run services using Terraform blueprints). This approach is ideal if you manage your application infrastructure independently, but want to use App Lifecycle Manager for safe feature flag management.
In this standalone approach, you will:
- Model your system with lightweight App Lifecycle Manager resources: Create App Lifecycle Manager
Unitsto represent components of your existing infrastructure (e.g., a specific microservice deployment, a tenant environment, a single binary instance). These Units act solely as targets for flag configurations and do not involve deploying infrastructure using App Lifecycle Manager blueprints. - Define and Distribute Flags: Use the App Lifecycle Manager API or Google Cloud console to create feature flags. Manage their lifecycle using App Lifecycle Manager
Rolloutsto ensure safe, gradual propagation of configuration changes to your modeledUnits. This provides operational consistency and safety even when only managing flags. - Integrate with your Application: Use the OpenFeature SDK with the
flagdprovider in your application code (running anywhere – locally, on-premises, self-managed cloud). Configure it to connect to the App Lifecycle Manager flag service (saasconfig.googleapis.com), authenticate, and identify itself using its correspondingUnitresource name to fetch the correct flag values.
This approach lets you benefit from managed, safe flag distribution without altering your existing deployment pipelines or infrastructure management tools.
App Lifecycle Manager feature flags are in Private Preview. Access requires allowlisting. To request access for your organization or project, complete this form.
This quickstart uses a basic Python application run locally to demonstrate accessing the flags, simulating how your existing application would integrate.
Objectives
- Set up a new Google Cloud project or use an existing one.
- Enable required APIs (App Lifecycle Manager and SaaS Config).
- Grant necessary Identity and Access Management permissions for resource creation and flag reading.
- Create minimal App Lifecycle Manager resources (SaaS Offering, Unit Kind, Unit) to model an application component without deploying infrastructure.
- Define a feature flag resource associated with the Unit Kind.
- Create a flag rollout mechanism (Rollout Kind) defining the distribution strategy.
- Distribute the initial flag configuration using an App Lifecycle Manager Rollout.
- Run a sample Python application locally that connects to the App Lifecycle Manager flag service and evaluates the flag for the modeled Unit.
- Update the flag value, create a new flag release, and distribute the change.
- Verify the application picks up the updated flag value.
Before you begin
-
Sign in to your Google Account.
If you don't already have one, sign up for a new account.
-
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Enable the App Lifecycle Manager and SaaS Config APIs.
Roles required to enable APIs
To enable APIs, you need the Service Usage Admin IAM role (
roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enablepermission. Learn how to grant roles.-
Install the Google Cloud CLI.
-
If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.
-
To initialize the gcloud CLI, run the following command:
gcloud init -
In the Google Cloud console, on the project selector page, select or create a Google Cloud project.
Roles required to select or create a project
- Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
-
Create a project: To create a project, you need the Project Creator role
(
roles/resourcemanager.projectCreator), which contains theresourcemanager.projects.createpermission. Learn how to grant roles.
-
Verify that billing is enabled for your Google Cloud project.
Enable the App Lifecycle Manager and SaaS Config APIs.
Roles required to enable APIs
To enable APIs, you need the Service Usage Admin IAM role (
roles/serviceusage.serviceUsageAdmin), which contains theserviceusage.services.enablepermission. Learn how to grant roles.-
Install the Google Cloud CLI.
-
If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.
-
To initialize the gcloud CLI, run the following command:
gcloud init -
Install Python: Ensure you have Python 3.7+ installed on the machine where you will run the sample application. You also need pip to install dependencies.
python --version
pip --version
-
Authenticate gcloud for Application Default Credentials (ADC): The local Python script uses ADC to authenticate to Google Cloud services. Sign in using your user account:
gcloud auth application-default login
-
Grant Application Identity Permissions: Your application needs permission to read flag configurations from the SaaS Config service. Grant the `roles/saasconfig.viewer` role to the identity the application will use. For this quickstart using ADC locally with your user account, grant the role to your email address:
Replace PROJECT_ID with your Google Cloud project ID and YOUR_EMAIL_ADDRESS with the email associated with your CLI login.gcloud projects add-iam-policy-binding PROJECT_ID \ --member="user:YOUR_EMAIL_ADDRESS" \ --role="roles/saasconfig.viewer"
Create minimal App Lifecycle Manager resources
Even though we aren't deploying infrastructure with App Lifecycle Manager, we need a few resources to organize, target, and distribute our flags safely. These resources represent your existing application components within App Lifecycle Manager.
Define variables: Set environment variables for resource names and locations.
export PROJECT_ID="your-project-id" export SAAS_OFFERING_ID="standalone-flags-saas" export UNIT_KIND_ID="standalone-app-kind" export UNIT_ID="my-app-instance-01" export LOCATION_1="us-central1" # Example region where your app instance conceptually resides # Add more locations if your app components span multiple regions # export LOCATION_2="europe-west1"Create a SaaS offering: This acts as a top-level container for your service's configuration, including flags.
gcloud beta app-lifecycle-manager saas create ${SAAS_OFFERING_ID} \ --project=${PROJECT_ID} \ --location=global \ --locations=name=${LOCATION_1} # Add --locations=name=${LOCATION_2} if using more regions gcloud beta app-lifecycle-manager saas create ${SAAS_OFFERING_ID} \ --project=${PROJECT_ID} \ --location=${LOCATION_1} \ --locations=name=${LOCATION_1}Create a unit kind: This defines the type of component you are modeling. Crucially, we do not provide a blueprint because we are not managing infrastructure.
gcloud beta app-lifecycle-manager unit-kinds create ${UNIT_KIND_ID} \ --project=${PROJECT_ID} \ --location=global \ --saas=${SAAS_OFFERING_ID} gcloud beta app-lifecycle-manager unit-kinds create ${UNIT_KIND_ID} \ --project=${PROJECT_ID} \ --location=${LOCATION_1} \ --saas=${SAAS_OFFERING_ID}Create a unit: This represents a specific instance of your application.
gcloud beta app-lifecycle-manager units create ${UNIT_ID} \ --project=${PROJECT_ID} \ --unit-kind=${UNIT_KIND_ID} \ --location=${LOCATION_1}
Define and rollout the feature flag
Now, create the actual feature flag and use the App Lifecycle Manager rollout mechanism to make its configuration available to the units you created.
Define flag variables:
export FLAG_ID="standalone-flag-01" export FLAG_KEY="enable-beta-feature"Create the flag resource, revision, and release:
gcloud beta app-lifecycle-manager flags create ${FLAG_ID} \ --project=${PROJECT_ID} \ --key=${FLAG_KEY} \ --flag-value-type=BOOL \ --location=global \ --unit-kind=${UNIT_KIND_ID} \ export FLAG_REVISION_ID_1="${FLAG_ID}-rev1" gcloud beta app-lifecycle-manager flags revisions create ${FLAG_REVISION_ID_1} \ --project=${PROJECT_ID} \ --flag=${FLAG_ID} \ --location=global export FLAG_RELEASE_ID_1="${FLAG_ID}-rel1" gcloud beta app-lifecycle-manager flags releases create ${FLAG_RELEASE_ID_1} \ --project=${PROJECT_ID} \ --flag-revisions=${FLAG_REVISION_ID_1} \ --unit-kind=${UNIT_KIND_ID} \ --location=globalCreate a rollout kind: Define the strategy for distributing flag changes.
export ROLLOUT_KIND_ID="standalone-flags-rollout-kind" gcloud beta app-lifecycle-manager rollout-kinds create ${ROLLOUT_KIND_ID} \ --project=${PROJECT_ID} \ --unit-kind=${UNIT_KIND_ID} \ --rollout-orchestration-strategy=Google.Cloud.Simple.AllAtOnce \ --location=globalCreate the rollout: Initiate the distribution process.
export ROLLOUT_ID_1="${FLAG_ID}-rollout1" gcloud beta app-lifecycle-manager rollouts create ${ROLLOUT_ID_1} \ --project=${PROJECT_ID} \ --flag-release=${FLAG_RELEASE_ID_1} \ --rollout-kind=${ROLLOUT_KIND_ID} \ --location=globalMonitor the rollout: Ensure the deployment succeeds before proceeding.
gcloud beta app-lifecycle-manager rollouts describe ${ROLLOUT_ID_1} \ --project=${PROJECT_ID} \ --location=global
Configure standalone infrastructure
In a standalone setup, you manage your own application hosting (e.g., Cloud Run or GKE) and use App Lifecycle Manager purely for configuration sync. The application code remains standard across deployments; it only requires the FLAGD_SOURCE_PROVIDER_ID environment variable to be present at runtime to connect to the SaaS Config Service.
You can map your App Lifecycle Manager unit definitions into your standard Terraform deployment definitions by passing the constructed path as an environment variable.
Define your infrastructure: Map the path in your deployment template (e.g.,
standalone.tf).variable "project_id" { type = string } variable "region" { type = string } variable "unit_id" { type = string } resource "google_cloud_run_v2_service" "standalone_app" { name = "my-standalone-service" location = var.region template { containers { image = "us-central1-docker.pkg.dev/my-project/my-repo/my-image:latest" env { name = "FLAGD_SOURCE_PROVIDER_ID" value = "projects/${var.project_id}/locations/${var.region}/featureFlagsConfigs/${var.unit_id}" } } } }Define your variable values: Provide the configuration unit parameters in an associated variable file (e.g.,
terraform.tfvars).project_id = "PROJECT_ID" region = "LOCATION_1" unit_id = "UNIT_ID"
Integrate and run the sample application
Run an example Python application locally to connect to the App Lifecycle Manager flag service using the modeled unit configurations.
Create project directory and files:
mkdir saas_flags_standalone_app cd saas_flags_standalone_appCreate
requirements.txt:google-auth grpcio>=1.49.1,<2.0.0dev openfeature-sdk==0.8.0 openfeature-provider-flagd==0.2.2 requests typing_extensions Flask>=2.0Install dependencies:
pip install -r requirements.txtCreate app.py:
import google.auth.transport.grpc import google.auth.transport.requests import grpc import logging import time import os import sys from flask import Flask, jsonify from openfeature import api from openfeature.contrib.provider.flagd import FlagdProvider from openfeature.contrib.provider.flagd.config import ResolverType app = Flask(__name__) logging.basicConfig(stream=sys.stdout, level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') log = logging.getLogger(__name__) FLAG_KEY = os.environ.get("FLAG_KEY", "enable-beta-feature") DEFAULT_FLAG_VALUE = False # CRITICAL: Read the Unit resource name from environment variable. # This identifies the application instance to the flag service. provider_id = os.environ.get("FLAGD_SOURCE_PROVIDER_ID") if not provider_id: log.critical("FATAL: FLAGD_SOURCE_PROVIDER_ID not set.") sys.exit("FLAGD_SOURCE_PROVIDER_ID not set") log.info(f"Initializing OpenFeature provider for Unit: {provider_id}") def add_x_goog_request_params_header(config_name): return lambda context, callback: callback([("x-goog-request-params", f'name={config_name}')], None) try: credentials, detected_project_id = google.auth.default( scopes=["https://www.googleapis.com/auth/cloud-platform"] ) auth_req = google.auth.transport.requests.Request() configservice_credentials = grpc.composite_channel_credentials( grpc.ssl_channel_credentials(), grpc.metadata_call_credentials( google.auth.transport.grpc.AuthMetadataPlugin(credentials, auth_req) ), grpc.metadata_call_credentials( add_x_goog_request_params_header(provider_id) ) ) provider = FlagdProvider( resolver_type=ResolverType.IN_PROCESS, host="saasconfig.googleapis.com", port=443, sync_metadata_disabled=True, provider_id=provider_id, channel_credentials=configservice_credentials ) api.set_provider(provider) client = api.get_client() time.sleep(5) initial_flag_value = client.get_boolean_value(FLAG_KEY, DEFAULT_FLAG_VALUE) log.info(f"***** STARTUP FLAG CHECK ***** Flag '{FLAG_KEY}' evaluated to: {initial_flag_value}") except Exception as e: log.critical(f"FATAL: Failed to initialize OpenFeature provider: {e}", exc_info=True) sys.exit(f"Provider initialization failed: {e}") @app.route('/') def home(): log.info(f"Request received for endpoint '/', evaluating flag: {FLAG_KEY}") try: flag_value = client.get_boolean_value(FLAG_KEY, DEFAULT_FLAG_VALUE) log.info(f"Evaluated flag '{FLAG_KEY}': {flag_value}") return jsonify({ "flag_key": FLAG_KEY, "value": flag_value, "provider_id": provider_id }) except Exception as e: log.error(f"Error evaluating flag '{FLAG_KEY}': {e}", exc_info=True) return jsonify({ "error": f"Failed to evaluate flag {FLAG_KEY}", "details": str(e), }), 500 if __name__ == '__main__': port = int(os.environ.get('PORT', 8080)) log.info(f"Starting Flask web server on host 0.0.0.0 port {port}") app.run(host='0.0.0.0', port=port)Run the application:
export FLAGD_SOURCE_PROVIDER_ID="projects/${PROJECT_ID}/locations/${LOCATION_1}/featureFlagsConfigs/${UNIT_ID}" python app.pyVerify the initial flag value: Execute a check against the local endpoint in a secondary terminal.
curl http://localhost:8080
Update the flag and distribute the change
Modify the flag definition runtime state and distribute the update to connected targets.
Update the flag resource:
gcloud beta app-lifecycle-manager flags create ${FLAG_ID} \ --project=${PROJECT_ID} \ --key=${FLAG_KEY} \ --flag-value-type=BOOL \ --location=global \ --unit-kind=${UNIT_KIND_ID} export FLAG_REVISION_ID_2="${FLAG_ID}-rev2" gcloud beta app-lifecycle-manager flags revisions create ${FLAG_REVISION_ID_2} \ --project=${PROJECT_ID} \ --flag=${FLAG_ID} \ --location=global export FLAG_RELEASE_ID_2="${FLAG_ID}-rel2" gcloud beta app-lifecycle-manager flags releases create ${FLAG_RELEASE_ID_2} \ --project=${PROJECT_ID} \ --flag-revisions=${FLAG_REVISION_ID_2} \ --unit-kind=${UNIT_KIND_ID} \ --location=globalCreate a new rollout for the update:
export ROLLOUT_ID_2="${FLAG_ID}-rollout2" gcloud beta app-lifecycle-manager rollouts create ${ROLLOUT_ID_2} \ --project=${PROJECT_ID} \ --flag-release=${FLAG_RELEASE_ID_2} \ --rollout-kind=${ROLLOUT_KIND_ID} \ --location=globalMonitor the new rollout:
gcloud beta app-lifecycle-manager rollouts describe ${ROLLOUT_ID_2} \ --project=${PROJECT_ID} \ --location=globalVerify the change in the running application:
curl http://localhost:8080
Clean up
To avoid incurring charges to your Google Cloud account for the resources used on this page, follow these steps.
- Press
Ctrl+Cin the terminal whereapp.pyis running to stop the local Python application. - Set the flag state.
- Create a new rollout to remove obsolete flags.
After the rollout has completed and obsolete flags have been removed, delete the App Lifecycle Manager resources:
gcloud beta app-lifecycle-manager rollouts delete ${ROLLOUT_ID_1} --project=${PROJECT_ID} --location=global --quiet gcloud beta app-lifecycle-manager rollouts delete ${ROLLOUT_ID_2} --project=${PROJECT_ID} --location=global --quiet gcloud beta app-lifecycle-manager rollout-kinds delete ${ROLLOUT_KIND_ID} --project=${PROJECT_ID} --location=global --quiet gcloud beta app-lifecycle-manager flags releases delete ${FLAG_RELEASE_ID_1} --project=${PROJECT_ID} --location=global --quiet gcloud beta app-lifecycle-manager flags releases delete ${FLAG_RELEASE_ID_2} --project=${PROJECT_ID} --location=global --quiet gcloud beta app-lifecycle-manager flags delete ${FLAG_ID} --project=${PROJECT_ID} --location=global --quiet gcloud beta app-lifecycle-manager units delete ${UNIT_ID} --project=${PROJECT_ID} --location=${LOCATION_1} --quiet gcloud beta app-lifecycle-manager unit-kinds delete ${UNIT_KIND_ID} --project=${PROJECT_ID} --location=global --quiet gcloud beta app-lifecycle-manager unit-kinds delete ${UNIT_KIND_ID} --project=${PROJECT_ID} --location=${LOCATION_1} --quiet gcloud beta app-lifecycle-manager saas delete ${SAAS_OFFERING_ID} --project=${PROJECT_ID} --location=global --quiet gcloud beta app-lifecycle-manager saas delete ${SAAS_OFFERING_ID} --project=${PROJECT_ID} --location=${LOCATION_1} --quietDelete the local directory:
cd .. rm -rf saas_flags_standalone_app
What's next
- Read the App Lifecycle Manager feature flags overview for more conceptual details.
- Try the Deploy feature flags quickstart to see how flags integrate tightly with App Lifecycle Manager-managed deployments.