<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rishi Vachhani</title>
    <description>The latest articles on DEV Community by Rishi Vachhani (@vachhanirishi).</description>
    <link>https://dev.to/vachhanirishi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2893335%2F3f675c91-a026-44da-9202-31b44b639616.png</url>
      <title>DEV Community: Rishi Vachhani</title>
      <link>https://dev.to/vachhanirishi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vachhanirishi"/>
    <language>en</language>
    <item>
      <title>How to Automatically Replicate AWS SSM Parameters Across Regions Using EventBridge and Lambda</title>
      <dc:creator>Rishi Vachhani</dc:creator>
      <pubDate>Sun, 21 Jun 2026 12:15:24 +0000</pubDate>
      <link>https://dev.to/vachhanirishi/how-to-automatically-replicate-aws-ssm-parameters-across-regions-using-eventbridge-and-lambda-3o7c</link>
      <guid>https://dev.to/vachhanirishi/how-to-automatically-replicate-aws-ssm-parameters-across-regions-using-eventbridge-and-lambda-3o7c</guid>
      <description>&lt;p&gt;AWS Systems Manager Parameter Store is regional by design.&lt;/p&gt;

&lt;p&gt;If you create a parameter in &lt;code&gt;ap-south-1&lt;/code&gt;, it doesn't automatically exist in &lt;code&gt;us-east-1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For teams running disaster recovery environments, active-passive architectures, or multi-region applications, maintaining identical configuration across regions quickly becomes an operational challenge.&lt;/p&gt;

&lt;p&gt;In this guide, we'll build a fully serverless solution that automatically replicates SSM parameters whenever they are created, updated, or deleted.&lt;/p&gt;

&lt;p&gt;The solution uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Systems Manager Parameter Store&lt;/li&gt;
&lt;li&gt;AWS CloudTrail&lt;/li&gt;
&lt;li&gt;Amazon EventBridge&lt;/li&gt;
&lt;li&gt;AWS Lambda&lt;/li&gt;
&lt;li&gt;Python (boto3)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The end result is a low-cost, event-driven synchronization mechanism that keeps regions aligned automatically.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why I Built This
&lt;/h1&gt;

&lt;p&gt;While working on a disaster recovery setup recently, I noticed something that often gets overlooked.&lt;/p&gt;

&lt;p&gt;Infrastructure was deployed in multiple regions.&lt;/p&gt;

&lt;p&gt;Application containers were deployed.&lt;/p&gt;

&lt;p&gt;Databases were replicated.&lt;/p&gt;

&lt;p&gt;Monitoring was configured.&lt;/p&gt;

&lt;p&gt;Everything looked good.&lt;/p&gt;

&lt;p&gt;Until we started validating failover.&lt;/p&gt;

&lt;p&gt;Several services immediately failed because critical SSM parameters only existed in the primary region.&lt;/p&gt;

&lt;p&gt;Things like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/prod/app/DB_PASSWORD
/prod/app/API_KEY
/prod/api/JWT_SECRET
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;were missing in the secondary region.&lt;/p&gt;

&lt;p&gt;AWS Parameter Store is regional, which means your applications only see parameters that exist within the region they're running in.&lt;/p&gt;

&lt;p&gt;The obvious solution is manually maintaining copies.&lt;/p&gt;

&lt;p&gt;The practical solution is automating synchronization.&lt;/p&gt;




&lt;h1&gt;
  
  
  Architecture Overview
&lt;/h1&gt;

&lt;p&gt;Whenever someone creates, updates, or deletes a parameter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CloudTrail records the API call.&lt;/li&gt;
&lt;li&gt;EventBridge captures the event.&lt;/li&gt;
&lt;li&gt;Lambda is invoked.&lt;/li&gt;
&lt;li&gt;Lambda determines the operation type.&lt;/li&gt;
&lt;li&gt;Lambda replicates the change to one or more destination regions.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Create / Update / Delete Parameter
                │
                ▼
           CloudTrail
                │
                ▼
           EventBridge
                │
                ▼
              Lambda
                │
                ▼
      Destination Region(s)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No servers.&lt;/p&gt;

&lt;p&gt;No polling.&lt;/p&gt;

&lt;p&gt;No scheduled jobs.&lt;/p&gt;

&lt;p&gt;No manual intervention.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Replicate Deletes?
&lt;/h1&gt;

&lt;p&gt;In many organizations, disaster recovery environments are expected to mirror production as closely as possible.&lt;/p&gt;

&lt;p&gt;If a parameter is intentionally removed from the source region, keeping it in destination regions can introduce configuration drift.&lt;/p&gt;

&lt;p&gt;By replicating delete operations as well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Regions remain fully synchronized&lt;/li&gt;
&lt;li&gt;Stale parameters are automatically removed&lt;/li&gt;
&lt;li&gt;Configuration remains consistent across environments&lt;/li&gt;
&lt;li&gt;Operational overhead is reduced&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ Production Note:&lt;/p&gt;

&lt;p&gt;If accidental deletions are a concern in your organization, consider removing delete replication and handling deletions manually through change management processes.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  Prerequisites
&lt;/h1&gt;

&lt;p&gt;Before getting started, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS CLI configured&lt;/li&gt;
&lt;li&gt;Python 3.10+&lt;/li&gt;
&lt;li&gt;boto3 installed&lt;/li&gt;
&lt;li&gt;CloudTrail enabled&lt;/li&gt;
&lt;li&gt;Lambda execution role with SSM permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install boto3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;boto3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 1 - Enable CloudTrail
&lt;/h1&gt;

&lt;p&gt;EventBridge receives SSM API activity through CloudTrail.&lt;/p&gt;

&lt;p&gt;Without CloudTrail, EventBridge never sees Parameter Store changes.&lt;/p&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Console
→ CloudTrail
→ Trails
→ Create Trail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Recommended settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Management Events : Enabled
API Activity      : Write
CloudWatch Logs   : Enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once enabled, CloudTrail begins recording Parameter Store API calls.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 2 - Create the EventBridge Rule
&lt;/h1&gt;

&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWS Console
→ EventBridge
→ Rules
→ Create Rule
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the following event pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"aws.ssm"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail-type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"AWS API Call via CloudTrail"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eventSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"ssm.amazonaws.com"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"eventName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"PutParameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"DeleteParameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="s2"&gt;"DeleteParameters"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that parameter creations, updates, and deletions trigger the replication Lambda.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 3 - Deploy the Lambda Replicator
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Environment Variables
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Variable&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DEST_REGIONS&lt;/td&gt;
&lt;td&gt;Destination AWS regions&lt;/td&gt;
&lt;td&gt;us-east-1,eu-west-1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PARAM_PATHS&lt;/td&gt;
&lt;td&gt;Parameter paths to replicate&lt;/td&gt;
&lt;td&gt;/prod/app,/prod/api&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DEST_KMS_KEY_ID&lt;/td&gt;
&lt;td&gt;KMS key for SecureString parameters&lt;/td&gt;
&lt;td&gt;alias/prod-key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DRY_RUN&lt;/td&gt;
&lt;td&gt;Preview mode without writes&lt;/td&gt;
&lt;td&gt;false&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Example Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEST_REGIONS=us-east-1,eu-west-1
PARAM_PATHS=/prod/app,/prod/api
DEST_KMS_KEY_ID=alias/prod-key
DRY_RUN=false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Lambda Function
&lt;/h1&gt;

&lt;p&gt;The Lambda performs the following actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Receives EventBridge events&lt;/li&gt;
&lt;li&gt;Extracts parameter names&lt;/li&gt;
&lt;li&gt;Determines create, update, or delete operations&lt;/li&gt;
&lt;li&gt;Validates watched paths&lt;/li&gt;
&lt;li&gt;Reads source parameter values&lt;/li&gt;
&lt;li&gt;Replicates values and tags&lt;/li&gt;
&lt;li&gt;Deletes parameters in destination regions when required&lt;/li&gt;
&lt;li&gt;Produces structured CloudWatch logs&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Supported Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;PutParameter&lt;/li&gt;
&lt;li&gt;DeleteParameter&lt;/li&gt;
&lt;li&gt;DeleteParameters&lt;/li&gt;
&lt;li&gt;Native Parameter Store Change Events&lt;/li&gt;
&lt;li&gt;Multiple destination regions&lt;/li&gt;
&lt;li&gt;SecureString replication&lt;/li&gt;
&lt;li&gt;Tag replication&lt;/li&gt;
&lt;li&gt;Dry-run mode
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"""
SSM Parameter Store Cross-Region Replicator
============================================
Triggered by: EventBridge rule watching SSM Parameter Store events in source region
              (PutParameter, DeleteParameter)

Environment Variables (set in Lambda config):
  DEST_REGIONS      : Comma-separated destination regions  e.g. "us-east-1,eu-west-1"
  PARAM_PATHS       : Comma-separated path prefixes to watch e.g. "/prod/app,/prod/api"
  DEST_PARAM_TYPE   : (Optional) Force a type — String | SecureString | StringList
                      Default: preserves the source parameter's original type
  DEST_KMS_KEY_ID   : (Optional) KMS Key ID/ARN to use in destination for SecureString
                      Default: uses AWS managed key (alias/aws/ssm)
  DRY_RUN           : (Optional) Set to "true" to log actions without writing. Default: false

IAM permissions required on Lambda execution role:
  Source region:
    ssm:GetParameter
    ssm:GetParametersByPath
    ssm:DescribeParameters

  Destination region(s):
    ssm:PutParameter
    ssm:DeleteParameter
    ssm:AddTagsToResource

  KMS (if using SecureString with custom key):
    kms:GenerateDataKey
    kms:Decrypt
"""

import boto3
import json
import logging
import os
import re
from botocore.exceptions import ClientError, BotoCoreError

# ── Logging ──────────────────────────────────────────────────────────────────
logger = logging.getLogger()
logger.setLevel(logging.INFO)

def log_info(msg, **kwargs):
    logger.info(json.dumps({"level": "INFO", "message": msg, **kwargs}))

def log_warn(msg, **kwargs):
    logger.warning(json.dumps({"level": "WARN", "message": msg, **kwargs}))

def log_error(msg, **kwargs):
    logger.error(json.dumps({"level": "ERROR", "message": msg, **kwargs}))


# ── Config ───────────────────────────────────────────────────────────────────

class Config:
    """Reads and validates all environment variables at cold-start."""

    def __init__(self):
        self.dest_regions   = self._parse_list("DEST_REGIONS")
        self.param_paths    = self._parse_list("PARAM_PATHS")
        self.dest_param_type = os.environ.get("DEST_PARAM_TYPE", "").strip() or None
        self.dest_kms_key   = os.environ.get("DEST_KMS_KEY_ID", "").strip() or None
        self.dry_run        = os.environ.get("DRY_RUN", "false").strip().lower() == "true"
        self._validate()

    def _parse_list(self, env_var):
        raw = os.environ.get(env_var, "").strip()
        if not raw:
            raise EnvironmentError(f"Required environment variable '{env_var}' is not set or empty.")
        return [item.strip() for item in raw.split(",") if item.strip()]

    def _validate(self):
        valid_regions_pattern = re.compile(r'^[a-z]{2}-[a-z]+-\d+$')
        for region in self.dest_regions:
            if not valid_regions_pattern.match(region):
                raise ValueError(f"Invalid region format: '{region}'. Expected format like 'us-east-1'.")

        for path in self.param_paths:
            if not path.startswith("/"):
                raise ValueError(f"PARAM_PATHS entry '{path}' must start with '/'. e.g. '/prod/app'")

        valid_types = {"String", "StringList", "SecureString"}
        if self.dest_param_type and self.dest_param_type not in valid_types:
            raise ValueError(f"DEST_PARAM_TYPE '{self.dest_param_type}' is invalid. Choose from: {valid_types}")

        if self.dry_run:
            log_warn("DRY_RUN is enabled — no parameters will be written.")

        log_info("Configuration loaded",
                 dest_regions=self.dest_regions,
                 param_paths=self.param_paths,
                 dest_param_type=self.dest_param_type or "preserve-source",
                 dest_kms_key=self.dest_kms_key or "aws-managed-default",
                 dry_run=self.dry_run)


# Load config once at cold-start so errors surface immediately in CloudWatch
try:
    CONFIG = Config()
except (EnvironmentError, ValueError) as e:
    log_error("Configuration error — Lambda will not process events until fixed.", error=str(e))
    CONFIG = None


# ── Helpers ──────────────────────────────────────────────────────────────────

def normalize_path(path: str) -&amp;gt; str:
    """Ensure path starts with / and has no trailing slash."""
    path = path.strip()
    if not path.startswith("/"):
        path = "/" + path
    return path.rstrip("/")


def path_is_watched(param_name: str, watched_paths: list) -&amp;gt; bool:
    """Return True if param_name is under one of the watched path prefixes."""
    for prefix in watched_paths:
        if param_name == prefix or param_name.startswith(prefix + "/"):
            return True
    return False


def get_source_parameter(ssm_source, param_name: str) -&amp;gt; dict | None:
    """
    Fetch the current value + metadata of a parameter from the source region.
    Returns None if the parameter does not exist (e.g. was deleted).
    """
    try:
        response = ssm_source.get_parameter(Name=param_name, WithDecryption=True)
        param = response["Parameter"]
        log_info("Fetched source parameter",
                 name=param_name,
                 type=param.get("Type"),
                 version=param.get("Version"))
        return param
    except ClientError as e:
        code = e.response["Error"]["Code"]
        if code == "ParameterNotFound":
            log_warn("Parameter not found in source region — may have been deleted.", name=param_name)
            return None
        log_error("Failed to fetch source parameter",
                  name=param_name,
                  error_code=code,
                  error=str(e))
        raise


def get_parameter_tags(ssm_source, param_name: str) -&amp;gt; list:
    """Fetch tags from the source parameter. Returns empty list on failure."""
    try:
        response = ssm_source.list_tags_for_resource(
            ResourceType="Parameter",
            ResourceId=param_name
        )
        return response.get("TagList", [])
    except ClientError as e:
        log_warn("Could not fetch tags for parameter — tags will not be replicated.",
                 name=param_name,
                 error=str(e))
        return []


def replicate_put(ssm_dest, dest_region: str, param: dict, tags: list, config: Config):
    """Write a parameter to the destination region."""
    name  = param["Name"]
    value = param["Value"]
    ptype = config.dest_param_type or param.get("Type", "SecureString")
    desc  = param.get("Description", "Replicated by SSM cross-region replicator Lambda")

    put_kwargs = dict(
        Name=name,
        Value=value,
        Type=ptype,
        Description=desc,
        Overwrite=True,
        Tier="Standard",
    )

    if ptype == "SecureString" and config.dest_kms_key:
        put_kwargs["KeyId"] = config.dest_kms_key

    log_info("Replicating parameter",
             action="PUT",
             name=name,
             dest_region=dest_region,
             type=ptype,
             dry_run=config.dry_run)

    if config.dry_run:
        return

    try:
        response = ssm_dest.put_parameter(**put_kwargs)
        log_info("Parameter replicated successfully",
                 name=name,
                 dest_region=dest_region,
                 version=response.get("Version"))

        # Replicate tags if any
        if tags:
            ssm_dest.add_tags_to_resource(
                ResourceType="Parameter",
                ResourceId=name,
                Tags=tags
            )
            log_info("Tags replicated", name=name, dest_region=dest_region, tag_count=len(tags))

    except ClientError as e:
        log_error("Failed to replicate parameter",
                  name=name,
                  dest_region=dest_region,
                  error_code=e.response["Error"]["Code"],
                  error=str(e))
        raise


def replicate_delete(ssm_dest, dest_region: str, param_name: str, config: Config):
    """Delete a parameter in the destination region."""
    log_info("Replicating delete",
             action="DELETE",
             name=param_name,
             dest_region=dest_region,
             dry_run=config.dry_run)

    if config.dry_run:
        return

    try:
        ssm_dest.delete_parameter(Name=param_name)
        log_info("Parameter deleted successfully",
                 name=param_name,
                 dest_region=dest_region)
    except ClientError as e:
        code = e.response["Error"]["Code"]
        if code == "ParameterNotFound":
            log_warn("Parameter already absent in destination region — nothing to delete.",
                     name=param_name,
                     dest_region=dest_region)
            return
        log_error("Failed to delete parameter",
                  name=param_name,
                  dest_region=dest_region,
                  error_code=code,
                  error=str(e))
        raise


def parse_event(event: dict) -&amp;gt; tuple[str, list, str]:
    """
    Extract (action, param_names, source_region) from the EventBridge event.

    param_names is always a list — most events carry a single parameter,
    but the console's "Delete" button (and any batch delete) calls the
    DeleteParameters (plural) API, which can carry multiple names in one
    CloudTrail event.

    Supported event sources:
      - EventBridge + CloudTrail: detail-type = "AWS API Call via CloudTrail"
      - EventBridge native SSM events: detail-type = "Parameter Store Change"
    """
    detail      = event.get("detail", {})
    detail_type = event.get("detail-type", "")
    source_region = event.get("region", os.environ.get("AWS_REGION", ""))

    # ── CloudTrail-based event ────────────────────────────────────────────────
    if detail_type == "AWS API Call via CloudTrail":
        event_name = detail.get("eventName", "")
        request_params = detail.get("requestParameters", {}) or {}

        action_map = {
            "PutParameter"     : "PUT",
            "DeleteParameter"  : "DELETE",
            "DeleteParameters" : "DELETE",
        }
        action = action_map.get(event_name)
        if not action:
            raise ValueError(f"Unsupported or ignored CloudTrail eventName: '{event_name}'")

        if event_name == "DeleteParameters":
            # Batch delete — names come back as a list
            raw_names = request_params.get("names") or request_params.get("Names") or []
            if not raw_names:
                raise ValueError(f"Could not extract parameter names from CloudTrail event: {json.dumps(detail)}")
            param_names = [normalize_path(n) for n in raw_names]
        else:
            # Single put/delete — name comes back as a string
            raw_name = request_params.get("name") or request_params.get("Name") or ""
            if not raw_name:
                raise ValueError(f"Could not extract parameter name from CloudTrail event: {json.dumps(detail)}")
            param_names = [normalize_path(raw_name)]

        return action, param_names, source_region

    # ── Native SSM EventBridge event ──────────────────────────────────────────
    if detail_type == "Parameter Store Change":
        operation = detail.get("operation", "")
        param_name = detail.get("name", "")

        if not param_name:
            raise ValueError(f"Could not extract parameter name from SSM event: {json.dumps(detail)}")

        action_map = {
            "Create" : "PUT",
            "Update" : "PUT",
            "Delete" : "DELETE",
            "LabelParameterVersion": None,  # Ignored
        }
        action = action_map.get(operation)
        if action is None:
            raise ValueError(f"Unsupported or ignored SSM operation: '{operation}'")

        return action, [normalize_path(param_name)], source_region

    raise ValueError(f"Unsupported event detail-type: '{detail_type}'. "
                     f"Expected 'AWS API Call via CloudTrail' or 'Parameter Store Change'.")


# ── Lambda Handler ────────────────────────────────────────────────────────────

def lambda_handler(event, context):
    log_info("Lambda invoked",
             request_id=context.aws_request_id,
             function=context.function_name,
             remaining_ms=context.get_remaining_time_in_millis())

    # Config failed at cold-start — abort early with a clear message
    if CONFIG is None:
        log_error("Aborting: Lambda has invalid configuration. Fix environment variables and redeploy.")
        return {"statusCode": 500, "body": "Invalid Lambda configuration — check CloudWatch logs."}

    # ── Parse the incoming event ──────────────────────────────────────────────
    try:
        action, param_names, source_region = parse_event(event)
    except ValueError as e:
        log_error("Event parsing failed — skipping.", error=str(e), raw_event=json.dumps(event))
        return {"statusCode": 400, "body": str(e)}

    log_info("Event parsed",
             action=action,
             param_names=param_names,
             source_region=source_region)

    # ── Filter down to only the parameters under a watched path ────────────────
    watched_param_names = [p for p in param_names if path_is_watched(p, CONFIG.param_paths)]
    skipped_param_names = [p for p in param_names if p not in watched_param_names]

    if skipped_param_names:
        log_info("Some parameters are not under a watched path — skipping them.",
                 skipped=skipped_param_names,
                 watched_paths=CONFIG.param_paths)

    if not watched_param_names:
        log_info("No parameters in this event are under a watched path — skipping.",
                 param_names=param_names,
                 watched_paths=CONFIG.param_paths)
        return {"statusCode": 200, "body": "No parameters in watched paths — skipped."}

    # ── Source SSM client ─────────────────────────────────────────────────────
    ssm_source = boto3.client("ssm", region_name=source_region)

    all_results = {}

    for param_name in watched_param_names:
        results = {}

        # ── Replicate to each destination region ──────────────────────────────
        for dest_region in CONFIG.dest_regions:

            if dest_region == source_region:
                log_warn("Destination region is the same as source — skipping to avoid overwrite.",
                         region=dest_region)
                results[dest_region] = "skipped-same-region"
                continue

            ssm_dest = boto3.client("ssm", region_name=dest_region)

            try:
                if action == "DELETE":
                    replicate_delete(ssm_dest, dest_region, param_name, CONFIG)
                    results[dest_region] = "deleted"
                    continue

                # Fetch latest value from source
                param = get_source_parameter(ssm_source, param_name)
                if param is None:
                    log_warn("Source parameter vanished before replication — skipping.",
                             name=param_name,
                             dest_region=dest_region)
                    results[dest_region] = "skipped-source-not-found"
                    continue

                tags = get_parameter_tags(ssm_source, param_name)
                replicate_put(ssm_dest, dest_region, param, tags, CONFIG)
                results[dest_region] = "replicated"

            except (ClientError, BotoCoreError) as e:
                log_error("Replication failed for destination region",
                          dest_region=dest_region,
                          param_name=param_name,
                          error=str(e))
                results[dest_region] = f"error: {str(e)}"

        all_results[param_name] = results

    log_info("Replication complete", action=action, results=all_results)

    return {
        "statusCode": 200,
        "body": json.dumps({
            "action": action,
            "results": all_results
        })
    }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  IAM Permissions
&lt;/h1&gt;

&lt;p&gt;The Lambda execution role requires the following permissions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source Region
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"ssm:GetParameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"ssm:GetParametersByPath"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"ssm:DescribeParameters"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"ssm:ListTagsForResource"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Destination Regions
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"ssm:PutParameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"ssm:DeleteParameter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"ssm:AddTagsToResource"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If SecureString parameters use a customer-managed KMS key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"kms:Decrypt"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"kms:GenerateDataKey"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 4 - Bulk Sync Existing Parameters
&lt;/h1&gt;

&lt;p&gt;The Lambda only handles future changes.&lt;/p&gt;

&lt;p&gt;What about parameters that already exist?&lt;/p&gt;

&lt;p&gt;For that we use a one-time bulk synchronization script.&lt;/p&gt;

&lt;p&gt;This script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads all parameters under configured prefixes&lt;/li&gt;
&lt;li&gt;Preserves parameter values&lt;/li&gt;
&lt;li&gt;Preserves SecureString encryption&lt;/li&gt;
&lt;li&gt;Preserves descriptions&lt;/li&gt;
&lt;li&gt;Preserves tags&lt;/li&gt;
&lt;li&gt;Writes everything to the destination region&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Preview Before Writing
&lt;/h1&gt;

&lt;p&gt;Always start with a dry run.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;DRY_RUN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;SOURCE_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ap-south-1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;DESTINATION_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;PARAMETER_PREFIXES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/prod/app,/prod/api &lt;span class="se"&gt;\&lt;/span&gt;
python bulk_sync_ssm.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[DRY-RUN] Would write → /prod/app/DB_HOST
[DRY-RUN] Would write → /prod/app/DB_PASSWORD
[DRY-RUN] Would write → /prod/api/JWT_SECRET
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No parameters are modified.&lt;/p&gt;




&lt;h1&gt;
  
  
  Execute the Synchronization
&lt;/h1&gt;

&lt;p&gt;Once satisfied:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;SOURCE_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ap-south-1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;DESTINATION_REGION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nv"&gt;PARAMETER_PREFIXES&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/prod/app,/prod/api &lt;span class="se"&gt;\&lt;/span&gt;
python bulk_sync_ssm.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[OK] /prod/app/DB_HOST
[OK] /prod/app/DB_PASSWORD
[OK] /prod/api/JWT_SECRET
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Testing the Setup
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Test Parameter Creation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm put-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/prod/app/DB_HOST"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"database.example.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; String &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--overwrite&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; ap-south-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/prod/app/DB_HOST"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Test Parameter Update
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm put-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/prod/app/DB_HOST"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--value&lt;/span&gt; &lt;span class="s2"&gt;"new-database.example.com"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--type&lt;/span&gt; String &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--overwrite&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; ap-south-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the updated value exists in the destination region.&lt;/p&gt;




&lt;h2&gt;
  
  
  Test Parameter Deletion
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm delete-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/prod/app/DB_HOST"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; ap-south-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ssm get-parameter &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"/prod/app/DB_HOST"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ParameterNotFound
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Common Issues
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Lambda Never Triggers
&lt;/h2&gt;

&lt;p&gt;Usually caused by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CloudTrail disabled&lt;/li&gt;
&lt;li&gt;EventBridge rule in the wrong region&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  AccessDeniedException
&lt;/h2&gt;

&lt;p&gt;Ensure the Lambda role has:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssm:GetParameter
ssm:GetParametersByPath
ssm:DescribeParameters
ssm:PutParameter
ssm:DeleteParameter
ssm:AddTagsToResource
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  InvalidKeyId
&lt;/h2&gt;

&lt;p&gt;The destination KMS key does not exist.&lt;/p&gt;

&lt;p&gt;Either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create the key&lt;/li&gt;
&lt;li&gt;Use AWS-managed encryption&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Parameters Not Replicating
&lt;/h2&gt;

&lt;p&gt;Verify the parameter path matches one of the configured prefixes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/prod/app
/prod/api
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Security Recommendations
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Use SecureString
&lt;/h2&gt;

&lt;p&gt;Encrypt sensitive values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database passwords&lt;/li&gt;
&lt;li&gt;API keys&lt;/li&gt;
&lt;li&gt;Access tokens&lt;/li&gt;
&lt;li&gt;JWT secrets&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Restrict IAM Permissions
&lt;/h2&gt;

&lt;p&gt;Avoid:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssm:* on *
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Instead:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arn:aws:ssm:*:*:parameter/prod/*
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Enable Monitoring
&lt;/h2&gt;

&lt;p&gt;Monitor:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lambda errors&lt;/li&gt;
&lt;li&gt;Replication failures&lt;/li&gt;
&lt;li&gt;Unexpected Parameter Store changes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Operational visibility becomes invaluable when troubleshooting.&lt;/p&gt;




&lt;h1&gt;
  
  
  Cost Considerations
&lt;/h1&gt;

&lt;p&gt;This solution is surprisingly inexpensive.&lt;/p&gt;

&lt;p&gt;You're only using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;EventBridge&lt;/li&gt;
&lt;li&gt;Lambda&lt;/li&gt;
&lt;li&gt;CloudTrail&lt;/li&gt;
&lt;li&gt;Parameter Store&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are no always-running resources.&lt;/p&gt;

&lt;p&gt;For most teams, the monthly cost is negligible compared to the operational effort saved.&lt;/p&gt;




&lt;h1&gt;
  
  
  Complete Workflow
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Day 0
│
├─ Enable CloudTrail
├─ Deploy Lambda
├─ Create EventBridge Rule
├─ Run bulk_sync_ssm.py
└─ Verify replication

Day 1+
│
├─ Developer creates parameter
│     └─ Replicated
│
├─ Developer updates parameter
│     └─ Replicated
│
├─ Developer deletes parameter
│     └─ Deleted from destination regions
│
└─ Regions remain synchronized automatically
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;AWS doesn't currently provide native cross-region replication for Parameter Store.&lt;/p&gt;

&lt;p&gt;Fortunately, combining CloudTrail, EventBridge, and Lambda makes it easy to build your own event-driven synchronization mechanism.&lt;/p&gt;

&lt;p&gt;The biggest lesson from implementing this in production is that configuration drift is rarely caused by technology—it is usually caused by manual processes.&lt;/p&gt;

&lt;p&gt;By automating parameter replication for creates, updates, and deletions, you remove an entire category of operational risk and ensure that all regions remain synchronized automatically.&lt;/p&gt;

&lt;p&gt;If you're running multi-region AWS workloads, this is one of those small automations that quietly saves hours of troubleshooting later.&lt;/p&gt;

&lt;p&gt;Happy building 🚀&lt;/p&gt;




&lt;h3&gt;
  
  
  Acknowledgements
&lt;/h3&gt;

&lt;p&gt;A special thanks to *&lt;em&gt;&lt;a class="mentioned-user" href="https://dev.to/vikram_patel"&gt;@vikram_patel&lt;/a&gt; *&lt;/em&gt; for collaboration, testing, and valuable feedback during the implementation of this solution.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>aws</category>
      <category>automation</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Streamline Your Flutter Development: Complete CI/CD Pipeline with GitHub Actions and Google Play Store Deployment</title>
      <dc:creator>Rishi Vachhani</dc:creator>
      <pubDate>Sat, 30 Aug 2025 11:13:44 +0000</pubDate>
      <link>https://dev.to/vachhanirishi/streamline-your-flutter-development-complete-cicd-pipeline-with-github-actions-and-google-play-21fc</link>
      <guid>https://dev.to/vachhanirishi/streamline-your-flutter-development-complete-cicd-pipeline-with-github-actions-and-google-play-21fc</guid>
      <description>&lt;h1&gt;
  
  
  Streamline Your Flutter Development: Complete CI/CD Pipeline with GitHub Actions and Google Play Store Deployment
&lt;/h1&gt;

&lt;p&gt;As Flutter applications grow in complexity, manual building and deployment processes become time-consuming and error-prone. Implementing a robust CI/CD (Continuous Integration/Continuous Deployment) pipeline can dramatically improve your development workflow, reduce human errors, and ensure consistent releases.&lt;/p&gt;

&lt;p&gt;In this comprehensive guide, we'll walk through setting up an automated CI/CD pipeline using GitHub Actions that builds your Flutter app, runs tests, and deploys directly to the Google Play Store.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You'll Learn
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Setting up GitHub Actions for Flutter CI/CD&lt;/li&gt;
&lt;li&gt;Configuring automatic deployment to Google Play Store&lt;/li&gt;
&lt;li&gt;Best practices for managing secrets and sensitive data&lt;/li&gt;
&lt;li&gt;Real-world pipeline configuration with practical examples&lt;/li&gt;
&lt;li&gt;Common pitfalls and how to avoid them&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before we dive in, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Flutter application hosted on GitHub&lt;/li&gt;
&lt;li&gt;A Google Play Console developer account&lt;/li&gt;
&lt;li&gt;Basic understanding of YAML and GitHub Actions&lt;/li&gt;
&lt;li&gt;Android app signing key (we'll cover this)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Part 1: Understanding the CI/CD Pipeline
&lt;/h2&gt;

&lt;p&gt;Our pipeline will consist of three main stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Integration (CI)&lt;/strong&gt;: Code validation, testing, and building&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Continuous Deployment (CD)&lt;/strong&gt;: Automated deployment to Google Play Store&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: Pipeline health and deployment status tracking&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 2: Setting Up Google Play Console
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Create a Service Account
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Visit the &lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Create a new project or select an existing one&lt;/li&gt;
&lt;li&gt;Navigate to "IAM &amp;amp; Admin" → "Service Accounts"&lt;/li&gt;
&lt;li&gt;Click "Create Service Account"&lt;/li&gt;
&lt;li&gt;Fill in the service account details:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;flutter-ci-cd-service&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt;: &lt;code&gt;Service account for Flutter CI/CD pipeline&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 2: Configure Play Console Access
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;a href="https://play.google.com/console" rel="noopener noreferrer"&gt;Google Play Console&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Navigate to "Setup" → "API access"&lt;/li&gt;
&lt;li&gt;Link your Google Cloud project&lt;/li&gt;
&lt;li&gt;Grant access to your service account with these permissions:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Release manager&lt;/strong&gt;: For uploading and releasing apps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;View app information&lt;/strong&gt;: For reading app metadata&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3: Generate Service Account Key
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;In Google Cloud Console, go to your service account&lt;/li&gt;
&lt;li&gt;Click "Keys" → "Add Key" → "Create new key"&lt;/li&gt;
&lt;li&gt;Select "JSON" format&lt;/li&gt;
&lt;li&gt;Download the key file (keep it secure!)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 3: Android App Signing Setup
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Generate Upload Key
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;keytool &lt;span class="nt"&gt;-genkey&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nt"&gt;-keystore&lt;/span&gt; upload-keystore.jks &lt;span class="nt"&gt;-keyalg&lt;/span&gt; RSA &lt;span class="nt"&gt;-keysize&lt;/span&gt; 2048 &lt;span class="nt"&gt;-validity&lt;/span&gt; 10000 &lt;span class="nt"&gt;-alias&lt;/span&gt; upload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create key.properties
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;android/key.properties&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="py"&gt;storePassword&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_keystore_password&lt;/span&gt;
&lt;span class="py"&gt;keyPassword&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;your_key_password&lt;/span&gt;
&lt;span class="py"&gt;keyAlias&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;upload&lt;/span&gt;
&lt;span class="py"&gt;storeFile&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;upload-keystore.jks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configure build.gradle
&lt;/h3&gt;

&lt;p&gt;Update &lt;code&gt;android/app/build.gradle&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Add before android block&lt;/span&gt;
&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;keystoreProperties&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Properties&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;keystorePropertiesFile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rootProject&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'key.properties'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keystorePropertiesFile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exists&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;keystoreProperties&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;load&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;FileInputStream&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keystorePropertiesFile&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;android&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// ... existing configuration&lt;/span&gt;

    &lt;span class="n"&gt;signingConfigs&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;keyAlias&lt;/span&gt; &lt;span class="n"&gt;keystoreProperties&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'keyAlias'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;keyPassword&lt;/span&gt; &lt;span class="n"&gt;keystoreProperties&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'keyPassword'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;storeFile&lt;/span&gt; &lt;span class="n"&gt;keystoreProperties&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'storeFile'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;keystoreProperties&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'storeFile'&lt;/span&gt;&lt;span class="o"&gt;])&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
            &lt;span class="n"&gt;storePassword&lt;/span&gt; &lt;span class="n"&gt;keystoreProperties&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'storePassword'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;buildTypes&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;signingConfig&lt;/span&gt; &lt;span class="n"&gt;signingConfigs&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;release&lt;/span&gt;
            &lt;span class="n"&gt;minifyEnabled&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
            &lt;span class="n"&gt;proguardFiles&lt;/span&gt; &lt;span class="nf"&gt;getDefaultProguardFile&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'proguard-android.txt'&lt;/span&gt;&lt;span class="o"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'proguard-rules.pro'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 4: GitHub Actions CI/CD Pipeline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Complete Workflow Configuration
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;.github/workflows/flutter-ci-cd.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Flutter CI/CD Pipeline&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;published&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;FLUTTER_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.24.0"&lt;/span&gt;
  &lt;span class="na"&gt;JAVA_VERSION&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;17"&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# Continuous Integration Job&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run Tests and Analysis&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Java&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;distribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temurin'&lt;/span&gt;
        &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.JAVA_VERSION }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Flutter&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;subosito/flutter-action@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;flutter-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.FLUTTER_VERSION }}&lt;/span&gt;
        &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stable'&lt;/span&gt;
        &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter pub get&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Verify formatting&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dart format --output=none --set-exit-if-changed .&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Analyze project source&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter analyze --fatal-infos&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run unit tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter test --coverage&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload coverage to Codecov&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecov/codecov-action@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.CODECOV_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;coverage/lcov.info&lt;/span&gt;

  &lt;span class="c1"&gt;# Build Job&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build APK and App Bundle&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'push' || github.event_name == 'release'&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Java&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-java@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;distribution&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;temurin'&lt;/span&gt;
        &lt;span class="na"&gt;java-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.JAVA_VERSION }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Flutter&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;subosito/flutter-action@v2&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;flutter-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.FLUTTER_VERSION }}&lt;/span&gt;
        &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stable'&lt;/span&gt;
        &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter pub get&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Decode keystore&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "${{ secrets.KEYSTORE_BASE64 }}" | base64 --decode &amp;gt; android/app/keystore.jks&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create key.properties&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "storeFile=keystore.jks" &amp;gt; android/key.properties&lt;/span&gt;
        &lt;span class="s"&gt;echo "storePassword=${{ secrets.KEYSTORE_PASSWORD }}" &amp;gt;&amp;gt; android/key.properties&lt;/span&gt;
        &lt;span class="s"&gt;echo "keyPassword=${{ secrets.KEY_PASSWORD }}" &amp;gt;&amp;gt; android/key.properties&lt;/span&gt;
        &lt;span class="s"&gt;echo "keyAlias=${{ secrets.KEY_ALIAS }}" &amp;gt;&amp;gt; android/key.properties&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build APK&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter build apk --release&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build App Bundle&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter build appbundle --release&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload APK artifact&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release-apk&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/app/outputs/flutter-apk/app-release.apk&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload App Bundle artifact&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/upload-artifact@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release-aab&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/app/outputs/bundle/release/app-release.aab&lt;/span&gt;

  &lt;span class="c1"&gt;# Deploy to Google Play Store&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Play Store&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'release' &amp;amp;&amp;amp; github.event.action == 'published'&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout repository&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Download App Bundle artifact&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/download-artifact@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release-aab&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Create service account JSON&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;echo "${{ secrets.GOOGLE_SERVICES_JSON }}" | base64 --decode &amp;gt; service-account.json&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Play Store&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;r0adkll/upload-google-play@v1.1.3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;serviceAccountJson&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service-account.json&lt;/span&gt;
        &lt;span class="na"&gt;packageName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;com.yourcompany.yourapp&lt;/span&gt;
        &lt;span class="na"&gt;releaseFiles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;app-release.aab&lt;/span&gt;
        &lt;span class="na"&gt;track&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;internal&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;completed&lt;/span&gt;
        &lt;span class="na"&gt;inAppUpdatePriority&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
        &lt;span class="na"&gt;userFraction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5&lt;/span&gt;
        &lt;span class="na"&gt;whatsNewDirectory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;distribution/whatsnew&lt;/span&gt;
        &lt;span class="na"&gt;mappingFile&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build/app/outputs/mapping/release/mapping.txt&lt;/span&gt;

  &lt;span class="c1"&gt;# Notify on deployment&lt;/span&gt;
  &lt;span class="na"&gt;notify&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Send Deployment Notification&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy&lt;/span&gt;
    &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always()&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Notify Slack&lt;/span&gt;
      &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;needs.deploy.result == 'success'&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8398a7/action-slack@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;success&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;🚀&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Flutter&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;successfully&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;deployed&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;to&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Play&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Store!'&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SLACK_WEBHOOK_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_WEBHOOK_URL }}&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Notify on failure&lt;/span&gt;
      &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;needs.deploy.result == 'failure'&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8398a7/action-slack@v3&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;failure&lt;/span&gt;
        &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;❌&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;Flutter&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;deployment&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;failed!'&lt;/span&gt;
      &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;SLACK_WEBHOOK_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_WEBHOOK_URL }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 5: Advanced Pipeline Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multi-Environment Deployment
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;internal&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;alpha&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;include&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;internal&lt;/span&gt;
        &lt;span class="na"&gt;track&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;internal&lt;/span&gt;
        &lt;span class="na"&gt;user_fraction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.0&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpha&lt;/span&gt;
        &lt;span class="na"&gt;track&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpha&lt;/span&gt;
        &lt;span class="na"&gt;user_fraction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.1&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
        &lt;span class="na"&gt;track&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
        &lt;span class="na"&gt;user_fraction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conditional Deployments
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Internal Track&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/develop'&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;r0adkll/upload-google-play@v1.1.3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;track&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;internal&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Production&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.event_name == 'release'&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;r0adkll/upload-google-play@v1.1.3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;track&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 6: Security Best Practices
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Managing Secrets Securely
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Required GitHub Secrets
&lt;/h4&gt;

&lt;p&gt;Navigate to your repository → Settings → Secrets and variables → Actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;KEYSTORE_BASE64          # Base64 encoded keystore file
KEYSTORE_PASSWORD        # Keystore password
KEY_PASSWORD            # Key password
KEY_ALIAS               # Key alias
GOOGLE_SERVICES_JSON    # Base64 encoded service account JSON
CODECOV_TOKEN          # Optional: for code coverage
SLACK_WEBHOOK_URL      # Optional: for notifications
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Encoding Files to Base64
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Encode keystore&lt;/span&gt;
&lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; upload-keystore.jks | pbcopy

&lt;span class="c"&gt;# Encode service account JSON&lt;/span&gt;
&lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; service-account.json | pbcopy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Environment-Specific Configurations
&lt;/h3&gt;

&lt;p&gt;Create separate secret sets for different environments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEV_KEYSTORE_BASE64
STAGING_KEYSTORE_BASE64
PROD_KEYSTORE_BASE64
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Secret Rotation Strategy
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rotate service account keys every 90 days&lt;/li&gt;
&lt;li&gt;Use time-limited access tokens when possible&lt;/li&gt;
&lt;li&gt;Implement secret scanning in your repository&lt;/li&gt;
&lt;li&gt;Never commit secrets to version control&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. Access Control
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Restrict deployment to specific branches&lt;/span&gt;
&lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github.ref == 'refs/heads/main' &amp;amp;&amp;amp; github.event_name == 'push'&lt;/span&gt;

&lt;span class="c1"&gt;# Require manual approval for production deployments&lt;/span&gt;
&lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
  &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://play.google.com/store/apps/details?id=com.yourcompany.yourapp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 7: Enhanced Pipeline Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Code Quality Gates
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run custom lints&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter analyze --fatal-warnings&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check code coverage threshold&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;COVERAGE=$(flutter test --coverage | grep -o '[0-9]*\.[0-9]*%' | head -1 | sed 's/%//')&lt;/span&gt;
    &lt;span class="s"&gt;if (( $(echo "$COVERAGE &amp;lt; 80" | bc -l) )); then&lt;/span&gt;
      &lt;span class="s"&gt;echo "Coverage $COVERAGE% is below threshold of 80%"&lt;/span&gt;
      &lt;span class="s"&gt;exit 1&lt;/span&gt;
    &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Dynamic Version Management
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Update version&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;VERSION_CODE=${{ github.run_number }}&lt;/span&gt;
    &lt;span class="s"&gt;VERSION_NAME="${{ github.ref_name }}-${{ github.run_number }}"&lt;/span&gt;

    &lt;span class="s"&gt;# Update pubspec.yaml&lt;/span&gt;
    &lt;span class="s"&gt;sed -i "s/version: .*/version: $VERSION_NAME+$VERSION_CODE/" pubspec.yaml&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Parallel Testing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test-type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;unit&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;widget&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;integration&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run ${{ matrix.test-type }} tests&lt;/span&gt;
      &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter test test/${{ matrix.test-type }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 8: Troubleshooting Common Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Issue 1: Build Failures
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Gradle build fails due to dependency conflicts&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Clean build cache&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;flutter clean&lt;/span&gt;
    &lt;span class="s"&gt;flutter pub get&lt;/span&gt;
    &lt;span class="s"&gt;cd android &amp;amp;&amp;amp; ./gradlew clean&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Issue 2: Keystore Issues
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Keystore not found or invalid&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Verify keystore&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;if [ ! -f "android/app/keystore.jks" ]; then&lt;/span&gt;
      &lt;span class="s"&gt;echo "Keystore file not found!"&lt;/span&gt;
      &lt;span class="s"&gt;exit 1&lt;/span&gt;
    &lt;span class="s"&gt;fi&lt;/span&gt;
    &lt;span class="s"&gt;keytool -list -keystore android/app/keystore.jks -storepass ${{ secrets.KEYSTORE_PASSWORD }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Issue 3: Play Console Upload Failures
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Service account lacks permissions&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Verify service account has "Release Manager" role&lt;/li&gt;
&lt;li&gt;Ensure app is properly linked in Play Console&lt;/li&gt;
&lt;li&gt;Check track configuration (internal/alpha/beta/production)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Part 9: Monitoring and Notifications
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Slack Integration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Notify deployment status&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;8398a7/action-slack@v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ job.status }}&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;repo,message,commit,author,action,eventName,ref,workflow&lt;/span&gt;
  &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;SLACK_WEBHOOK_URL&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.SLACK_WEBHOOK_URL }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Email Notifications
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Send email notification&lt;/span&gt;
  &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;failure()&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dawidd6/action-send-mail@v3&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;server_address&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;smtp.gmail.com&lt;/span&gt;
    &lt;span class="na"&gt;server_port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;465&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EMAIL_USERNAME }}&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.EMAIL_PASSWORD }}&lt;/span&gt;
    &lt;span class="na"&gt;subject&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;🚨 Flutter CI/CD Pipeline Failed&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;The CI/CD pipeline for ${{ github.repository }} has failed.&lt;/span&gt;

      &lt;span class="s"&gt;Commit: ${{ github.sha }}&lt;/span&gt;
      &lt;span class="s"&gt;Branch: ${{ github.ref }}&lt;/span&gt;
      &lt;span class="s"&gt;Author: ${{ github.actor }}&lt;/span&gt;

      &lt;span class="s"&gt;Check the logs: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}&lt;/span&gt;
    &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev-team@yourcompany.com&lt;/span&gt;
    &lt;span class="na"&gt;from&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ci-cd@yourcompany.com&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 10: Performance Optimization
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Caching Strategy
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache Flutter dependencies&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;~/.pub-cache&lt;/span&gt;
      &lt;span class="s"&gt;${{ runner.tool_cache }}/flutter&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-flutter-${{ hashFiles('**/pubspec.lock') }}&lt;/span&gt;
    &lt;span class="na"&gt;restore-keys&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;${{ runner.os }}-flutter-&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cache Gradle dependencies&lt;/span&gt;
  &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/cache@v4&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;~/.gradle/caches&lt;/span&gt;
      &lt;span class="s"&gt;~/.gradle/wrapper&lt;/span&gt;
    &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build Optimization
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Enable Gradle daemon&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;mkdir -p ~/.gradle&lt;/span&gt;
    &lt;span class="s"&gt;echo "org.gradle.daemon=true" &amp;gt;&amp;gt; ~/.gradle/gradle.properties&lt;/span&gt;
    &lt;span class="s"&gt;echo "org.gradle.parallel=true" &amp;gt;&amp;gt; ~/.gradle/gradle.properties&lt;/span&gt;
    &lt;span class="s"&gt;echo "org.gradle.configureondemand=true" &amp;gt;&amp;gt; ~/.gradle/gradle.properties&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 11: Advanced Security Measures
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Secret Scanning
&lt;/h3&gt;

&lt;p&gt;Add &lt;code&gt;.github/workflows/security-scan.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Security Scan&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;develop&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;main&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;secret-scan&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;fetch-depth&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run TruffleHog OSS&lt;/span&gt;
      &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;trufflesecurity/trufflehog@main&lt;/span&gt;
      &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./&lt;/span&gt;
        &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
        &lt;span class="na"&gt;head&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;HEAD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Dependency Vulnerability Scanning
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run dependency audit&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;flutter pub deps --json | dart run security_audit&lt;/span&gt;

&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Check for outdated packages&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter pub outdated --exit-if-outdated&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Code Signing Verification
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Verify app signing&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;jarsigner -verify -verbose -certs build/app/outputs/bundle/release/app-release.aab&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Part 12: Multi-Platform Support
&lt;/h2&gt;

&lt;h3&gt;
  
  
  iOS Deployment Extension
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;build-ios&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build iOS&lt;/span&gt;
  &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;macos-latest&lt;/span&gt;
  &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;

  &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Flutter&lt;/span&gt;
    &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;subosito/flutter-action@v2&lt;/span&gt;
    &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;flutter-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.FLUTTER_VERSION }}&lt;/span&gt;
      &lt;span class="na"&gt;channel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;stable'&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter pub get&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build iOS&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;flutter build ios --release --no-codesign&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Build IPA&lt;/span&gt;
    &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
      &lt;span class="s"&gt;cd ios&lt;/span&gt;
      &lt;span class="s"&gt;xcodebuild -workspace Runner.xcworkspace \&lt;/span&gt;
                 &lt;span class="s"&gt;-scheme Runner \&lt;/span&gt;
                 &lt;span class="s"&gt;-configuration Release \&lt;/span&gt;
                 &lt;span class="s"&gt;-destination generic/platform=iOS \&lt;/span&gt;
                 &lt;span class="s"&gt;-archivePath build/Runner.xcarchive \&lt;/span&gt;
                 &lt;span class="s"&gt;archive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Essential Resources and Links
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Google Play Console &amp;amp; APIs
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://play.google.com/console" rel="noopener noreferrer"&gt;Google Play Console&lt;/a&gt; - Main dashboard for app management&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://console.cloud.google.com/" rel="noopener noreferrer"&gt;Google Cloud Console&lt;/a&gt; - Service account management&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developers.google.com/android-publisher" rel="noopener noreferrer"&gt;Google Play Developer API&lt;/a&gt; - API documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://support.google.com/googleplay/android-developer" rel="noopener noreferrer"&gt;Play Console Help&lt;/a&gt; - Official support docs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  GitHub Actions Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/marketplace?type=actions" rel="noopener noreferrer"&gt;GitHub Actions Marketplace&lt;/a&gt; - Find reusable actions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/marketplace/actions/flutter-action" rel="noopener noreferrer"&gt;Flutter Action&lt;/a&gt; - Official Flutter setup action&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/marketplace/actions/upload-android-release-to-play-store" rel="noopener noreferrer"&gt;Upload Google Play Action&lt;/a&gt; - Play Store deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security Tools
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/trufflesecurity/trufflehog" rel="noopener noreferrer"&gt;TruffleHog&lt;/a&gt; - Secret detection&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gitguardian.com/" rel="noopener noreferrer"&gt;GitGuardian&lt;/a&gt; - Secret monitoring service&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Best Practices Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Security
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Use GitHub Secrets for all sensitive data&lt;/li&gt;
&lt;li&gt;✅ Encode binary files (keystore, service account) as Base64&lt;/li&gt;
&lt;li&gt;✅ Implement secret rotation schedule&lt;/li&gt;
&lt;li&gt;✅ Enable branch protection rules&lt;/li&gt;
&lt;li&gt;✅ Use environment-specific deployments&lt;/li&gt;
&lt;li&gt;✅ Implement secret scanning&lt;/li&gt;
&lt;li&gt;✅ Never commit secrets to repository&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Cache Flutter and Gradle dependencies&lt;/li&gt;
&lt;li&gt;✅ Use matrix builds for parallel testing&lt;/li&gt;
&lt;li&gt;✅ Optimize Docker images if using containers&lt;/li&gt;
&lt;li&gt;✅ Implement incremental builds&lt;/li&gt;
&lt;li&gt;✅ Use artifact caching between jobs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Reliability
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Implement proper error handling&lt;/li&gt;
&lt;li&gt;✅ Add retry mechanisms for flaky operations&lt;/li&gt;
&lt;li&gt;✅ Use health checks before deployment&lt;/li&gt;
&lt;li&gt;✅ Implement rollback strategies&lt;/li&gt;
&lt;li&gt;✅ Monitor deployment success rates&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Quality
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;✅ Run automated tests (unit, widget, integration)&lt;/li&gt;
&lt;li&gt;✅ Enforce code formatting standards&lt;/li&gt;
&lt;li&gt;✅ Implement static analysis&lt;/li&gt;
&lt;li&gt;✅ Check code coverage thresholds&lt;/li&gt;
&lt;li&gt;✅ Scan for security vulnerabilities&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Monitoring Your Pipeline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Key Metrics to Track
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Build Success Rate&lt;/strong&gt;: Percentage of successful builds&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment Frequency&lt;/strong&gt;: How often you deploy&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lead Time&lt;/strong&gt;: Time from commit to production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mean Time to Recovery&lt;/strong&gt;: Time to fix failed deployments&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Setting Up Monitoring
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Record metrics&lt;/span&gt;
  &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;echo "build_duration=${{ job.duration }}" &amp;gt;&amp;gt; metrics.log&lt;/span&gt;
    &lt;span class="s"&gt;echo "commit_sha=${{ github.sha }}" &amp;gt;&amp;gt; metrics.log&lt;/span&gt;
    &lt;span class="s"&gt;echo "deployment_time=$(date -u +%Y-%m-%dT%H:%M:%SZ)" &amp;gt;&amp;gt; metrics.log&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Pitfalls and Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Version Conflicts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Flutter/Dart version mismatches&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Pin specific versions in workflow and use version matrix for testing&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Keystore Management
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Keystore security and access&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Use Base64 encoding and GitHub Secrets, never commit keystore files&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Play Console Permissions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Service account lacks necessary permissions&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Grant "Release Manager" role and verify API access configuration&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Build Artifacts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Problem&lt;/strong&gt;: Large artifact sizes affecting pipeline performance&lt;br&gt;
&lt;strong&gt;Solution&lt;/strong&gt;: Implement artifact cleanup and use efficient compression&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Implementing a robust CI/CD pipeline for your Flutter application transforms your development workflow from manual, error-prone processes to automated, reliable deployments. This setup ensures that every code change is thoroughly tested, properly built, and securely deployed to the Google Play Store.&lt;/p&gt;

&lt;p&gt;Key benefits you'll experience:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Faster Release Cycles&lt;/strong&gt;: Automated processes reduce deployment time from hours to minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improved Code Quality&lt;/strong&gt;: Automated testing catches issues before they reach production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Security&lt;/strong&gt;: Proper secret management and automated security scanning&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Collaboration&lt;/strong&gt;: Standardized processes make team collaboration smoother&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reduced Human Error&lt;/strong&gt;: Automation eliminates manual deployment mistakes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Next Steps
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Implement the basic pipeline and test with a simple Flutter app&lt;/li&gt;
&lt;li&gt;Gradually add advanced features like multi-environment deployment&lt;/li&gt;
&lt;li&gt;Set up monitoring and alerting for pipeline health&lt;/li&gt;
&lt;li&gt;Establish a secret rotation schedule&lt;/li&gt;
&lt;li&gt;Document your team's deployment processes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Remember, CI/CD is an iterative process. Start simple, monitor your pipeline's performance, and continuously improve based on your team's needs and feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Additional Resources
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.flutter.dev/deployment/cd" rel="noopener noreferrer"&gt;Flutter DevOps Guide&lt;/a&gt; - Official Flutter deployment docs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/platform/technology/app-bundle" rel="noopener noreferrer"&gt;Android App Bundle Guide&lt;/a&gt; - Google's app bundle documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.github.com/en/actions" rel="noopener noreferrer"&gt;GitHub Actions Documentation&lt;/a&gt; - Complete GitHub Actions reference&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy coding, and may your deployments be ever smooth! 🚀&lt;/p&gt;




</description>
      <category>cicd</category>
      <category>flutter</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Setting Up Auto Scaling Groups and Load Balancer on AWS EC2: A Step-by Step Guide</title>
      <dc:creator>Rishi Vachhani</dc:creator>
      <pubDate>Sun, 27 Apr 2025 08:30:09 +0000</pubDate>
      <link>https://dev.to/vachhanirishi/setting-up-auto-scaling-groups-and-load-balancer-on-aws-ec2-a-step-by-step-guide-1io9</link>
      <guid>https://dev.to/vachhanirishi/setting-up-auto-scaling-groups-and-load-balancer-on-aws-ec2-a-step-by-step-guide-1io9</guid>
      <description>&lt;p&gt;Ensuring high availability and scalability for your application is crucial when deploying on AWS.&lt;/p&gt;

&lt;p&gt;In this guide, we'll walk through setting up Auto Scaling Groups (ASG), an Application Load Balancer (ALB), and a Target Group on AWS EC2.&lt;br&gt;
By the end, you'll have a fully functional architecture that dynamically scales based on demand.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Launch EC2 Instance
Before setting up Auto Scaling, start by launching an EC2 instance and configuring it to serve traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Install Nginx on the Instance&lt;br&gt;
Once your instance is running, install an Nginx server to serve a default page:&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt install nginx -y&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;When you access the instance's public IP in a browser, you should see the default Nginx welcome page.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Create a Target Group
A Target Group is needed to route traffic from the Load Balancer to the EC2 instances.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Steps to Create a Target Group:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to Target Groups in the AWS EC2 dashboard.&lt;/li&gt;
&lt;li&gt;Click Create Target Group.&lt;/li&gt;
&lt;li&gt;Select Instances as the target type.&lt;/li&gt;
&lt;li&gt;Specify the port (80/443) and protocol (HTTP/HTTPS).&lt;/li&gt;
&lt;li&gt;Attach the previously launched EC2 instances.&lt;/li&gt;
&lt;li&gt;AWS will now check the health status of the instances.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
Create an Application Load Balancer (ALB)
The Load Balancer distributes incoming traffic across multiple instances, improving availability and reliability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Steps to Create a Load Balancer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to Load Balancers in the AWS dashboard.&lt;/li&gt;
&lt;li&gt;Click Create Load Balancer and select Application Load Balancer.&lt;/li&gt;
&lt;li&gt;Choose Internet-facing as the scheme.&lt;/li&gt;
&lt;li&gt;Configure Security Groups to allow HTTP/HTTPS traffic.&lt;/li&gt;
&lt;li&gt;Select Regions and Availability Zones as needed.&lt;/li&gt;
&lt;li&gt;Attach the previously created Target Group.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Click Create Load Balancer.&lt;/p&gt;

&lt;p&gt;Once created, you can access the instances using the Load Balancer's DNS name.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Create a Launch Template
A Launch Template defines the instance configuration for Auto Scaling.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Steps to Create a Launch Template:&lt;/p&gt;

&lt;p&gt;Navigate to Launch Templates in AWS.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Click Create Launch Template.&lt;/li&gt;
&lt;li&gt;Choose an instance type (e.g., t2.micro, t3.medium).&lt;/li&gt;
&lt;li&gt;Configure network settings and attach necessary storage.&lt;/li&gt;
&lt;li&gt;Select Security Groups and Key Pairs for authentication.&lt;/li&gt;
&lt;li&gt;Save and create the Launch Template.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;
Set Up an Auto Scaling Group (ASG)
Auto Scaling ensures that your application scales up or down based on demand.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Steps to Create an Auto Scaling Group:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to Auto Scaling Groups in AWS.&lt;/li&gt;
&lt;li&gt;Click Create Auto Scaling Group.&lt;/li&gt;
&lt;li&gt;Select the previously created Launch Template.&lt;/li&gt;
&lt;li&gt;Choose VPC settings and Subnets.&lt;/li&gt;
&lt;li&gt;Define the desired number of instances to maintain.&lt;/li&gt;
&lt;li&gt;Integrate with the Load Balancer and Target Group.&lt;/li&gt;
&lt;li&gt;Configure additional settings like Scaling Policies.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Click Create Auto Scaling Group.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
Configure Dynamic Scaling Policies
A Dynamic Scaling Policy adjusts the number of instances based on traffic.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Steps to Configure Scaling Policies:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to Auto Scaling Groups.&lt;/li&gt;
&lt;li&gt;Select Scaling Policies.&lt;/li&gt;
&lt;li&gt;Define Scaling Conditions such as CPU utilization or request rate.&lt;/li&gt;
&lt;li&gt;Choose Step Scaling or Target Tracking Scaling.&lt;/li&gt;
&lt;li&gt;Set thresholds for scaling in and out dynamically.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Save the policy — AWS will now adjust instances automatically based on demand.&lt;/p&gt;

&lt;p&gt;Final Architecture Overview&lt;br&gt;
After completing these steps, your AWS setup will include:&lt;/p&gt;

&lt;p&gt;✅ EC2 instances running Nginx&lt;br&gt;
✅ An Application Load Balancer distributing traffic&lt;br&gt;
✅ A Target Group managing instance health&lt;br&gt;
✅ An Auto Scaling Group ensuring dynamic scaling&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiybrln93j70k68ck057c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fiybrln93j70k68ck057c.png" alt="Image description" width="761" height="628"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This architecture ensures high availability, fault tolerance, and scalability for your AWS-hosted applications.&lt;/p&gt;

&lt;p&gt;Conclusion&lt;br&gt;
By following this guide, you've successfully deployed a scalable and fault-tolerant AWS infrastructure using Auto Scaling, Load Balancer, and Target Groups.&lt;br&gt;
This setup ensures your application remains highly available even during traffic spikes.&lt;/p&gt;

&lt;h2&gt;
  
  
  📌 For a detailed step-by-step guide with images, download the PDF &lt;a href="https://docs.google.com/document/d/1-gD4uwvILBT92iprmF9YxFN54twPXXtX/edit" rel="noopener noreferrer"&gt;here&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;👥 Thanks to &lt;a class="mentioned-user" href="https://dev.to/vikram_patel"&gt;@vikram_patel&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/shreyansh_1904"&gt;@shreyansh_1904&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/karmpatel"&gt;@karmpatel&lt;/a&gt;, and &lt;a class="mentioned-user" href="https://dev.to/thisaakash"&gt;@thisaakash&lt;/a&gt; for their collaboration.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>cloud</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Automating CPU and Memory Utilization Logging with Cron Jobs on Windows and Linux</title>
      <dc:creator>Rishi Vachhani</dc:creator>
      <pubDate>Fri, 14 Mar 2025 16:08:58 +0000</pubDate>
      <link>https://dev.to/vachhanirishi/automating-cpu-and-memory-utilization-logging-with-cron-jobs-on-windows-and-linux-2phl</link>
      <guid>https://dev.to/vachhanirishi/automating-cpu-and-memory-utilization-logging-with-cron-jobs-on-windows-and-linux-2phl</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Monitoring system performance is crucial for maintaining a healthy and efficient computing environment. In this guide, we will automate the logging of CPU and memory utilization every 15 minutes using scheduled tasks in Windows and cron jobs in Linux. We will also ensure that a new log file is created daily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This is Useful in Everyday Life
&lt;/h2&gt;

&lt;p&gt;Automating system monitoring can greatly simplify daily operations, especially for developers, system administrators, and IT professionals. Instead of manually checking system resource usage, automated logging allows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Early detection of performance issues&lt;/strong&gt; – Identify spikes in CPU or memory usage before they cause major slowdowns or crashes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Efficient troubleshooting&lt;/strong&gt; – Logs provide historical data, making it easier to diagnose and resolve performance problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better resource planning&lt;/strong&gt; – Analyze usage trends over time to optimize system resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Peace of mind&lt;/strong&gt; – Once set up, the script runs in the background without user intervention, ensuring continuous monitoring.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Setting Up the Python Script
&lt;/h2&gt;

&lt;p&gt;Before setting up the scheduled jobs, let's create a Python script that logs CPU and memory utilization.&lt;/p&gt;

&lt;h3&gt;
  
  
  Install Required Dependencies
&lt;/h3&gt;

&lt;p&gt;We will use the &lt;code&gt;psutil&lt;/code&gt; module to fetch CPU and memory utilization. If you haven't installed it yet, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;psutil
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python Script to Log System Utilization
&lt;/h3&gt;

&lt;p&gt;Create a script named &lt;code&gt;system_monitor.py&lt;/code&gt; with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;log_system_utilization&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;today&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;logs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makedirs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exist_ok&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;log_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu_memory_log_&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;today&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;cpu_usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cpu_percent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;memory_usage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;psutil&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;virtual_memory&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;percent&lt;/span&gt;
        &lt;span class="n"&gt;log_entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;timestamp&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; - CPU Usage: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;cpu_usage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;% | Memory Usage: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;memory_usage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;%&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;log_entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;log_system_utilization&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a log directory if it doesn’t exist.&lt;/li&gt;
&lt;li&gt;Generates a new log file daily.&lt;/li&gt;
&lt;li&gt;Logs CPU and memory usage every time it runs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scheduling the Script on Linux Using Cron Job
&lt;/h2&gt;

&lt;p&gt;In Linux, we use cron jobs to automate script execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Open the Crontab Editor
&lt;/h3&gt;

&lt;p&gt;Run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Add the Cron Job
&lt;/h3&gt;

&lt;p&gt;Add the following line at the end of the file to run the script every 15 minutes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="k"&gt;*&lt;/span&gt;/15 &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; /usr/bin/python3 /path/to/system_monitor.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;*/15&lt;/code&gt; → Runs every 15 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;* * * *&lt;/code&gt; → Runs every hour, day, month, and weekday.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/usr/bin/python3&lt;/code&gt; → Path to the Python interpreter.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;/path/to/system_monitor.py&lt;/code&gt; → Full path to the script.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 3: Save and Exit
&lt;/h3&gt;

&lt;p&gt;Save the file and exit. The cron job will now run every 15 minutes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Verify the Cron Job
&lt;/h3&gt;

&lt;p&gt;To list scheduled cron jobs, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;crontab &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Scheduling the Script on Windows Using Task Scheduler
&lt;/h2&gt;

&lt;p&gt;On Windows, we use Task Scheduler to automate the script execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Open Task Scheduler
&lt;/h3&gt;

&lt;p&gt;Press &lt;code&gt;Win + R&lt;/code&gt;, type &lt;code&gt;taskschd.msc&lt;/code&gt;, and hit Enter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Create a New Task
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Create Basic Task&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Name it "System Utilization Logger" and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 3: Set the Trigger
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;strong&gt;Daily&lt;/strong&gt; and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Set the start time to midnight and repeat every day.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 4: Set the Action
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Choose &lt;strong&gt;Start a Program&lt;/strong&gt; and click &lt;strong&gt;Next&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Browse to the Python executable (e.g., &lt;code&gt;C:\Python39\python.exe&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;In the &lt;strong&gt;Add arguments&lt;/strong&gt; field, enter the full path to &lt;code&gt;system_monitor.py&lt;/code&gt;, e.g.:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   "C:\path\to\system_monitor.py"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt; and then &lt;strong&gt;Finish&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 5: Modify Task to Run Every 15 Minutes
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Open &lt;strong&gt;Task Scheduler Library&lt;/strong&gt;, right-click the created task, and select &lt;strong&gt;Properties&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Go to the &lt;strong&gt;Triggers&lt;/strong&gt; tab and click &lt;strong&gt;Edit&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;Repeat task every 15 minutes&lt;/strong&gt; and &lt;strong&gt;Stop after 1 day&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;OK&lt;/strong&gt; and &lt;strong&gt;Apply&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Step 6: Test the Task
&lt;/h3&gt;

&lt;p&gt;Right-click the task and select &lt;strong&gt;Run&lt;/strong&gt; to ensure it executes correctly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By following this guide, you've successfully automated system monitoring on both Linux and Windows. The script now runs every 15 minutes, generating daily logs to track CPU and memory utilization. This setup helps in proactive system monitoring and can be further enhanced with alert mechanisms or cloud storage integrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  How This Makes Life Easier
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Saves Time &amp;amp; Effort:&lt;/strong&gt; No need to manually check system performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improves System Stability:&lt;/strong&gt; Prevent unexpected failures by analyzing logs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhances Troubleshooting:&lt;/strong&gt; Quickly identify patterns of high CPU/memory usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalable &amp;amp; Automated:&lt;/strong&gt; Works on any system without manual intervention.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this setup in place, you can focus on other important tasks while ensuring your system's performance is continuously monitored. 🚀&lt;/p&gt;

&lt;p&gt;Let me know in the comments if you have any questions or suggestions!&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/vikram_patel"&gt;@vikram_patel&lt;/a&gt; , &lt;a class="mentioned-user" href="https://dev.to/thisaakash"&gt;@thisaakash&lt;/a&gt; , &lt;a class="mentioned-user" href="https://dev.to/shreyansh_1904"&gt;@shreyansh_1904&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/karmpatel"&gt;@karmpatel&lt;/a&gt; Thanks for colloborations.&lt;/p&gt;

</description>
      <category>automation</category>
      <category>systemmonitoring</category>
      <category>performanceoptimization</category>
      <category>techtips</category>
    </item>
    <item>
      <title>Understanding Runlevels in Linux: A Complete Guide</title>
      <dc:creator>Rishi Vachhani</dc:creator>
      <pubDate>Sat, 08 Mar 2025 05:42:08 +0000</pubDate>
      <link>https://dev.to/vachhanirishi/understanding-runlevels-in-linux-a-complete-guide-2pbp</link>
      <guid>https://dev.to/vachhanirishi/understanding-runlevels-in-linux-a-complete-guide-2pbp</guid>
      <description>&lt;p&gt;Linux is a powerful and flexible operating system used in servers, embedded systems, and desktops worldwide. One of the essential components of Linux system administration is &lt;strong&gt;runlevels&lt;/strong&gt;. Runlevels define the state of a Linux system by controlling the services and processes that run at startup.&lt;/p&gt;

&lt;p&gt;Whether you’re troubleshooting boot issues or managing system services, understanding runlevels can significantly improve your Linux administration skills. In this blog, we’ll explore &lt;strong&gt;what runlevels are, where they are used, how to check the current runlevel, how to change it, and real-world use cases&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Are Runlevels in Linux?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;runlevel&lt;/strong&gt; in Linux is a mode of operation that determines what processes and services are active at a given time. Different runlevels are predefined for various system states, such as &lt;strong&gt;single-user mode, multi-user mode, or GUI mode&lt;/strong&gt;. Traditionally, runlevels range from &lt;strong&gt;0 to 6&lt;/strong&gt;, each serving a specific purpose.&lt;/p&gt;




&lt;h2&gt;
  
  
  Standard Runlevels in Linux
&lt;/h2&gt;

&lt;p&gt;The standard runlevels in &lt;strong&gt;SysVinit-based&lt;/strong&gt; Linux distributions are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Runlevel&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;Halt (Shutdown)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Single-user mode (Maintenance Mode)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Multi-user mode without network&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Full multi-user mode (CLI)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Unused (customizable)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;Multi-user mode with GUI&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Reboot&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;However, modern Linux distributions such as &lt;strong&gt;Ubuntu (16.04+), RHEL 7+, and CentOS 7+&lt;/strong&gt; have replaced &lt;strong&gt;SysVinit&lt;/strong&gt; with &lt;strong&gt;systemd&lt;/strong&gt;, where &lt;strong&gt;targets&lt;/strong&gt; are used instead of runlevels.&lt;/p&gt;




&lt;h2&gt;
  
  
  Where Are Runlevels Used?
&lt;/h2&gt;

&lt;p&gt;Runlevels are used in various scenarios, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System Boot Management&lt;/strong&gt; — Define what services should start during boot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Troubleshooting&lt;/strong&gt; — Switching to &lt;strong&gt;single-user mode (Runlevel 1)&lt;/strong&gt; helps in fixing critical system issues.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server Configurations&lt;/strong&gt; — Servers often run in &lt;strong&gt;Runlevel 3 (CLI mode)&lt;/strong&gt; to save resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GUI vs CLI Switching&lt;/strong&gt; — Users can switch between &lt;strong&gt;GUI (Runlevel 5)&lt;/strong&gt; and &lt;strong&gt;CLI (Runlevel 3)&lt;/strong&gt; as needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom System Modes&lt;/strong&gt; — &lt;strong&gt;Runlevel 4&lt;/strong&gt; (unused by default) can be customized for specific requirements.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Check the Current Runlevel?
&lt;/h2&gt;

&lt;p&gt;To check the current runlevel of your Linux system, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;runlevel
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Output:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;N 5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;N&lt;/code&gt; indicates there was no previous runlevel change, and &lt;code&gt;5&lt;/code&gt; represents the current runlevel (multi-user mode with GUI).&lt;/p&gt;

&lt;p&gt;For &lt;strong&gt;systemd-based distributions&lt;/strong&gt;, use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl get-default
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Example Output:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;graphical.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This corresponds to &lt;strong&gt;Runlevel 5&lt;/strong&gt; in &lt;strong&gt;SysVinit&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Change Runlevels in Linux?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  In SysVinit-based Systems
&lt;/h3&gt;

&lt;p&gt;To switch to a different runlevel &lt;strong&gt;temporarily&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;init &amp;lt;runlevel&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example, to switch to runlevel 3:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;init 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;telinit 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To &lt;strong&gt;change the default runlevel permanently&lt;/strong&gt;, edit the &lt;code&gt;/etc/inittab&lt;/code&gt; file and modify this line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;default:5:initdefault:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change &lt;code&gt;5&lt;/code&gt; to your desired runlevel and &lt;strong&gt;reboot&lt;/strong&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  In Systemd-based Systems
&lt;/h3&gt;

&lt;p&gt;To &lt;strong&gt;change the current runlevel (target)&lt;/strong&gt; in &lt;strong&gt;systemd-based systems&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl isolate multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To &lt;strong&gt;set a default runlevel (target)&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl set-default multi-user.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To &lt;strong&gt;switch back to GUI mode&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;systemctl isolate graphical.target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Real-Time Use Cases of Runlevels
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Recovering a Broken System&lt;/strong&gt; — Boot into &lt;strong&gt;single-user mode (Runlevel 1)&lt;/strong&gt; to fix misconfigured files or disk errors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Running a Server Efficiently&lt;/strong&gt; — Use &lt;strong&gt;Runlevel 3 (multi-user CLI mode)&lt;/strong&gt; to optimize performance by disabling GUI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Switching to Maintenance Mode&lt;/strong&gt; — If you need to perform updates or maintenance, temporarily move to &lt;strong&gt;Runlevel 1&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Troubleshooting Network Issues&lt;/strong&gt; — &lt;strong&gt;Runlevel 2 (no network)&lt;/strong&gt; helps isolate networking problems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automating Startup Services&lt;/strong&gt; — Customize runlevel scripts for specific startup configurations.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Understanding &lt;strong&gt;Linux runlevels&lt;/strong&gt; is crucial for &lt;strong&gt;system administrators and advanced users&lt;/strong&gt;. Whether you’re using an old &lt;strong&gt;SysVinit-based system&lt;/strong&gt; or a modern &lt;strong&gt;systemd-based one&lt;/strong&gt;, knowing how to &lt;strong&gt;check, change, and utilize runlevels&lt;/strong&gt; can improve system management.&lt;/p&gt;

&lt;p&gt;By mastering runlevels, you can &lt;strong&gt;efficiently manage services, troubleshoot issues, and optimize system performance&lt;/strong&gt;. Start experimenting with different runlevels today to enhance your Linux skills!&lt;/p&gt;




&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/vikram_patel"&gt;@vikram_patel&lt;/a&gt;, &lt;a class="mentioned-user" href="https://dev.to/thisaakash"&gt;@thisaakash&lt;/a&gt; , &lt;a class="mentioned-user" href="https://dev.to/shreyansh_1904"&gt;@shreyansh_1904&lt;/a&gt; Thanks for colloborations.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>sysadmins</category>
      <category>opensource</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Git Reset: Understanding and Using It Effectively</title>
      <dc:creator>Rishi Vachhani</dc:creator>
      <pubDate>Thu, 06 Mar 2025 16:14:34 +0000</pubDate>
      <link>https://dev.to/vachhanirishi/git-reset-understanding-and-using-it-effectively-4ja2</link>
      <guid>https://dev.to/vachhanirishi/git-reset-understanding-and-using-it-effectively-4ja2</guid>
      <description>&lt;p&gt;Git is a powerful Distributed Version Control System (DVCS) packed with commands that let developers manage their codebases efficiently. With its robust capabilities, Git provides flexibility for high-level operations while giving full access to its internals. It is fast, scalable, and an indispensable tool for modern development workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is Git Reset?
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;git reset&lt;/code&gt; is one of Git’s most versatile yet often misunderstood commands. It allows developers to undo changes at different levels of their repository. Depending on the options provided (&lt;code&gt;--soft&lt;/code&gt;, &lt;code&gt;--mixed&lt;/code&gt;, &lt;code&gt;--hard&lt;/code&gt;), it manipulates three key components of Git:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Commit Tree (HEAD):&lt;/strong&gt; Tracks the latest commit in the current branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Staging Index:&lt;/strong&gt; Where changes are prepared for a commit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Working Directory:&lt;/strong&gt; Reflects local files and modifications.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Each mode of &lt;code&gt;git reset&lt;/code&gt; changes these components in different ways.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Three Modes of Git Reset
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Soft Reset (&lt;code&gt;git reset --soft&lt;/code&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Moves the &lt;code&gt;HEAD&lt;/code&gt; pointer to the specified commit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Keeps all changes in the staging area and working directory untouched.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; When you want to modify or amend a commit without losing your staged changes.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; git reset &lt;span class="nt"&gt;--soft&lt;/span&gt; &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. Mixed Reset (&lt;code&gt;git reset --mixed&lt;/code&gt;) (default)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Moves the &lt;code&gt;HEAD&lt;/code&gt; pointer to the specified commit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Unstages changes but retains them in the working directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; When you need to re-stage or redo your commit preparation.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; git reset &lt;span class="nt"&gt;--mixed&lt;/span&gt; &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Hard Reset (&lt;code&gt;git reset --hard&lt;/code&gt;)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Moves the &lt;code&gt;HEAD&lt;/code&gt; pointer to the specified commit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Deletes all changes from both the staging area and the working directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use case:&lt;/strong&gt; When you want to discard all changes and return to a clean state.&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; &amp;lt;commit-hash&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How Git Reset Works Internally
&lt;/h2&gt;

&lt;p&gt;To understand how &lt;code&gt;git reset&lt;/code&gt; works, let’s look at the three core components of a Git repository:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;HEAD:&lt;/strong&gt; Points to the latest commit in the current branch.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Index:&lt;/strong&gt; The staging area for changes ready to be committed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Working Directory:&lt;/strong&gt; The local files and their current state.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Use Cases for Git Reset
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use &lt;code&gt;--soft&lt;/code&gt; for minor adjustments:&lt;/strong&gt; Great for tweaking or amending recent commits without losing any work.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stick to &lt;code&gt;--mixed&lt;/code&gt; for safe resets:&lt;/strong&gt; Less destructive since it preserves changes in the working directory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Be cautious with &lt;code&gt;--hard&lt;/code&gt;:&lt;/strong&gt; Only use it when you are sure you no longer need the uncommitted changes. Back up your work if necessary.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Avoid &lt;code&gt;git reset&lt;/code&gt; on shared branches:&lt;/strong&gt; Resetting history on shared branches can cause conflicts and confusion.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Leverage &lt;code&gt;git reflog&lt;/code&gt; for recovery:&lt;/strong&gt; If you reset to the wrong commit, &lt;code&gt;git reflog&lt;/code&gt; can help you recover lost references.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l4o6lnc0oxldgxwibr7.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6l4o6lnc0oxldgxwibr7.jpeg" alt="Work flow of Git reset" width="700" height="408"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Understanding &lt;code&gt;git reset&lt;/code&gt; is essential for managing code efficiently. Whether making small corrections, undoing staged changes, or completely resetting a repository, knowing when and how to use &lt;code&gt;git reset&lt;/code&gt; ensures a smooth development workflow.&lt;/p&gt;

&lt;p&gt;By mastering &lt;code&gt;git reset&lt;/code&gt;, developers can confidently navigate version history, fix mistakes, and optimize their Git experience.&lt;/p&gt;

&lt;p&gt;&lt;a class="mentioned-user" href="https://dev.to/vikram_patel"&gt;@vikram_patel&lt;/a&gt; , &lt;a class="mentioned-user" href="https://dev.to/thisaakash"&gt;@thisaakash&lt;/a&gt; , &lt;a class="mentioned-user" href="https://dev.to/shreyansh_1904"&gt;@shreyansh_1904&lt;/a&gt; Thanks for collaborations.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>github</category>
      <category>development</category>
      <category>git</category>
    </item>
  </channel>
</rss>
