diff --git a/README.md b/README.md
index 7c2fbb829..79713de36 100644
--- a/README.md
+++ b/README.md
@@ -25,6 +25,7 @@ We recommend cid-cmd tool via [AWS CloudShell](https://console.aws.amazon.com/cl
 | [Cost Anomaly Dashboard](https://catalog.workshops.aws/awscid/en-US/dashboards/advanced/cost-anomaly) | [demo](https://cid.workshops.aws.dev/demo?dashboard=aws-cost-anomalies) | [link](https://catalog.workshops.aws/awscid/en-US/dashboards/advanced/cost-anomaly/prerequisites) |
 | [Data Transfer Cost Dashboard](https://catalog.workshops.aws/awscid/en-US/dashboards/additional/data-transfer) | [demo](https://cid.workshops.aws.dev/demo?dashboard=datatransfer-cost-analysis-dashboard) | [link](https://catalog.workshops.aws/awscid/en-US/dashboards/foundational/cudos-cid-kpi/deploy) (Steps 1 and 2) |
 | [AWS Budgets Dashboard](https://catalog.workshops.aws/awscid/en-US/dashboards/advanced/aws-budgets) | [demo](https://cid.workshops.aws.dev/demo?dashboard=aws-budgets) | [link](https://catalog.workshops.aws/awscid/en-US/dashboards/advanced/aws-budgets#deploy-via-cid-tool) |
+| [Cost Forecast Dashboard](https://catalog.workshops.aws/awscid/en-US/dashboards/advanced/cost-forecast) | [demo](https://cid.workshops.aws.dev/demo?dashboard=cost-forecast-dashboard) | [link](https://catalog.workshops.aws/awscid/en-US/dashboards/advanced/cost-forecast#deploy-via-cid-tool) |
 
 See more dashboards on the [workshop page](https://catalog.workshops.aws/awscid/en-US/dashboards).
 
diff --git a/cfn-templates/cost-forecast-dashboard.yaml b/cfn-templates/cost-forecast-dashboard.yaml
new file mode 100644
index 000000000..336485f1b
--- /dev/null
+++ b/cfn-templates/cost-forecast-dashboard.yaml
@@ -0,0 +1,331 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Description: 'AWS Cost Forecast Dashboard - Visualize AWS Cost Explorer forecasts to predict future spending'
+
+Parameters:
+  QuickSightUserName:
+    Type: String
+    Description: QuickSight user name
+    Default: ''
+  
+  QuickSightIdentityRegion:
+    Type: String
+    Description: QuickSight identity region
+    Default: 'us-east-1'
+  
+  AthenaDatabase:
+    Type: String
+    Description: Athena database name
+    Default: 'athenacurcfn_cost_forecast'
+  
+  AthenaWorkGroup:
+    Type: String
+    Description: Athena workgroup name
+    Default: 'primary'
+  
+  CURTableName:
+    Type: String
+    Description: CUR table name
+    Default: 'cost_and_usage_report'
+  
+  ForecastTableName:
+    Type: String
+    Description: Forecast data table name
+    Default: 'cost_forecast_data'
+  
+  S3BucketName:
+    Type: String
+    Description: S3 bucket name for forecast data
+    Default: ''
+  
+  QuickSightTheme:
+    Type: String
+    Description: QuickSight theme
+    Default: 'MIDNIGHT'
+    AllowedValues:
+      - 'CLASSIC'
+      - 'MIDNIGHT'
+      - 'SEASIDE'
+      - 'RAINIER'
+
+Resources:
+  CostForecastLambdaRole:
+    Type: AWS::IAM::Role
+    Properties:
+      AssumeRolePolicyDocument:
+        Version: '2012-10-17'
+        Statement:
+          - Effect: Allow
+            Principal:
+              Service: lambda.amazonaws.com
+            Action: sts:AssumeRole
+      ManagedPolicyArns:
+        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
+      Policies:
+        - PolicyName: CostExplorerAccess
+          PolicyDocument:
+            Version: '2012-10-17'
+            Statement:
+              - Effect: Allow
+                Action:
+                  - ce:GetCostForecast
+                  - ce:GetDimensionValues
+                Resource: '*'
+        - PolicyName: S3Access
+          PolicyDocument:
+            Version: '2012-10-17'
+            Statement:
+              - Effect: Allow
+                Action:
+                  - s3:PutObject
+                  - s3:GetObject
+                  - s3:ListBucket
+                Resource:
+                  - !Sub 'arn:aws:s3:::${S3BucketName}'
+                  - !Sub 'arn:aws:s3:::${S3BucketName}/*'
+        - PolicyName: AthenaAccess
+          PolicyDocument:
+            Version: '2012-10-17'
+            Statement:
+              - Effect: Allow
+                Action:
+                  - athena:StartQueryExecution
+                  - athena:GetQueryExecution
+                  - athena:GetQueryResults
+                Resource: '*'
+              - Effect: Allow
+                Action:
+                  - glue:CreateTable
+                  - glue:GetTable
+                  - glue:GetTables
+                  - glue:UpdateTable
+                Resource: '*'
+
+  CostForecastFunction:
+    Type: AWS::Lambda::Function
+    Properties:
+      Handler: index.handler
+      Role: !GetAtt CostForecastLambdaRole.Arn
+      Runtime: python3.9
+      Timeout: 300
+      MemorySize: 256
+      Environment:
+        Variables:
+          S3_BUCKET: !Ref S3BucketName
+          ATHENA_DATABASE: !Ref AthenaDatabase
+          ATHENA_WORKGROUP: !Ref AthenaWorkGroup
+          FORECAST_TABLE: !Ref ForecastTableName
+      Code:
+        ZipFile: |
+          import boto3
+          import json
+          import os
+          import csv
+          import datetime
+          import time
+          from io import StringIO
+
+          def handler(event, context):
+              # Configuration
+              s3_bucket = os.environ['S3_BUCKET']
+              athena_database = os.environ['ATHENA_DATABASE']
+              athena_workgroup = os.environ['ATHENA_WORKGROUP']
+              forecast_table = os.environ['FORECAST_TABLE']
+              
+              # Initialize clients
+              ce_client = boto3.client('ce')
+              s3_client = boto3.client('s3')
+              athena_client = boto3.client('athena')
+              
+              # Get parameters from event or use defaults
+              time_period = event.get('time_period', 30)
+              metrics = event.get('metrics', ['UNBLENDED_COST'])
+              dimensions = event.get('dimensions', ['SERVICE'])
+              granularity = event.get('granularity', 'MONTHLY')
+              
+              # Calculate time period
+              today = datetime.date.today()
+              start_date = today.strftime('%Y-%m-%d')
+              
+              if isinstance(time_period, int):
+                  end_date = (today + datetime.timedelta(days=time_period)).strftime('%Y-%m-%d')
+              else:
+                  end_date = time_period
+              
+              # Prepare CSV output
+              csv_output = StringIO()
+              csv_writer = csv.writer(csv_output)
+              csv_writer.writerow(['Dimension', 'Value', 'Metric', 'StartDate', 'EndDate', 'MeanValue', 'LowerBound', 'UpperBound'])
+              
+              # Process each dimension
+              for dimension in dimensions:
+                  # Get dimension values
+                  dimension_values_response = ce_client.get_dimension_values(
+                      TimePeriod={
+                          'Start': (today - datetime.timedelta(days=30)).strftime('%Y-%m-%d'),
+                          'End': today.strftime('%Y-%m-%d')
+                      },
+                      Dimension=dimension
+                  )
+                  
+                  dimension_values = [item['Value'] for item in dimension_values_response.get('DimensionValues', [])]
+                  
+                  # For each dimension value, get forecast for each metric
+                  for value in dimension_values:
+                      for metric in metrics:
+                          try:
+                              forecast_response = ce_client.get_cost_forecast(
+                                  TimePeriod={
+                                      'Start': start_date,
+                                      'End': end_date
+                                  },
+                                  Metric=metric,
+                                  Granularity=granularity,
+                                  PredictionIntervalLevel=95,
+                                  Filter={
+                                      "Dimensions": {
+                                          "Key": dimension,
+                                          "Values": [value]
+                                      }
+                                  }
+                              )
+                              
+                              # Process forecast results
+                              for result in forecast_response.get('ForecastResultsByTime', []):
+                                  row = [
+                                      dimension,
+                                      value,
+                                      metric,
+                                      result['TimePeriod']['Start'],
+                                      result['TimePeriod']['End'],
+                                      result['MeanValue'],
+                                      result.get('PredictionIntervalLowerBound', ''),
+                                      result.get('PredictionIntervalUpperBound', '')
+                                  ]
+                                  csv_writer.writerow(row)
+                          except Exception as e:
+                              print(f"Error getting forecast for {dimension}={value}, metric={metric}: {str(e)}")
+                              continue
+              
+              # Upload CSV to S3
+              timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
+              s3_key = f"forecasts/forecast_{timestamp}.csv"
+              s3_client.put_object(
+                  Bucket=s3_bucket,
+                  Key=s3_key,
+                  Body=csv_output.getvalue(),
+                  ContentType='text/csv'
+              )
+              
+              # Create manifest file for QuickSight
+              manifest = {
+                  "fileLocations": [
+                      {
+                          "URIs": [
+                              f"s3://{s3_bucket}/{s3_key}"
+                          ]
+                      }
+                  ],
+                  "globalUploadSettings": {
+                      "format": "CSV",
+                      "delimiter": ",",
+                      "textqualifier": "\"",
+                      "containsHeader": "true"
+                  }
+              }
+              
+              manifest_key = "forecasts/manifest.json"
+              s3_client.put_object(
+                  Bucket=s3_bucket,
+                  Key=manifest_key,
+                  Body=json.dumps(manifest, indent=4),
+                  ContentType='application/json'
+              )
+              
+              # Create or update Athena table
+              create_table_query = f"""
+              CREATE EXTERNAL TABLE IF NOT EXISTS {athena_database}.{forecast_table} (
+                  dimension string,
+                  value string,
+                  metric string,
+                  startdate string,
+                  enddate string,
+                  meanvalue double,
+                  lowerbound double,
+                  upperbound double
+              )
+              ROW FORMAT DELIMITED
+              FIELDS TERMINATED BY ','
+              STORED AS TEXTFILE
+              LOCATION 's3://{s3_bucket}/forecasts/'
+              TBLPROPERTIES ('skip.header.line.count'='1')
+              """
+              
+              response = athena_client.start_query_execution(
+                  QueryString=create_table_query,
+                  QueryExecutionContext={
+                      'Database': athena_database
+                  },
+                  WorkGroup=athena_workgroup
+              )
+              
+              # Wait for query to complete
+              query_execution_id = response['QueryExecutionId']
+              state = 'RUNNING'
+              
+              while state in ['RUNNING', 'QUEUED']:
+                  response = athena_client.get_query_execution(QueryExecutionId=query_execution_id)
+                  state = response['QueryExecution']['Status']['State']
+                  
+                  if state in ['RUNNING', 'QUEUED']:
+                      time.sleep(1)
+              
+              return {
+                  'statusCode': 200,
+                  'body': json.dumps({
+                      'message': 'Forecast data processed successfully',
+                      'csv_location': f"s3://{s3_bucket}/{s3_key}",
+                      'manifest_location': f"s3://{s3_bucket}/{manifest_key}"
+                  })
+              }
+
+  CostForecastScheduledRule:
+    Type: AWS::Events::Rule
+    Properties:
+      Description: "Scheduled rule to trigger cost forecast generation"
+      ScheduleExpression: "rate(7 days)"
+      State: "ENABLED"
+      Targets:
+        - Arn: !GetAtt CostForecastFunction.Arn
+          Id: "CostForecastFunction"
+          Input: !Sub |
+            {
+              "time_period": 90,
+              "metrics": ["UNBLENDED_COST"],
+              "dimensions": ["SERVICE", "LINKED_ACCOUNT", "REGION"],
+              "granularity": "MONTHLY"
+            }
+
+  PermissionForEventsToInvokeLambda:
+    Type: AWS::Lambda::Permission
+    Properties:
+      FunctionName: !Ref CostForecastFunction
+      Action: "lambda:InvokeFunction"
+      Principal: "events.amazonaws.com"
+      SourceArn: !GetAtt CostForecastScheduledRule.Arn
+
+Outputs:
+  CostForecastFunction:
+    Description: "Lambda function for cost forecast generation"
+    Value: !GetAtt CostForecastFunction.Arn
+  
+  S3BucketForForecastData:
+    Description: "S3 bucket for forecast data"
+    Value: !Ref S3BucketName
+  
+  ManifestLocation:
+    Description: "QuickSight manifest location"
+    Value: !Sub "s3://${S3BucketName}/forecasts/manifest.json"
+  
+  DeployDashboardCommand:
+    Description: "Command to deploy the dashboard using cid-cmd"
+    Value: !Sub "cid-cmd deploy --dashboard-id cost-forecast-dashboard"
diff --git a/cid/builtin/core/__init__.py b/cid/builtin/core/__init__.py
index fdacb785d..0c3031b0d 100644
--- a/cid/builtin/core/__init__.py
+++ b/cid/builtin/core/__init__.py
@@ -1 +1,33 @@
 # This plugin implements Core dashboards
+
+def provides():
+    return {
+        'views': {
+            'account_map': {
+                'name': 'Account Map',
+                'providedBy': 'cid.builtin.core',
+                'File': 'queries/shared/account_map.sql',
+            },
+            'cost_forecast': {
+                'name': 'Cost Forecast View',
+                'providedBy': 'cid.builtin.core',
+                'File': 'queries/forecast/cost_forecast_view.sql',
+                'parameters': {
+                    'forecast_table_name': {
+                        'description': 'Name of the table containing forecast data',
+                        'default': 'cost_forecast_data'
+                    }
+                }
+            },
+        },
+        'datasets': {
+            'cost_forecast_dataset': {
+                'name': 'Cost Forecast Dataset',
+                'providedBy': 'cid.builtin.core',
+                'File': 'datasets/forecast/cost_forecast_dataset.json',
+                'dependsOn': {
+                    'views': ['cost_forecast']
+                }
+            }
+        }
+    }
diff --git a/cid/builtin/core/data/datasets/forecast/cost_forecast_dataset.json b/cid/builtin/core/data/datasets/forecast/cost_forecast_dataset.json
new file mode 100644
index 000000000..9ae7bf1c3
--- /dev/null
+++ b/cid/builtin/core/data/datasets/forecast/cost_forecast_dataset.json
@@ -0,0 +1,108 @@
+{
+  "DataSetId": "cost-forecast-dataset",
+  "Name": "Cost Forecast Dataset",
+  "PhysicalTableMap": {
+    "cost-forecast-table": {
+      "CustomSql": {
+        "DataSourceArn": "${athena_datasource_arn}",
+        "Name": "Cost Forecast",
+        "SqlQuery": "SELECT dimension, value, metric, start_date, end_date, mean_value, lower_bound, upper_bound, metric_name, dimension_name FROM ${athena_database_name}.cost_forecast",
+        "Columns": [
+          {
+            "Name": "dimension",
+            "Type": "STRING"
+          },
+          {
+            "Name": "value",
+            "Type": "STRING"
+          },
+          {
+            "Name": "metric",
+            "Type": "STRING"
+          },
+          {
+            "Name": "start_date",
+            "Type": "DATETIME"
+          },
+          {
+            "Name": "end_date",
+            "Type": "DATETIME"
+          },
+          {
+            "Name": "mean_value",
+            "Type": "DECIMAL"
+          },
+          {
+            "Name": "lower_bound",
+            "Type": "DECIMAL"
+          },
+          {
+            "Name": "upper_bound",
+            "Type": "DECIMAL"
+          },
+          {
+            "Name": "metric_name",
+            "Type": "STRING"
+          },
+          {
+            "Name": "dimension_name",
+            "Type": "STRING"
+          }
+        ]
+      }
+    }
+  },
+  "LogicalTableMap": {
+    "cost-forecast-logical-table": {
+      "Alias": "cost_forecast",
+      "DataTransforms": [
+        {
+          "CreateColumnsOperation": {
+            "Columns": [
+              {
+                "ColumnName": "forecast_range",
+                "ColumnId": "forecast_range",
+                "Expression": "ifelse(datediff(end_date, start_date) <= 1, 'Daily', 'Monthly')"
+              },
+              {
+                "ColumnName": "variance",
+                "ColumnId": "variance",
+                "Expression": "upper_bound - lower_bound"
+              },
+              {
+                "ColumnName": "variance_percentage",
+                "ColumnId": "variance_percentage",
+                "Expression": "ifelse(mean_value = 0, 0, (upper_bound - lower_bound) / mean_value * 100)"
+              },
+              {
+                "ColumnName": "confidence_level",
+                "ColumnId": "confidence_level",
+                "Expression": "ifelse(variance_percentage < 10, 'High', ifelse(variance_percentage < 25, 'Medium', 'Low'))"
+              },
+              {
+                "ColumnName": "forecast_month",
+                "ColumnId": "forecast_month",
+                "Expression": "formatDate(start_date, 'yyyy-MM')"
+              },
+              {
+                "ColumnName": "forecast_quarter",
+                "ColumnId": "forecast_quarter",
+                "Expression": "concat('Q', toString(quarter(start_date)), ' ', toString(year(start_date)))"
+              },
+              {
+                "ColumnName": "trend_indicator",
+                "ColumnId": "trend_indicator",
+                "Expression": "runningSum(mean_value)"
+              }
+            ]
+          }
+        }
+      ],
+      "Source": {
+        "PhysicalTableId": "cost-forecast-table"
+      }
+    }
+  },
+  "ImportMode": "DIRECT_QUERY",
+  "Permissions": []
+}
diff --git a/cid/builtin/core/data/queries/forecast/cost_forecast_view.sql b/cid/builtin/core/data/queries/forecast/cost_forecast_view.sql
new file mode 100644
index 000000000..9212fbcc0
--- /dev/null
+++ b/cid/builtin/core/data/queries/forecast/cost_forecast_view.sql
@@ -0,0 +1,61 @@
+-- Create a view for cost forecast data
+CREATE OR REPLACE VIEW ${athena_database_name}.cost_forecast AS
+SELECT 
+    dimension,
+    value,
+    metric,
+    CAST(startdate AS date) AS start_date,
+    CAST(enddate AS date) AS end_date,
+    CAST(meanvalue AS decimal(18,4)) AS mean_value,
+    CAST(lowerbound AS decimal(18,4)) AS lower_bound,
+    CAST(upperbound AS decimal(18,4)) AS upper_bound,
+    CASE 
+        WHEN metric = 'UNBLENDED_COST' THEN 'Unblended Cost'
+        WHEN metric = 'BLENDED_COST' THEN 'Blended Cost'
+        WHEN metric = 'AMORTIZED_COST' THEN 'Amortized Cost'
+        WHEN metric = 'NET_UNBLENDED_COST' THEN 'Net Unblended Cost'
+        WHEN metric = 'NET_AMORTIZED_COST' THEN 'Net Amortized Cost'
+        WHEN metric = 'USAGE_QUANTITY' THEN 'Usage Quantity'
+        WHEN metric = 'NORMALIZED_USAGE_AMOUNT' THEN 'Normalized Usage'
+        ELSE metric
+    END AS metric_name,
+    CASE
+        WHEN dimension = 'SERVICE' THEN 'AWS Service'
+        WHEN dimension = 'LINKED_ACCOUNT' THEN 'Account ID'
+        WHEN dimension = 'LINKED_ACCOUNT_NAME' THEN 'Account Name'
+        WHEN dimension = 'REGION' THEN 'Region'
+        WHEN dimension = 'USAGE_TYPE' THEN 'Usage Type'
+        WHEN dimension = 'INSTANCE_TYPE' THEN 'Instance Type'
+        WHEN dimension = 'OPERATION' THEN 'Operation'
+        WHEN dimension = 'PURCHASE_TYPE' THEN 'Purchase Type'
+        WHEN dimension = 'AZ' THEN 'Availability Zone'
+        WHEN dimension = 'RECORD_TYPE' THEN 'Record Type'
+        WHEN dimension = 'OPERATING_SYSTEM' THEN 'Operating System'
+        WHEN dimension = 'TENANCY' THEN 'Tenancy'
+        WHEN dimension = 'SCOPE' THEN 'Scope'
+        WHEN dimension = 'PLATFORM' THEN 'Platform'
+        WHEN dimension = 'SUBSCRIPTION_ID' THEN 'Subscription ID'
+        WHEN dimension = 'LEGAL_ENTITY_NAME' THEN 'Legal Entity'
+        WHEN dimension = 'DEPLOYMENT_OPTION' THEN 'Deployment Option'
+        WHEN dimension = 'DATABASE_ENGINE' THEN 'Database Engine'
+        WHEN dimension = 'INSTANCE_TYPE_FAMILY' THEN 'Instance Family'
+        WHEN dimension = 'BILLING_ENTITY' THEN 'Billing Entity'
+        WHEN dimension = 'RESERVATION_ID' THEN 'Reservation ID'
+        WHEN dimension = 'SAVINGS_PLAN_ARN' THEN 'Savings Plan ARN'
+        ELSE dimension
+    END AS dimension_name,
+    -- Additional derived fields for enhanced analytics
+    CAST(upperbound - lowerbound AS decimal(18,4)) AS forecast_variance,
+    CASE 
+        WHEN meanvalue = 0 THEN 0
+        ELSE CAST(((upperbound - lowerbound) / meanvalue * 100) AS decimal(18,2))
+    END AS confidence_percentage,
+    CASE
+        WHEN (upperbound - lowerbound) / NULLIF(meanvalue, 0) * 100 < 10 THEN 'High Confidence'
+        WHEN (upperbound - lowerbound) / NULLIF(meanvalue, 0) * 100 < 25 THEN 'Medium Confidence'
+        ELSE 'Low Confidence'
+    END AS confidence_level,
+    DATE_FORMAT(CAST(startdate AS date), '%Y-%m') AS forecast_month,
+    CONCAT('Q', CAST(EXTRACT(QUARTER FROM CAST(startdate AS date)) AS VARCHAR), ' ', CAST(EXTRACT(YEAR FROM CAST(startdate AS date)) AS VARCHAR)) AS forecast_quarter,
+    EXTRACT(YEAR FROM CAST(startdate AS date)) AS forecast_year
+FROM ${forecast_table_name}
diff --git a/cid/cli.py b/cid/cli.py
index 48813ffb6..2fb0c113f 100644
--- a/cid/cli.py
+++ b/cid/cli.py
@@ -298,6 +298,23 @@ def teardown(ctx, **kwargs):
 
     ctx.obj.teardown(**kwargs)
 
+@click.option('-v', '--verbose', count=True)
+@click.option('-y', '--yes', help='confirm all', is_flag=True, default=False)
+@cid_command
+def forecast(ctx, **kwargs):
+    """Generate AWS Cost Explorer forecasts
+
+    \b
+    Command options:
+     --time-period TEXT                    Time period for forecast (30, 90, 180, 365 days or custom)
+     --end-date TEXT                       End date for custom time period (YYYY-MM-DD)
+     --metrics TEXT                        Comma-separated list of metrics to forecast
+     --dimensions TEXT                     Comma-separated list of dimensions to forecast
+     --granularity TEXT                    Granularity of forecast (DAILY or MONTHLY)
+     --s3-bucket TEXT                      S3 bucket to upload results
+    """
+    ctx.obj.forecast(**kwargs)
+
 if __name__ == '__main__':
     main()
 
diff --git a/cid/commands/__init__.py b/cid/commands/__init__.py
index f2369526a..6b79e8bc6 100644
--- a/cid/commands/__init__.py
+++ b/cid/commands/__init__.py
@@ -1,4 +1,5 @@
 # flake8: noqa: E401
 from cid.commands.init_qs import InitQsCommand
+from cid.commands.forecast import ForecastCommand
 
 
diff --git a/cid/commands/forecast.py b/cid/commands/forecast.py
new file mode 100644
index 000000000..477b68797
--- /dev/null
+++ b/cid/commands/forecast.py
@@ -0,0 +1,387 @@
+import os
+import json
+import logging
+import datetime
+import tempfile
+import csv
+from pathlib import Path
+from typing import List, Dict, Any, Optional
+
+from cid.commands.command_base import CommandBase
+from cid.utils import get_parameter, get_parameters, set_parameters, cid_print
+
+logger = logging.getLogger(__name__)
+
+class ForecastCommand(CommandBase):
+    """Command to generate AWS Cost Explorer forecasts"""
+
+    def __init__(self, cid, **kwargs):
+        super().__init__(cid, **kwargs)
+        self.timestamp = datetime.datetime.now().strftime('%Y%m%d_%H%M%S')
+        self.output_dir = os.path.join(os.getcwd(), 'output', self.timestamp)
+        self.temp_dir = os.path.join(self.output_dir, 'temp')
+        self.output_file = os.path.join(self.output_dir, f'forecast_{self.timestamp}.csv')
+        
+        # Available metrics for Cost Explorer forecasts
+        self.metrics = [
+            "AMORTIZED_COST",
+            "BLENDED_COST",
+            "NET_AMORTIZED_COST",
+            "NET_UNBLENDED_COST",
+            "UNBLENDED_COST",
+            "USAGE_QUANTITY",
+            "NORMALIZED_USAGE_AMOUNT"
+        ]
+        
+        # Available dimensions for Cost Explorer forecasts
+        self.dimensions = [
+            "AZ",
+            "INSTANCE_TYPE",
+            "LINKED_ACCOUNT",
+            "LINKED_ACCOUNT_NAME",
+            "OPERATION",
+            "PURCHASE_TYPE",
+            "REGION",
+            "SERVICE",
+            "USAGE_TYPE",
+            "USAGE_TYPE_GROUP",
+            "RECORD_TYPE",
+            "OPERATING_SYSTEM",
+            "TENANCY",
+            "SCOPE",
+            "PLATFORM",
+            "SUBSCRIPTION_ID",
+            "LEGAL_ENTITY_NAME",
+            "DEPLOYMENT_OPTION",
+            "DATABASE_ENGINE",
+            "INSTANCE_TYPE_FAMILY",
+            "BILLING_ENTITY",
+            "RESERVATION_ID",
+            "SAVINGS_PLAN_ARN"
+        ]
+        
+        # Create output directories
+        os.makedirs(self.output_dir, exist_ok=True)
+        os.makedirs(self.temp_dir, exist_ok=True)
+
+    def execute(self) -> None:
+        """Execute the forecast command"""
+        cid_print("AWS Cost Forecast Data Fetch Tool")
+        
+        # Get time period
+        self._get_time_period()
+        
+        # Select metrics, dimensions, and granularity
+        self._select_options()
+        
+        # Process forecast
+        cid_print("\nProcessing Forecasts\n")
+        self._process_forecast()
+        
+        # Upload to S3 if requested
+        self._upload_to_s3()
+        
+        # Generate QuickSight manifest if uploaded to S3
+        if get_parameters().get('s3-bucket'):
+            self._generate_quicksight_manifest()
+        
+        # Clean up temporary files
+        self._cleanup()
+
+    def _get_time_period(self) -> None:
+        """Get the time period for the forecast"""
+        cid_print("Time Period Selection")
+        
+        choice = get_parameter(
+            param_name='time-period',
+            message="Select Time Period",
+            choices={
+                "Next 30 days": "30",
+                "Next 90 days": "90",
+                "Next 180 days": "180",
+                "Next 365 days": "365",
+                "Custom period": "custom"
+            },
+            default="30"
+        )
+        
+        today = datetime.date.today().strftime('%Y-%m-%d')
+        self.start_date = today
+        
+        if choice == "custom":
+            self.end_date = get_parameter(
+                param_name='end-date',
+                message="Enter end date (YYYY-MM-DD)",
+                default=(datetime.date.today() + datetime.timedelta(days=30)).strftime('%Y-%m-%d')
+            )
+        else:
+            days = int(choice)
+            self.end_date = (datetime.date.today() + datetime.timedelta(days=days)).strftime('%Y-%m-%d')
+        
+        self.time_period = f"Start={self.start_date},End={self.end_date}"
+        cid_print(f"Time period set: {self.start_date} to {self.end_date}")
+
+    def _select_options(self) -> None:
+        """Select metrics, dimensions, and granularity"""
+        cid_print("Metric Selection")
+        
+        # Select metrics
+        metric_choices = {"All metrics": "all"}
+        for i, metric in enumerate(self.metrics):
+            metric_choices[metric] = metric
+        
+        metric_selection = get_parameter(
+            param_name='metrics',
+            message="Select metrics (comma-separated for multiple)",
+            choices=metric_choices,
+            default="UNBLENDED_COST"
+        )
+        
+        if metric_selection == "all":
+            self.selected_metrics = self.metrics
+        else:
+            self.selected_metrics = [m.strip() for m in metric_selection.split(',')]
+        
+        cid_print(f"Selected {len(self.selected_metrics)} metrics")
+        
+        # Select dimensions
+        cid_print("Dimension Selection")
+        
+        dimension_choices = {"All dimensions": "all"}
+        for i, dimension in enumerate(self.dimensions):
+            dimension_choices[dimension] = dimension
+        
+        dimension_selection = get_parameter(
+            param_name='dimensions',
+            message="Select dimensions (comma-separated for multiple)",
+            choices=dimension_choices,
+            default="SERVICE"
+        )
+        
+        if dimension_selection == "all":
+            self.selected_dimensions = self.dimensions
+        else:
+            self.selected_dimensions = [d.strip() for d in dimension_selection.split(',')]
+        
+        cid_print(f"Selected {len(self.selected_dimensions)} dimensions")
+        
+        # Select granularity
+        cid_print("Granularity Selection")
+        
+        self.granularity = get_parameter(
+            param_name='granularity',
+            message="Select Granularity",
+            choices={"DAILY": "DAILY", "MONTHLY": "MONTHLY"},
+            default="MONTHLY"
+        )
+        
+        cid_print(f"Selected {self.granularity} granularity")
+
+    def _get_dimension_values(self, dimension: str) -> List[str]:
+        """Get values for a specific dimension"""
+        cid_print(f"Fetching values for dimension: {dimension}")
+        
+        try:
+            response = self.cid.base.session.client('ce').get_dimension_values(
+                TimePeriod={
+                    'Start': (datetime.date.today() - datetime.timedelta(days=30)).strftime('%Y-%m-%d'),
+                    'End': datetime.date.today().strftime('%Y-%m-%d')
+                },
+                Dimension=dimension
+            )
+            
+            values = [item['Value'] for item in response.get('DimensionValues', [])]
+            return values
+        except Exception as e:
+            logger.warning(f"Failed to fetch dimension values for {dimension}: {str(e)}")
+            return []
+
+    def _fetch_forecast(self, dimension: str, value: str, metric: str) -> None:
+        """Fetch forecast for a specific dimension, value, and metric"""
+        output_file = os.path.join(self.temp_dir, f"{dimension}_{value.replace('/', '_')}_{metric}.json")
+        
+        filter_json = {
+            "Dimensions": {
+                "Key": dimension,
+                "Values": [value]
+            }
+        }
+        
+        try:
+            response = self.cid.base.session.client('ce').get_cost_forecast(
+                TimePeriod={
+                    'Start': self.start_date,
+                    'End': self.end_date
+                },
+                Metric=metric,
+                Granularity=self.granularity,
+                PredictionIntervalLevel=95,
+                Filter=filter_json
+            )
+            
+            with open(output_file, 'w') as f:
+                json.dump(response, f)
+            
+            # Process the response and append to the output file
+            with open(f"{self.output_file}.tmp", 'a') as out_file:
+                for result in response.get('ForecastResultsByTime', []):
+                    row = [
+                        dimension,
+                        value,
+                        metric,
+                        result['TimePeriod']['Start'],
+                        result['TimePeriod']['End'],
+                        result['MeanValue'],
+                        result.get('PredictionIntervalLowerBound', ''),
+                        result.get('PredictionIntervalUpperBound', '')
+                    ]
+                    out_file.write(','.join([str(item) for item in row]) + '\n')
+            
+            # Remove the temporary JSON file
+            os.remove(output_file)
+            
+        except Exception as e:
+            logger.warning(f"Failed to fetch forecast for {dimension}={value}, metric={metric}: {str(e)}")
+
+    def _process_forecast(self) -> None:
+        """Process forecasts in parallel using boto3 client"""
+        # Create header for the output file
+        with open(self.output_file, 'w') as f:
+            f.write("Dimension,Value,Metric,StartDate,EndDate,MeanValue,LowerBound,UpperBound\n")
+        
+        # Create temporary file for results
+        with open(f"{self.output_file}.tmp", 'w'):
+            pass  # Just create an empty file
+        
+        # Calculate total jobs
+        total_jobs = 0
+        dimension_values = {}
+        
+        for dimension in self.selected_dimensions:
+            values = self._get_dimension_values(dimension)
+            dimension_values[dimension] = values
+            value_count = len(values)
+            dimension_total = value_count * len(self.selected_metrics)
+            total_jobs += dimension_total
+            
+            cid_print(f"Found {value_count} values for {dimension}, adding {dimension_total} jobs")
+        
+        cid_print(f"Total jobs to process: {total_jobs}")
+        
+        # Process forecasts
+        completed_jobs = 0
+        
+        for dimension in self.selected_dimensions:
+            cid_print(f"Processing dimension: {dimension}")
+            
+            for value in dimension_values[dimension]:
+                for metric in self.selected_metrics:
+                    self._fetch_forecast(dimension, value, metric)
+                    completed_jobs += 1
+                    progress = int(completed_jobs * 100 / total_jobs)
+                    self._display_progress(progress, "Processing forecasts")
+        
+        # Combine results
+        if os.path.exists(f"{self.output_file}.tmp"):
+            with open(f"{self.output_file}.tmp", 'r') as tmp_file:
+                with open(self.output_file, 'a') as out_file:
+                    out_file.write(tmp_file.read())
+            os.remove(f"{self.output_file}.tmp")
+            cid_print("\nData collection completed")
+        else:
+            cid_print("\nNo data was collected")
+
+    def _display_progress(self, progress: int, text: str) -> None:
+        """Display progress bar"""
+        width = 40
+        filled = int(progress * width / 100)
+        empty = width - filled
+        
+        bar = '█' * filled + '░' * empty
+        cid_print(f"\r\033[0;36m{text}: [{bar}] {progress}%\033[0m", end='')
+
+    def _upload_to_s3(self) -> None:
+        """Upload results to S3"""
+        cid_print("\nS3 Upload")
+        
+        s3_bucket = get_parameter(
+            param_name='s3-bucket',
+            message="Enter S3 bucket name (or press Enter to skip)",
+            default=""
+        )
+        
+        if s3_bucket:
+            set_parameters({'s3-bucket': s3_bucket})
+            cid_print(f"Uploading to S3...")
+            
+            try:
+                s3_client = self.cid.base.session.client('s3')
+                s3_key = f"forecasts/{os.path.basename(self.output_file)}"
+                
+                s3_client.upload_file(
+                    self.output_file,
+                    s3_bucket,
+                    s3_key
+                )
+                
+                cid_print(f"File uploaded to s3://{s3_bucket}/{s3_key}")
+            except Exception as e:
+                cid_print(f"Failed to upload to S3: {str(e)}")
+
+    def _generate_quicksight_manifest(self) -> None:
+        """Generate QuickSight manifest file"""
+        s3_bucket = get_parameters().get('s3-bucket')
+        if not s3_bucket:
+            return
+            
+        cid_print("QuickSight Configuration")
+        cid_print("Generating QuickSight manifest file...")
+        
+        csv_s3_uri = f"s3://{s3_bucket}/forecasts/{os.path.basename(self.output_file)}"
+        manifest_file = os.path.join(self.output_dir, "manifest.json")
+        
+        manifest = {
+            "fileLocations": [
+                {
+                    "URIs": [
+                        csv_s3_uri
+                    ]
+                }
+            ],
+            "globalUploadSettings": {
+                "format": "CSV",
+                "delimiter": ",",
+                "textqualifier": "\"",
+                "containsHeader": "true"
+            }
+        }
+        
+        with open(manifest_file, 'w') as f:
+            json.dump(manifest, f, indent=4)
+        
+        try:
+            s3_client = self.cid.base.session.client('s3')
+            s3_client.upload_file(
+                manifest_file,
+                s3_bucket,
+                "forecasts/manifest.json"
+            )
+            
+            cid_print(f"QuickSight manifest uploaded to s3://{s3_bucket}/forecasts/manifest.json")
+            
+            cid_print("QuickSight Setup")
+            cid_print("QuickSight Import Instructions:")
+            cid_print("1. In QuickSight, create a new dataset")
+            cid_print("2. Choose 'S3' as the data source")
+            cid_print(f"3. Use this manifest URL: s3://{s3_bucket}/forecasts/manifest.json")
+            cid_print("4. Configure permissions to allow QuickSight to access the S3 bucket")
+        except Exception as e:
+            cid_print(f"Failed to upload manifest file to S3: {str(e)}")
+
+    def _cleanup(self) -> None:
+        """Clean up temporary files"""
+        cid_print("Cleaning up temporary files...")
+        if os.path.exists(self.temp_dir):
+            for file in os.listdir(self.temp_dir):
+                os.remove(os.path.join(self.temp_dir, file))
+            os.rmdir(self.temp_dir)
diff --git a/cid/common.py b/cid/common.py
index 7a701606c..714c28390 100644
--- a/cid/common.py
+++ b/cid/common.py
@@ -26,7 +26,7 @@
 from cid.export import export_analysis
 from cid.logger import set_cid_logger
 from cid.exceptions import CidError, CidCritical
-from cid.commands import InitQsCommand
+from cid.commands import InitQsCommand, ForecastCommand
 
 logger = logging.getLogger(__name__)
 
@@ -1763,6 +1763,11 @@ def map(self, **kwargs):
         for v in ['account_map', 'aws_accounts']:
             self.create_or_update_account_map(v)
 
+    @command
+    def forecast(self, **kwargs):
+        """Generate AWS Cost Explorer forecasts"""
+        return ForecastCommand(cid=self, **kwargs).execute()
+
     @command
     def teardown(self, **kwargs):
         """remove all assets created by cid"""
diff --git a/dashboards/catalog.yaml b/dashboards/catalog.yaml
index 794b1bae1..c8d1f03ba 100644
--- a/dashboards/catalog.yaml
+++ b/dashboards/catalog.yaml
@@ -1,16 +1,5 @@
 Resources:
-  - Url: cost-anomalies/cost-anomalies.yaml
-  - Url: sustainability-proxy-metrics/sustainability-proxy-metrics.yaml
-  - Url: data-transfer/DataTransfer-Cost-Analysis-Dashboard.yaml
-  - Url: aws-marketplace/aws-marketplace-spg.yaml
-  - Url: extended-support-cost-projection/extended-support-cost-projection.yaml
-  - Url: graviton-savings-dashboard/graviton_savings_dashboard.yaml
-  - Url: graviton-savings-dashboard/graviton_legacy.yaml # deprecated
-  - Url: amazon-connect/amazon-connect.yaml
-  - Url: support-cases-radar/support-cases-radar.yaml
-  - Url: health-events/health-events.yaml
-  - Url: scad-containers-cost-allocation/scad-containers-cost-allocation.yaml
-  - Url: aws-feeds/aws-feeds.yaml
-  - Url: focus/focus.yaml
-  - Url: cora/cora.yaml
-  - Url: aws-budgets/aws-budgets.yaml
+  - Name: "Cost Forecast Dashboard"
+    Description: "Visualize AWS Cost Explorer forecasts to predict future spending"
+    Url: "cost-forecast/resources.yaml"
+    Category: "Advanced"
diff --git a/dashboards/cost-forecast/resources.yaml b/dashboards/cost-forecast/resources.yaml
new file mode 100644
index 000000000..30434d853
--- /dev/null
+++ b/dashboards/cost-forecast/resources.yaml
@@ -0,0 +1,780 @@
+dashboards:
+  cost_forecast_dashboard:
+    name: "AWS Cost Forecast Dashboard"
+    category: "Advanced"
+    dashboardId: "cost-forecast-dashboard"
+    description: "Visualize AWS Cost Explorer forecasts to predict future spending"
+    dependsOn:
+      datasets:
+        - cost_forecast_dataset
+    parameters:
+      theme:
+        description: "QuickSight Theme"
+        default: "MIDNIGHT"
+    data:
+      AwsAccountId: "{account_id}"
+      DashboardId: "cost-forecast-dashboard"
+      Name: "AWS Cost Forecast Dashboard"
+      Permissions:
+        - Principal: "arn:{partition}:quicksight:{region}:{account_id}:user/default/{user_name}"
+          Actions:
+            - "quicksight:DescribeDashboard"
+            - "quicksight:ListDashboardVersions"
+            - "quicksight:UpdateDashboardPermissions"
+            - "quicksight:QueryDashboard"
+            - "quicksight:UpdateDashboard"
+            - "quicksight:DeleteDashboard"
+            - "quicksight:DescribeDashboardPermissions"
+            - "quicksight:UpdateDashboardPublishedVersion"
+      DashboardPublishOptions:
+        AdHocFilteringOption:
+          AvailabilityStatus: ENABLED
+        ExportToCSVOption:
+          AvailabilityStatus: ENABLED
+        SheetControlsOption:
+          VisibilityState: EXPANDED
+      ThemeArn: "arn:{partition}:quicksight:{region}:{account_id}:theme/{theme}"
+      Definition:
+        DataSetIdentifierDeclarations:
+          - DataSetArn: "{cost_forecast_dataset_arn}"
+            Identifier: "cost_forecast_dataset"
+        Sheets:
+          - Name: "Cost Forecast Overview"
+            SheetId: "cost-forecast-overview"
+            Layouts:
+              - Configuration:
+                  GridLayout:
+                    Elements:
+                      - ElementId: "forecast-trend-chart"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 0
+                        ColumnSpan: 16
+                        RowIndex: 0
+                        RowSpan: 12
+                      - ElementId: "forecast-summary-kpis"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 16
+                        ColumnSpan: 8
+                        RowIndex: 0
+                        RowSpan: 6
+                      - ElementId: "forecast-by-dimension"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 16
+                        ColumnSpan: 8
+                        RowIndex: 6
+                        RowSpan: 6
+                      - ElementId: "forecast-details-table"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 0
+                        ColumnSpan: 24
+                        RowIndex: 12
+                        RowSpan: 8
+                    CanvasSizeOptions:
+                      ScreenCanvasSizeOptions:
+                        ResizeOption: "RESPONSIVE"
+                        OptimizedViewPortWidth: "1600px"
+            Visuals:
+              - LineChartVisual:
+                  VisualId: "forecast-trend-chart"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Cost Forecast Trend"
+                  ChartConfiguration:
+                    FieldWells:
+                      LineChartAggregatedFieldWells:
+                        Category:
+                          - CategoricalDimensionField:
+                              FieldId: "start_date"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "start_date"
+                        Values:
+                          - NumericalMeasureField:
+                              FieldId: "mean_value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "mean_value"
+                              AggregationFunction: "SUM"
+                          - NumericalMeasureField:
+                              FieldId: "lower_bound"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "lower_bound"
+                              AggregationFunction: "SUM"
+                          - NumericalMeasureField:
+                              FieldId: "upper_bound"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "upper_bound"
+                              AggregationFunction: "SUM"
+                        Colors:
+                          - CategoricalDimensionField:
+                              FieldId: "dimension"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "dimension"
+                    SortConfiguration:
+                      CategorySort:
+                        - FieldSort:
+                            FieldId: "start_date"
+                            Direction: "ASCENDING"
+                    Legend:
+                      Visibility: "VISIBLE"
+                      Position: "RIGHT"
+                      Title:
+                        Visibility: "VISIBLE"
+                        CustomLabel: "Forecast"
+                    XAxisDisplayOptions:
+                      TickLabelOptions:
+                        RotationAngle: 0
+                      AxisLabelOptions:
+                        Visibility: "VISIBLE"
+                        FontConfiguration:
+                          FontSize:
+                            Relative: "MEDIUM"
+                    PrimaryYAxisDisplayOptions:
+                      AxisLineVisibility: "VISIBLE"
+                      GridLineVisibility: "VISIBLE"
+                      DataLabelOptions:
+                        Visibility: "VISIBLE"
+                        FormatConfiguration:
+                          NumericFormatConfiguration:
+                            FormatConfiguration:
+                              CurrencyDisplayFormatConfiguration:
+                                DecimalPlacesConfiguration:
+                                  DecimalPlaces: 0
+                      AxisLabelOptions:
+                        Visibility: "VISIBLE"
+                        FontConfiguration:
+                          FontSize:
+                            Relative: "MEDIUM"
+                    Series:
+                      - SeriesId: "mean_value"
+                        AxisBinding: "PRIMARY_Y"
+                        LineStyleSettings:
+                          LineWidth: "MEDIUM"
+                          LineStyle: "SOLID"
+                          LineInterpolation: "CURVED"
+                        MarkerStyleSettings:
+                          Visibility: "HIDDEN"
+                      - SeriesId: "lower_bound"
+                        AxisBinding: "PRIMARY_Y"
+                        LineStyleSettings:
+                          LineWidth: "THIN"
+                          LineStyle: "DASHED"
+                          LineInterpolation: "CURVED"
+                        MarkerStyleSettings:
+                          Visibility: "HIDDEN"
+                      - SeriesId: "upper_bound"
+                        AxisBinding: "PRIMARY_Y"
+                        LineStyleSettings:
+                          LineWidth: "THIN"
+                          LineStyle: "DASHED"
+                          LineInterpolation: "CURVED"
+                        MarkerStyleSettings:
+                          Visibility: "HIDDEN"
+                    VisualPalette:
+                      ColorMap:
+                        - Color: "#2CA02C"
+                          DataValue: "mean_value"
+                        - Color: "#D3D3D3"
+                          DataValue: "lower_bound"
+                        - Color: "#D3D3D3"
+                          DataValue: "upper_bound"
+                      UsePaletteColorForBackground: false
+                    AreaStyleSettings:
+                      AreaStyleOptions:
+                        - SeriesId: "mean_value"
+                          Visibility: "HIDDEN"
+                        - SeriesId: "lower_bound"
+                          Visibility: "HIDDEN"
+                        - SeriesId: "upper_bound"
+                          Visibility: "HIDDEN"
+                      BetweenLinesAreaStyleOptions:
+                        - UpperSeriesId: "upper_bound"
+                          LowerSeriesId: "lower_bound"
+                          Visibility: "VISIBLE"
+                          Color: "rgba(44, 160, 44, 0.2)"
+                  Actions: []
+                  ColumnHierarchies: []
+                  Subtitle:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Showing forecast with 95% confidence interval"
+              - DonutChartVisual:
+                  VisualId: "forecast-by-dimension"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Forecast by Dimension"
+                  ChartConfiguration:
+                    FieldWells:
+                      DonutChartAggregatedFieldWells:
+                        Category:
+                          - CategoricalDimensionField:
+                              FieldId: "value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "value"
+                        Values:
+                          - NumericalMeasureField:
+                              FieldId: "mean_value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "mean_value"
+                              AggregationFunction: "SUM"
+                    SortConfiguration:
+                      CategoryItemsLimit:
+                        OtherCategories: "INCLUDE"
+                    DonutOptions:
+                      ArcOptions:
+                        ArcThickness: "MEDIUM"
+                    Legend:
+                      Visibility: "VISIBLE"
+                      Position: "RIGHT"
+                      Title:
+                        Visibility: "VISIBLE"
+                        CustomLabel: "Dimensions"
+                    DataLabels:
+                      Visibility: "VISIBLE"
+                      CategoryLabelVisibility: "VISIBLE"
+                      MeasureLabelVisibility: "VISIBLE"
+                      Position: "INSIDE"
+                      LabelFontConfiguration:
+                        FontSize:
+                          Relative: "SMALL"
+                      LabelColor: "#FFFFFF"
+                    VisualPalette:
+                      ColorMap:
+                        - Color: "#1F77B4"
+                        - Color: "#FF7F0E"
+                        - Color: "#2CA02C"
+                        - Color: "#D62728"
+                        - Color: "#9467BD"
+                        - Color: "#8C564B"
+                        - Color: "#E377C2"
+                        - Color: "#7F7F7F"
+                        - Color: "#BCBD22"
+                        - Color: "#17BECF"
+                      UsePaletteColorForBackground: false
+                  Actions: []
+                  ColumnHierarchies: []
+                  Subtitle:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Distribution of forecasted costs"
+              - KPIVisual:
+                  VisualId: "forecast-summary-kpis"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Forecast Summary"
+                  ChartConfiguration:
+                    FieldWells:
+                      Values:
+                        - NumericalMeasureField:
+                            FieldId: "mean_value"
+                            Column:
+                              DataSetIdentifier: "cost_forecast_dataset"
+                              ColumnName: "mean_value"
+                            AggregationFunction: "SUM"
+                      TargetValues:
+                        - NumericalMeasureField:
+                            FieldId: "upper_bound"
+                            Column:
+                              DataSetIdentifier: "cost_forecast_dataset"
+                              ColumnName: "upper_bound"
+                            AggregationFunction: "SUM"
+                      TrendGroups:
+                        - CategoricalDimensionField:
+                            FieldId: "start_date"
+                            Column:
+                              DataSetIdentifier: "cost_forecast_dataset"
+                              ColumnName: "start_date"
+                    SortConfiguration:
+                      TrendGroupSort:
+                        - FieldSort:
+                            FieldId: "start_date"
+                            Direction: "ASCENDING"
+                    KPIOptions:
+                      PrimaryValueDisplayType: "ACTUAL"
+                      PrimaryValueFontConfiguration:
+                        FontSize:
+                          Relative: "LARGE"
+                      ProgressBar:
+                        Visibility: "VISIBLE"
+                      TrendArrows:
+                        Visibility: "VISIBLE"
+                      Comparison:
+                        ComparisonMethod: "PERCENT_DIFFERENCE"
+                      SecondaryValue:
+                        Visibility: "VISIBLE"
+                    VisualPalette:
+                      ColorMap:
+                        - Color: "#2CA02C"
+                      UsePaletteColorForBackground: false
+                  Actions: []
+                  ColumnHierarchies: []
+              - TableVisual:
+                  VisualId: "forecast-details-table"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Forecast Details"
+                  ChartConfiguration:
+                    FieldWells:
+                      TableAggregatedFieldWells:
+                        GroupBy:
+                          - CategoricalDimensionField:
+                              FieldId: "dimension_name"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "dimension_name"
+                          - CategoricalDimensionField:
+                              FieldId: "value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "value"
+                          - CategoricalDimensionField:
+                              FieldId: "metric_name"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "metric_name"
+                          - CategoricalDimensionField:
+                              FieldId: "start_date"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "start_date"
+                        Values:
+                          - NumericalMeasureField:
+                              FieldId: "mean_value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "mean_value"
+                              AggregationFunction: "SUM"
+                          - NumericalMeasureField:
+                              FieldId: "lower_bound"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "lower_bound"
+                              AggregationFunction: "SUM"
+                          - NumericalMeasureField:
+                              FieldId: "upper_bound"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "upper_bound"
+                              AggregationFunction: "SUM"
+                          - NumericalMeasureField:
+                              FieldId: "variance"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "variance"
+                              AggregationFunction: "SUM"
+                    SortConfiguration:
+                      RowSort:
+                        - FieldSort:
+                            FieldId: "start_date"
+                            Direction: "ASCENDING"
+                    TableOptions:
+                      HeaderStyle:
+                        TextWrap: "WRAP"
+                        Height: 25
+                        FontConfiguration:
+                          FontSize:
+                            Relative: "MEDIUM"
+                      CellStyle:
+                        TextWrap: "WRAP"
+                        Height: 25
+                        FontConfiguration:
+                          FontSize:
+                            Relative: "SMALL"
+                      RowAlternateColorOptions:
+                        Status: "ENABLED"
+                        RowAlternateColors:
+                          - "rgba(0, 0, 0, 0.05)"
+                    TotalOptions:
+                      TotalsVisibility: "VISIBLE"
+                      Placement: "END"
+                      ScrollStatus: "PINNED"
+                      CustomLabel: "Total"
+                      TotalCellStyle:
+                        FontConfiguration:
+                          FontSize:
+                            Relative: "MEDIUM"
+                  Actions: []
+                  ColumnHierarchies: []
+                  Subtitle:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Detailed forecast data with confidence intervals"
+          - Name: "Forecast Analysis"
+            SheetId: "forecast-analysis"
+            Layouts:
+              - Configuration:
+                  GridLayout:
+                    Elements:
+                      - ElementId: "forecast-by-service"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 0
+                        ColumnSpan: 12
+                        RowIndex: 0
+                        RowSpan: 12
+                      - ElementId: "forecast-variance-heatmap"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 12
+                        ColumnSpan: 12
+                        RowIndex: 0
+                        RowSpan: 12
+                      - ElementId: "forecast-gauge"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 0
+                        ColumnSpan: 8
+                        RowIndex: 12
+                        RowSpan: 8
+                      - ElementId: "forecast-variance-kpi"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 8
+                        ColumnSpan: 8
+                        RowIndex: 12
+                        RowSpan: 8
+                      - ElementId: "forecast-comparison"
+                        ElementType: "VISUAL"
+                        ColumnIndex: 16
+                        ColumnSpan: 8
+                        RowIndex: 12
+                        RowSpan: 8
+                    CanvasSizeOptions:
+                      ScreenCanvasSizeOptions:
+                        ResizeOption: "RESPONSIVE"
+                        OptimizedViewPortWidth: "1600px"
+            Visuals:
+              - BarChartVisual:
+                  VisualId: "forecast-by-service"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Forecast by Service"
+                  ChartConfiguration:
+                    FieldWells:
+                      BarChartAggregatedFieldWells:
+                        Category:
+                          - CategoricalDimensionField:
+                              FieldId: "value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "value"
+                              FilterControl:
+                                SourceFilterId: "service-filter"
+                        Values:
+                          - NumericalMeasureField:
+                              FieldId: "mean_value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "mean_value"
+                              AggregationFunction: "SUM"
+                    SortConfiguration:
+                      CategorySort:
+                        - FieldSort:
+                            FieldId: "mean_value"
+                            Direction: "DESCENDING"
+                      CategoryItemsLimit:
+                        ItemCount: 10
+                    Legend:
+                      Visibility: "VISIBLE"
+                      Position: "RIGHT"
+                      Title:
+                        Visibility: "VISIBLE"
+                        CustomLabel: "Services"
+                    DataLabels:
+                      Visibility: "VISIBLE"
+                      CategoryLabelVisibility: "VISIBLE"
+                      MeasureLabelVisibility: "VISIBLE"
+                      OverlappingLabelVisibility: "VISIBLE"
+                    Orientation: "HORIZONTAL"
+                    BarsArrangement: "CLUSTERED"
+                    VisualPalette:
+                      ColorMap:
+                        - Color: "#1F77B4"
+                        - Color: "#FF7F0E"
+                        - Color: "#2CA02C"
+                        - Color: "#D62728"
+                        - Color: "#9467BD"
+                        - Color: "#8C564B"
+                        - Color: "#E377C2"
+                        - Color: "#7F7F7F"
+                        - Color: "#BCBD22"
+                        - Color: "#17BECF"
+                      UsePaletteColorForBackground: false
+                  Actions: []
+                  ColumnHierarchies: []
+                  Subtitle:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Top 10 services by forecasted cost"
+              - HeatMapVisual:
+                  VisualId: "forecast-variance-heatmap"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Forecast Variance Heatmap"
+                  ChartConfiguration:
+                    FieldWells:
+                      HeatMapAggregatedFieldWells:
+                        Rows:
+                          - CategoricalDimensionField:
+                              FieldId: "value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "value"
+                        Columns:
+                          - CategoricalDimensionField:
+                              FieldId: "start_date"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "start_date"
+                        Values:
+                          - NumericalMeasureField:
+                              FieldId: "variance_percentage"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "variance_percentage"
+                              AggregationFunction: "AVG"
+                    SortConfiguration:
+                      RowSort:
+                        - FieldSort:
+                            FieldId: "variance_percentage"
+                            Direction: "DESCENDING"
+                      ColumnSort:
+                        - FieldSort:
+                            FieldId: "start_date"
+                            Direction: "ASCENDING"
+                      RowItemsLimit:
+                        ItemCount: 10
+                    Legend:
+                      Visibility: "VISIBLE"
+                      Position: "RIGHT"
+                      Title:
+                        Visibility: "VISIBLE"
+                        CustomLabel: "Variance %"
+                    ColorScale:
+                      Colors:
+                        - Color: "#2CA02C"
+                        - Color: "#FFFF00"
+                        - Color: "#D62728"
+                      NullValueColor:
+                        Color: "#BDBDBD"
+                    DataLabels:
+                      Visibility: "VISIBLE"
+                      OverlappingLabelVisibility: "VISIBLE"
+                  Actions: []
+                  ColumnHierarchies: []
+                  Subtitle:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Forecast confidence by dimension and time"
+              - GaugeChartVisual:
+                  VisualId: "forecast-gauge"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Total Forecasted Cost"
+                  ChartConfiguration:
+                    FieldWells:
+                      GaugeChartAggregatedFieldWells:
+                        Values:
+                          - NumericalMeasureField:
+                              FieldId: "mean_value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "mean_value"
+                              AggregationFunction: "SUM"
+                        TargetValues:
+                          - NumericalMeasureField:
+                              FieldId: "upper_bound"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "upper_bound"
+                              AggregationFunction: "SUM"
+                    GaugeChartOptions:
+                      Arc:
+                        ArcAngle: 180
+                        ArcThickness: "MEDIUM"
+                      Comparison:
+                        ComparisonMethod: "PERCENT"
+                    DataLabels:
+                      Visibility: "VISIBLE"
+                      CategoryLabelVisibility: "VISIBLE"
+                      MeasureLabelVisibility: "VISIBLE"
+                      Position: "INSIDE"
+                    VisualPalette:
+                      ColorMap:
+                        - Color: "#2CA02C"
+                      UsePaletteColorForBackground: false
+                  Actions: []
+                  ColumnHierarchies: []
+              - KPIVisual:
+                  VisualId: "forecast-variance-kpi"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Forecast Variance"
+                  ChartConfiguration:
+                    FieldWells:
+                      Values:
+                        - NumericalMeasureField:
+                            FieldId: "variance_percentage"
+                            Column:
+                              DataSetIdentifier: "cost_forecast_dataset"
+                              ColumnName: "variance_percentage"
+                            AggregationFunction: "AVG"
+                    KPIOptions:
+                      PrimaryValueDisplayType: "ACTUAL"
+                      PrimaryValueFontConfiguration:
+                        FontSize:
+                          Relative: "LARGE"
+                      Sparkline:
+                        Visibility: "VISIBLE"
+                        Type: "LINE"
+                      TrendArrows:
+                        Visibility: "VISIBLE"
+                    VisualPalette:
+                      ColorMap:
+                        - Color: "#2CA02C"
+                      UsePaletteColorForBackground: false
+                  Actions: []
+                  ColumnHierarchies: []
+              - BarChartVisual:
+                  VisualId: "forecast-comparison"
+                  Title:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Forecast Comparison"
+                  ChartConfiguration:
+                    FieldWells:
+                      BarChartAggregatedFieldWells:
+                        Category:
+                          - CategoricalDimensionField:
+                              FieldId: "metric_name"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "metric_name"
+                        Values:
+                          - NumericalMeasureField:
+                              FieldId: "mean_value"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "mean_value"
+                              AggregationFunction: "SUM"
+                        Colors:
+                          - CategoricalDimensionField:
+                              FieldId: "metric_name"
+                              Column:
+                                DataSetIdentifier: "cost_forecast_dataset"
+                                ColumnName: "metric_name"
+                    SortConfiguration:
+                      CategorySort:
+                        - FieldSort:
+                            FieldId: "mean_value"
+                            Direction: "DESCENDING"
+                    Legend:
+                      Visibility: "VISIBLE"
+                      Position: "RIGHT"
+                      Title:
+                        Visibility: "VISIBLE"
+                        CustomLabel: "Metrics"
+                    DataLabels:
+                      Visibility: "VISIBLE"
+                      CategoryLabelVisibility: "VISIBLE"
+                      MeasureLabelVisibility: "VISIBLE"
+                    Orientation: "VERTICAL"
+                    BarsArrangement: "CLUSTERED"
+                    SmallMultiplesOptions:
+                      MaxVisibleRows: 2
+                      MaxVisibleColumns: 2
+                      PanelConfiguration:
+                        Title:
+                          Visibility: "VISIBLE"
+                        BorderVisibility: "VISIBLE"
+                    VisualPalette:
+                      ColorMap:
+                        - Color: "#1F77B4"
+                        - Color: "#FF7F0E"
+                        - Color: "#2CA02C"
+                        - Color: "#D62728"
+                        - Color: "#9467BD"
+                      UsePaletteColorForBackground: false
+                  Actions: []
+                  ColumnHierarchies: []
+                  Subtitle:
+                    Visibility: "VISIBLE"
+                    FormatText:
+                      PlainText: "Comparing different forecast metrics"
+        FilterGroups:
+          - FilterGroupId: "filter-group-1"
+            Filters:
+              - CategoryFilter:
+                  FilterId: "dimension-filter"
+                  Column:
+                    DataSetIdentifier: "cost_forecast_dataset"
+                    ColumnName: "dimension"
+                  Configuration:
+                    FilterListConfiguration:
+                      MatchOperator: "EQUALS"
+                      CategoryValues:
+                        - "SERVICE"
+                        - "LINKED_ACCOUNT"
+                        - "REGION"
+              - CategoryFilter:
+                  FilterId: "service-filter"
+                  Column:
+                    DataSetIdentifier: "cost_forecast_dataset"
+                    ColumnName: "value"
+                  Configuration:
+                    FilterListConfiguration:
+                      MatchOperator: "EQUALS"
+              - CategoryFilter:
+                  FilterId: "metric-filter"
+                  Column:
+                    DataSetIdentifier: "cost_forecast_dataset"
+                    ColumnName: "metric"
+                  Configuration:
+                    FilterListConfiguration:
+                      MatchOperator: "EQUALS"
+                      CategoryValues:
+                        - "UNBLENDED_COST"
+        CalculatedFields: []
+        ParameterDeclarations:
+          - StringParameter:
+              ParameterId: "forecast-period"
+              Name: "Forecast Period"
+              DefaultValues:
+                StaticValues:
+                  - "90 Days"
+              ValueWhenUnset:
+                StaticValue: "90 Days"
+              Values:
+                StaticValues:
+                  - "30 Days"
+                  - "90 Days"
+                  - "180 Days"
+                  - "365 Days"
+
+datasets:
+  cost_forecast_dataset:
+    name: "Cost Forecast Dataset"
+    providedBy: "cid.builtin.core"
+    File: "datasets/forecast/cost_forecast_dataset.json"
+    dependsOn:
+      views:
+        - cost_forecast
+
+views:
+  cost_forecast:
+    name: "Cost Forecast View"
+    providedBy: "cid.builtin.core"
+    File: "queries/forecast/cost_forecast_view.sql"
+    parameters:
+      forecast_table_name:
+        description: "Name of the table containing forecast data"
+        default: "cost_forecast_data"
diff --git a/docs/cost_forecast.md b/docs/cost_forecast.md
new file mode 100644
index 000000000..7687ed7bf
--- /dev/null
+++ b/docs/cost_forecast.md
@@ -0,0 +1,95 @@
+# AWS Cost Forecast Dashboard
+
+The AWS Cost Forecast Dashboard provides a comprehensive view of your future AWS spending based on AWS Cost Explorer forecasts. This dashboard helps you predict and plan for future costs across different dimensions such as services, accounts, and regions.
+
+## Features
+
+- Visualize cost forecasts with confidence intervals
+- Analyze forecasted costs by service, account, region, and other dimensions
+- Compare forecasts across different metrics (Unblended Cost, Amortized Cost, etc.)
+- View daily or monthly forecast granularity
+- Identify potential cost spikes or anomalies in future spending
+
+## Prerequisites
+
+Before deploying the Cost Forecast Dashboard, ensure you have:
+
+1. Completed the [general prerequisites](https://catalog.workshops.aws/awscid/en-US/dashboards/foundational/cudos-cid-kpi/deploy) (Steps 1 and 2)
+2. AWS Cost Explorer enabled in your account
+3. QuickSight Enterprise Edition activated
+
+## Deployment Options
+
+### Option 1: Using cid-cmd tool (Recommended)
+
+1. Generate forecast data using the built-in forecast command:
+
+```bash
+cid-cmd forecast
+```
+
+2. Follow the interactive prompts to:
+   - Select the forecast time period
+   - Choose metrics and dimensions
+   - Set granularity (daily or monthly)
+   - Upload results to S3
+
+3. Deploy the dashboard:
+
+```bash
+cid-cmd deploy --dashboard-id cost-forecast-dashboard
+```
+
+### Option 2: Using the standalone script
+
+If you prefer to use the standalone script for more control over the forecast data collection:
+
+1. Run the script from the scripts directory:
+
+```bash
+cd scripts
+./cost_forecast.sh
+```
+
+2. Follow the interactive prompts to configure and generate the forecast data
+
+3. After uploading to S3, deploy the dashboard:
+
+```bash
+cid-cmd deploy --dashboard-id cost-forecast-dashboard
+```
+
+## Dashboard Sections
+
+### Cost Forecast Overview
+- Trend chart showing forecasted costs over time with confidence intervals
+- Distribution of forecasted costs by selected dimension
+- Detailed forecast data table with confidence bounds
+
+### Forecast Analysis
+- Top services by forecasted cost
+- Total forecasted cost KPI
+- Forecast variance analysis
+
+## Customization
+
+You can customize the dashboard by:
+
+1. Modifying the forecast parameters when generating data
+2. Editing the QuickSight dashboard after deployment
+3. Creating additional visualizations based on the forecast dataset
+
+## Troubleshooting
+
+If you encounter issues:
+
+- Ensure AWS Cost Explorer is enabled in your account
+- Verify you have sufficient permissions to access Cost Explorer APIs
+- Check S3 bucket permissions if using S3 for data storage
+- Run the forecast command with verbose logging: `cid-cmd forecast -vv`
+
+## Additional Resources
+
+- [AWS Cost Explorer Documentation](https://docs.aws.amazon.com/cost-management/latest/userguide/ce-what-is.html)
+- [AWS Cost Explorer API Reference](https://docs.aws.amazon.com/aws-cost-management/latest/APIReference/API_GetCostForecast.html)
+- [QuickSight Documentation](https://docs.aws.amazon.com/quicksight/latest/user/welcome.html)
diff --git a/scripts/cost_forecast.sh b/scripts/cost_forecast.sh
new file mode 100755
index 000000000..b93269c39
--- /dev/null
+++ b/scripts/cost_forecast.sh
@@ -0,0 +1,512 @@
+#!/bin/bash
+# AWS Cost Forecast Data Fetch Tool
+# Set strict error handling
+set -euo pipefail
+
+# Configuration
+readonly TIMESTAMP=$(date +%Y%m%d_%H%M%S)
+readonly OUTPUT_DIR="${PWD}/output/${TIMESTAMP}"
+readonly OUTPUT_FILE="${OUTPUT_DIR}/forecast_${TIMESTAMP}.csv"
+readonly TEMP_DIR="${OUTPUT_DIR}/temp"
+readonly MAX_PARALLEL=10  # Maximum parallel processes
+
+# Create directories
+mkdir -p "${OUTPUT_DIR}" "${TEMP_DIR}"
+
+# Color codes and formatting
+readonly RED='\033[0;31m'
+readonly GREEN='\033[0;32m'
+readonly BLUE='\033[0;34m'
+readonly YELLOW='\033[1;33m'
+readonly CYAN='\033[0;36m'
+readonly MAGENTA='\033[1;35m'
+readonly NC='\033[0m'
+readonly BOLD='\033[1m'
+readonly UNDERLINE='\033[4m'
+readonly BG_BLUE='\033[44m'
+readonly BG_GREEN='\033[42m'
+
+# Spinner characters
+readonly SPINNER_CHARS='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
+
+# Global variables for job tracking
+declare -i total_jobs=0
+declare -i completed_jobs=0
+declare -i spinner_idx=0
+
+# Available metrics
+readonly METRICS=(
+    "AMORTIZED_COST"
+    "BLENDED_COST"
+    "NET_AMORTIZED_COST"
+    "NET_UNBLENDED_COST"
+    "UNBLENDED_COST"
+    "USAGE_QUANTITY"
+    "NORMALIZED_USAGE_AMOUNT"
+)
+
+# Available dimensions
+readonly DIMENSIONS=(
+    "AZ"
+    "INSTANCE_TYPE"
+    "LINKED_ACCOUNT"
+    "LINKED_ACCOUNT_NAME"
+    "OPERATION"
+    "PURCHASE_TYPE"
+    "REGION"
+    "SERVICE"
+    "USAGE_TYPE"
+    "USAGE_TYPE_GROUP"
+    "RECORD_TYPE"
+    "OPERATING_SYSTEM"
+    "TENANCY"
+    "SCOPE"
+    "PLATFORM"
+    "SUBSCRIPTION_ID"
+    "LEGAL_ENTITY_NAME"
+    "DEPLOYMENT_OPTION"
+    "DATABASE_ENGINE"
+    "INSTANCE_TYPE_FAMILY"
+    "BILLING_ENTITY"
+    "RESERVATION_ID"
+    "SAVINGS_PLAN_ARN"
+)
+
+# Display functions
+display_spinner() {
+    local text="$1"
+    printf "\r${CYAN}${SPINNER_CHARS:spinner_idx++:1}${NC} %s" "$text"
+    spinner_idx=$(( spinner_idx >= ${#SPINNER_CHARS} ? 0 : spinner_idx ))
+}
+
+display_banner() {
+    local text="$1"
+    local width=60
+    local padding=$(( (width - ${#text}) / 2 ))
+    
+    echo
+    echo -e "${BG_BLUE}${BOLD}$(printf '%*s' $width '')${NC}"
+    echo -e "${BG_BLUE}${BOLD}$(printf '%*s' $padding '')${text}$(printf '%*s' $padding '')${NC}"
+    echo -e "${BG_BLUE}${BOLD}$(printf '%*s' $width '')${NC}"
+    echo
+}
+
+display_section_header() {
+    local text="$1"
+    echo -e "\n${YELLOW}${BOLD}═══════════════════ ${text} ═══════════════════${NC}\n"
+}
+
+display_progress_bar() {
+    local progress=$1
+    local text="${2:-Processing}"
+    local width=40
+    local filled=$(( progress * width / 100 ))
+    local empty=$(( width - filled ))
+    
+    printf "\r${CYAN}${text}: ["
+    printf "%${filled}s" '' | tr ' ' '█'
+    printf "%${empty}s" '' | tr ' ' '░'
+    printf "] %3d%%${NC}" $progress
+}
+
+# Rate limiting function
+rate_limit() {
+    sleep 0.5  # Half second delay between API calls
+}
+
+# Logging function
+log() {
+    local level=$1
+    local message=$2
+    local color
+    
+    case $level in
+        "INFO") color="${CYAN}";;
+        "SUCCESS") color="${GREEN}";;
+        "WARNING") color="${YELLOW}";;
+        "ERROR") color="${RED}";;
+        *) color="${NC}";;
+    esac
+    
+    echo -e "$(date '+%Y-%m-%d %H:%M:%S') [${color}${level}${NC}] ${message}"
+}
+
+check_prerequisites() {
+    display_section_header "CHECKING PREREQUISITES"
+    local spinner_text="Checking AWS CLI..."
+    
+    display_spinner "${spinner_text}"
+    if ! command -v aws >/dev/null 2>&1; then
+        echo
+        log "ERROR" "AWS CLI is not installed"
+        exit 1
+    fi
+    
+    spinner_text="Checking jq..."
+    display_spinner "${spinner_text}"
+    if ! command -v jq >/dev/null 2>&1; then
+        echo
+        log "ERROR" "jq is not installed"
+        exit 1
+    fi
+    
+    spinner_text="Checking AWS credentials..."
+    display_spinner "${spinner_text}"
+    if ! aws sts get-caller-identity >/dev/null 2>&1; then
+        echo
+        log "ERROR" "AWS credentials not configured"
+        exit 1
+    fi
+    
+    echo
+    log "SUCCESS" "All prerequisites met"
+}
+
+get_time_period() {
+    display_section_header "TIME PERIOD SELECTION"
+    echo -e "${CYAN}${BOLD}Select Time Period:${NC}"
+    echo -e "${MAGENTA}1)${NC} Next 30 days"
+    echo -e "${MAGENTA}2)${NC} Next 90 days"
+    echo -e "${MAGENTA}3)${NC} Next 180 days"
+    echo -e "${MAGENTA}4)${NC} Next 365 days"
+    echo -e "${MAGENTA}5)${NC} Custom period"
+    
+    echo -e "\n${BOLD}Enter your choice [1-5]:${NC}"
+    read -p "→ " choice
+    
+    TODAY=$(date '+%Y-%m-%d')
+    
+    case $choice in
+        1) END_DATE=$(date -d "${TODAY} +30 days" '+%Y-%m-%d');;
+        2) END_DATE=$(date -d "${TODAY} +90 days" '+%Y-%m-%d');;
+        3) END_DATE=$(date -d "${TODAY} +180 days" '+%Y-%m-%d');;
+        4) END_DATE=$(date -d "${TODAY} +365 days" '+%Y-%m-%d');;
+        5)
+            echo -e "\n${BOLD}Enter end date (YYYY-MM-DD):${NC}"
+            read -p "→ " END_DATE
+            ;;
+        *)
+            log "ERROR" "Invalid choice"
+            exit 1
+            ;;
+    esac
+    
+    START_DATE="${TODAY}"
+    TIME_PERIOD="Start=${START_DATE},End=${END_DATE}"
+    log "SUCCESS" "Time period set: ${START_DATE} to ${END_DATE}"
+}
+
+get_dimension_values() {
+    local dimension=$1
+    local values
+    local spinner_text="Fetching values for ${dimension}..."
+    
+    display_spinner "${spinner_text}"
+    rate_limit
+    values=$(aws ce get-dimension-values \
+        --time-period Start=$(date -d '30 days ago' +%Y-%m-%d),End=$(date +%Y-%m-%d) \
+        --dimension "${dimension}" \
+        --query 'DimensionValues[*].Value' \
+        --output json 2>/dev/null | jq -r '.[]' 2>/dev/null)
+    
+    if [[ $? -eq 0 && -n "$values" ]]; then
+        echo "$values"
+    else
+        echo
+        log "WARNING" "No values found for dimension: ${dimension}"
+        echo ""
+    fi
+}
+
+fetch_forecast() {
+    local dimension=$1
+    local value=$2
+    local metric=$3
+    local output_file="${TEMP_DIR}/${dimension}_${value//\//_}_${metric}.json"
+    
+    local filter="{\"Dimensions\":{\"Key\":\"${dimension}\",\"Values\":[\"${value}\"]}}"
+    
+    rate_limit
+    if aws ce get-cost-forecast \
+        --time-period "${TIME_PERIOD}" \
+        --metric "${metric}" \
+        --granularity "${GRANULARITY}" \
+        --prediction-interval-level 95 \
+        --filter "${filter}" > "${output_file}" 2>/dev/null; then
+        
+        if [[ -f "${output_file}" ]]; then
+            jq -r --arg dim "${dimension}" \
+               --arg val "${value}" \
+               --arg met "${metric}" \
+               '.ForecastResultsByTime[] | [
+                   $dim,
+                   $val,
+                   $met,
+                   .TimePeriod.Start,
+                   .TimePeriod.End,
+                   .MeanValue,
+                   .PredictionIntervalLowerBound,
+                   .PredictionIntervalUpperBound
+               ] | @csv' "${output_file}" >> "${OUTPUT_FILE}.tmp" 2>/dev/null
+            
+            rm "${output_file}"
+        fi
+    else
+        log "WARNING" "Failed to fetch forecast for ${dimension}=${value}, metric=${metric}"
+    fi
+}
+
+process_forecast_parallel() {
+    echo "Dimension,Value,Metric,StartDate,EndDate,MeanValue,LowerBound,UpperBound" > "${OUTPUT_FILE}"
+    touch "${OUTPUT_FILE}.tmp"
+
+    # First, calculate total jobs and cache dimension values
+    log "INFO" "Calculating total jobs..."
+    declare -A dimension_values
+    total_jobs=0
+    
+    for dimension in "${SELECTED_DIMENSIONS[@]}"; do
+        log "INFO" "Fetching values for dimension: ${dimension}"
+        # Cache dimension values in an array
+        dimension_values[$dimension]=$(get_dimension_values "${dimension}")
+        
+        # Count number of values for this dimension
+        value_count=$(echo "${dimension_values[$dimension]}" | wc -l)
+        # Multiply by number of metrics
+        dimension_total=$((value_count * ${#SELECTED_METRICS[@]}))
+        total_jobs=$((total_jobs + dimension_total))
+        
+        log "INFO" "Found ${value_count} values for ${dimension}, adding ${dimension_total} jobs"
+    done
+
+    log "INFO" "Total jobs to process: ${total_jobs}"
+
+    # Create a FIFO for job control
+    mkfifo "${TEMP_DIR}/jobs.fifo"
+
+    # Start background process to limit concurrent jobs
+    exec 3<>"${TEMP_DIR}/jobs.fifo"
+    for ((i=0; i&3
+    done
+
+    completed_jobs=0
+
+    for dimension in "${SELECTED_DIMENSIONS[@]}"; do
+        log "INFO" "Processing dimension: ${dimension}"
+        
+        echo "${dimension_values[$dimension]}" | while read -r value; do
+            # Skip empty values
+            [ -z "$value" ] && continue
+            
+            for metric in "${SELECTED_METRICS[@]}"; do
+                # Wait for a slot
+                read -u3
+                {
+                    fetch_forecast "${dimension}" "${value}" "${metric}"
+                    echo >&3  # Release the slot
+                    
+                    # Update progress atomically
+                    {
+                        ((completed_jobs++))
+                        progress=$((completed_jobs * 100 / total_jobs))
+                        display_progress_bar $progress "Processing forecasts"
+                    } 2>/dev/null
+                } &
+            done
+        done
+    done
+
+    # Wait for all background jobs to complete
+    wait
+
+    # Clean up
+    exec 3>&-
+    rm "${TEMP_DIR}/jobs.fifo"
+
+    # Combine results
+    if [[ -f "${OUTPUT_FILE}.tmp" ]]; then
+        cat "${OUTPUT_FILE}.tmp" >> "${OUTPUT_FILE}"
+        rm "${OUTPUT_FILE}.tmp"
+        echo  # New line after progress bar
+        log "SUCCESS" "Data collection completed"
+    else
+        log "WARNING" "No data was collected"
+    fi
+}
+
+select_options() {
+    display_section_header "METRIC SELECTION"
+    echo -e "${CYAN}${BOLD}Available Metrics:${NC}"
+    echo -e "${MAGENTA}0)${NC} All metrics"
+    
+    for i in "${!METRICS[@]}"; do
+        echo -e "${MAGENTA}$((i+1)))${NC} ${METRICS[$i]}"
+    done
+    
+    echo -e "\n${BOLD}Enter your choice (0 for all, or comma-separated numbers):${NC}"
+    read -p "→ " choices
+    
+    SELECTED_METRICS=()
+    if [[ "$choices" == "0" ]]; then
+        SELECTED_METRICS=("${METRICS[@]}")
+        log "INFO" "Selected all metrics"
+    else
+        IFS=',' read -ra NUMS <<< "$choices"
+        for num in "${NUMS[@]}"; do
+            if [[ $num =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le "${#METRICS[@]}" ]; then
+                SELECTED_METRICS+=("${METRICS[$((num-1))]}")
+            fi
+        done
+        log "INFO" "Selected ${#SELECTED_METRICS[@]} metrics"
+    fi
+    
+    display_section_header "DIMENSION SELECTION"
+    echo -e "${CYAN}${BOLD}Available Dimensions:${NC}"
+    echo -e "${MAGENTA}0)${NC} All dimensions"
+    
+    for i in "${!DIMENSIONS[@]}"; do
+        echo -e "${MAGENTA}$((i+1)))${NC} ${DIMENSIONS[$i]}"
+    done
+    
+    echo -e "\n${BOLD}Enter your choice (0 for all, or comma-separated numbers):${NC}"
+    read -p "→ " choices
+    
+    SELECTED_DIMENSIONS=()
+    if [[ "$choices" == "0" ]]; then
+        SELECTED_DIMENSIONS=("${DIMENSIONS[@]}")
+        log "INFO" "Selected all dimensions"
+    else
+        IFS=',' read -ra NUMS <<< "$choices"
+        for num in "${NUMS[@]}"; do
+            if [[ $num =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le "${#DIMENSIONS[@]}" ]; then
+                SELECTED_DIMENSIONS+=("${DIMENSIONS[$((num-1))]}")
+            fi
+        done
+        log "INFO" "Selected ${#SELECTED_DIMENSIONS[@]} dimensions"
+    fi
+    
+    display_section_header "GRANULARITY SELECTION"
+    echo -e "${CYAN}${BOLD}Select Granularity:${NC}"
+    echo -e "${MAGENTA}1)${NC} DAILY"
+    echo -e "${MAGENTA}2)${NC} MONTHLY"
+    
+    echo -e "\n${BOLD}Enter your choice [1-2]:${NC}"
+    read -p "→ " choice
+    
+    case $choice in
+        1) GRANULARITY="DAILY";;
+        2) GRANULARITY="MONTHLY";;
+        *) 
+            log "ERROR" "Invalid choice"
+            exit 1
+            ;;
+    esac
+    log "INFO" "Selected ${GRANULARITY} granularity"
+}
+
+upload_to_s3() {
+    echo -e "\n${BOLD}Enter S3 bucket name (or press Enter to skip):${NC}"
+    read -p "→ " S3_BUCKET
+    
+    if [[ -n "${S3_BUCKET}" ]]; then
+        local spinner_text="Uploading to S3..."
+        display_spinner "${spinner_text}"
+        if aws s3 cp "${OUTPUT_FILE}" "s3://${S3_BUCKET}/forecasts/$(basename ${OUTPUT_FILE})" >/dev/null 2>&1; then
+            echo
+            log "SUCCESS" "File uploaded to s3://${S3_BUCKET}/forecasts/$(basename ${OUTPUT_FILE})"
+        else
+            echo
+            log "ERROR" "Failed to upload to S3"
+            exit 1
+        fi
+    fi
+}
+
+generate_quicksight_manifest() {
+    local csv_s3_uri="s3://${S3_BUCKET}/forecasts/$(basename ${OUTPUT_FILE})"
+    local manifest_file="${OUTPUT_DIR}/manifest.json"
+    
+    log "INFO" "Generating QuickSight manifest file..."
+    local spinner_text="Creating manifest..."
+    display_spinner "${spinner_text}"
+    
+    cat > "${manifest_file}" << EOF
+{
+    "fileLocations": [
+        {
+            "URIs": [
+                "${csv_s3_uri}"
+            ]
+        }
+    ],
+    "globalUploadSettings": {
+        "format": "CSV",
+        "delimiter": ",",
+        "textqualifier": "\"",
+        "containsHeader": "true"
+    }
+}
+EOF
+
+    if [[ -n "${S3_BUCKET}" ]]; then
+        spinner_text="Uploading manifest to S3..."
+        display_spinner "${spinner_text}"
+        if aws s3 cp "${manifest_file}" "s3://${S3_BUCKET}/forecasts/manifest.json" >/dev/null 2>&1; then
+            echo
+            log "SUCCESS" "QuickSight manifest uploaded to s3://${S3_BUCKET}/forecasts/manifest.json"
+            display_section_header "QUICKSIGHT SETUP"
+            echo -e "${GREEN}${BOLD}QuickSight Import Instructions:${NC}"
+            echo -e "${CYAN}1.${NC} In QuickSight, create a new dataset"
+            echo -e "${CYAN}2.${NC} Choose 'S3' as the data source"
+            echo -e "${CYAN}3.${NC} Use this manifest URL: s3://${S3_BUCKET}/forecasts/manifest.json"
+            echo -e "${CYAN}4.${NC} Configure permissions to allow QuickSight to access the S3 bucket"
+        else
+            echo
+            log "ERROR" "Failed to upload manifest file to S3"
+        fi
+    else
+        echo
+        log "INFO" "Manifest file created locally at: ${manifest_file}"
+    fi
+}
+
+cleanup() {
+    log "INFO" "Cleaning up temporary files..."
+    rm -rf "${TEMP_DIR}"
+}
+
+main() {
+    clear
+    display_banner "AWS Cost Forecast Data Fetch Tool"
+    
+    # Set up trap for cleanup
+    trap cleanup EXIT
+    
+    check_prerequisites
+    get_time_period
+    select_options
+    
+    display_section_header "PROCESSING"
+    log "INFO" "Starting parallel forecast generation..."
+    process_forecast_parallel
+    
+    if [[ -f "${OUTPUT_FILE}" ]]; then
+        local records=$(wc -l < "${OUTPUT_FILE}")
+        display_section_header "RESULTS"
+        log "SUCCESS" "Generated forecast with $((records-1)) records"
+        
+        display_section_header "S3 UPLOAD"
+        upload_to_s3
+        
+        if [[ -n "${S3_BUCKET}" ]]; then
+            display_section_header "QUICKSIGHT CONFIGURATION"
+            generate_quicksight_manifest
+        fi
+    else
+        log "ERROR" "No forecast data generated"
+        exit 1
+    fi
+}
+
+main "$@"
diff --git a/terraform-modules/cid-dashboards/cost-forecast.tf b/terraform-modules/cid-dashboards/cost-forecast.tf
new file mode 100644
index 000000000..2595b9bb6
--- /dev/null
+++ b/terraform-modules/cid-dashboards/cost-forecast.tf
@@ -0,0 +1,66 @@
+resource "aws_cloudformation_stack" "cost_forecast_dashboard" {
+  count = contains(var.dashboards, "cost-forecast-dashboard") ? 1 : 0
+  name  = "cost-forecast-dashboard-${random_string.uid.result}"
+
+  parameters = {
+    QuickSightUserName      = var.quicksight_username
+    QuickSightIdentityRegion = var.quicksight_identity_region
+    AthenaDatabase          = var.athena_database
+    AthenaWorkGroup         = var.athena_workgroup
+    CURTableName            = var.cur_table_name
+    ForecastTableName       = var.forecast_table_name
+    S3BucketName            = var.s3_bucket_name
+    QuickSightTheme         = var.quicksight_theme
+  }
+
+  template_url = "https://aws-cudos-framework-deployment.s3.amazonaws.com/cfn-templates/cost-forecast-dashboard.yaml"
+
+  capabilities = ["CAPABILITY_NAMED_IAM"]
+
+  timeouts {
+    create = "60m"
+    update = "60m"
+    delete = "60m"
+  }
+
+  tags = var.tags
+}
+
+resource "aws_lambda_permission" "cost_forecast_lambda_permission" {
+  count         = contains(var.dashboards, "cost-forecast-dashboard") ? 1 : 0
+  statement_id  = "AllowExecutionFromCloudWatch"
+  action        = "lambda:InvokeFunction"
+  function_name = aws_cloudformation_stack.cost_forecast_dashboard[0].outputs["CostForecastFunction"]
+  principal     = "events.amazonaws.com"
+  source_arn    = "arn:aws:events:${var.region}:${data.aws_caller_identity.current.account_id}:rule/CostForecastScheduledRule-*"
+}
+
+resource "aws_s3_bucket_policy" "cost_forecast_bucket_policy" {
+  count  = contains(var.dashboards, "cost-forecast-dashboard") && var.s3_bucket_name != "" ? 1 : 0
+  bucket = var.s3_bucket_name
+
+  policy = jsonencode({
+    Version = "2012-10-17"
+    Statement = [
+      {
+        Effect = "Allow"
+        Principal = {
+          Service = "quicksight.amazonaws.com"
+        }
+        Action = [
+          "s3:GetObject",
+          "s3:ListBucket"
+        ]
+        Resource = [
+          "arn:aws:s3:::${var.s3_bucket_name}",
+          "arn:aws:s3:::${var.s3_bucket_name}/*"
+        ]
+        Condition = {
+          StringEquals = {
+            "aws:SourceAccount" = data.aws_caller_identity.current.account_id
+          }
+        }
+      }
+    ]
+  })
+}
diff --git a/terraform-modules/cid-dashboards/variables.tf b/terraform-modules/cid-dashboards/variables.tf
index de6b84a8c..8f4cf8608 100644
--- a/terraform-modules/cid-dashboards/variables.tf
+++ b/terraform-modules/cid-dashboards/variables.tf
@@ -1,68 +1,65 @@
-variable "stack_name" {
+variable "dashboards" {
+  description = "List of dashboards to deploy"
+  type        = list(string)
+  default     = ["cudos", "cost_intelligence_dashboard", "kpi_dashboard", "trends-dashboard", "cost-forecast-dashboard"]
+}
+
+variable "quicksight_username" {
+  description = "QuickSight user name"
   type        = string
-  description = "CloudFormation stack name for Cloud Intelligence Dashboards deployment"
+  default     = ""
 }
 
-variable "template_bucket" {
+variable "quicksight_identity_region" {
+  description = "QuickSight identity region"
   type        = string
-  description = "S3 bucket where the Cloudformation template will be uploaded. Must already exist and be in the same region as the stack."
+  default     = "us-east-1"
 }
 
-variable "template_key" {
+variable "athena_database" {
+  description = "Athena database name"
   type        = string
-  description = "Name of the S3 path/key where the Cloudformation template will be created. Defaults to cid-cfn.yml"
-  default     = "cid-cfn.yml"
+  default     = "athenacurcfn_cost_forecast"
 }
 
-variable "stack_parameters" {
-  type        = map(string)
-  description = <<-EOF
-    CloudFormation stack parameters. For the full list of available parameters, refer to
-    https://github.com/aws-samples/aws-cudos-framework-deployment/blob/main/cfn-templates/cid-cfn.yml.
-    For most setups, you will want to set the following parameters:
-      - PrerequisitesQuickSight: yes/no
-      - PrerequisitesQuickSightPermissions: yes/no
-      - QuickSightUser: Existing quicksight user
-      - QuickSightDataSetRefreshSchedule: Cron expression to refresh spice datasets daily outside of business hours. Default is 4 AM UTC, which should work for most customers in US and EU time zones
-      - CURBucketPath: Leave as default is if CUR was created with CloudFormation (cur-aggregation.yaml). If it was a manually created CUR, the path entered below must be for the directory that contains the years partition (s3://curbucketname/prefix/curname/curname/).
-      - OptimizationDataCollectionBucketPath: The S3 path to the bucket created by the Cost Optimization Data Collection Lab. The path will need point to a folder containing /optics-data-collector folder. Required for TAO and Compute Optimizer dashboards.
-      - DataBuketsKmsKeyArns: Comma-delimited list of KMS key ARNs ("*" is also valid). Include any KMS keys used to encrypt your CUR or Cost Optimization Data S3 data
-      - DeployCUDOSDashboard: (yes/no, default no)
-      - DeployCostIntelligenceDashboard: (yes/no, default no)
-      - DeployKPIDashboard: (yes/no, default no)
-      - DeployTAODashboard: (yes/no, default no)
-      - DeployComputeOptimizerDashboard: (yes/no, default no)
-      - PermissionsBoundary: Leave blank if you don't need to set a boundary for roles
-      - RolePath: Path for roles where PermissionBoundaries can limit location
-  EOF
+variable "athena_workgroup" {
+  description = "Athena workgroup name"
+  type        = string
+  default     = "primary"
 }
 
-variable "stack_tags" {
-  type        = map(string)
-  description = "Tag key-value pairs to apply to the stack"
-  default     = null
+variable "cur_table_name" {
+  description = "CUR table name"
+  type        = string
+  default     = "cost_and_usage_report"
 }
 
-variable "stack_policy_body" {
+variable "forecast_table_name" {
+  description = "Forecast data table name"
   type        = string
-  description = "String containing the stack policy body. Conflicts with stack_policy_url."
-  default     = null
+  default     = "cost_forecast_data"
 }
 
-variable "stack_policy_url" {
+variable "s3_bucket_name" {
+  description = "S3 bucket name for forecast data"
   type        = string
-  description = "Location of a file containing the stack policy body. Conflicts with stack_policy_body."
-  default     = null
+  default     = ""
 }
 
-variable "stack_notification_arns" {
-  type        = list(string)
-  description = "A list of SNS topic ARNs to publish stack related events."
-  default     = []
+variable "quicksight_theme" {
+  description = "QuickSight theme"
+  type        = string
+  default     = "MIDNIGHT"
 }
 
-variable "stack_iam_role" {
+variable "region" {
+  description = "AWS region"
   type        = string
-  description = "The ARN of an IAM role that AWS CloudFormation assumes to create the stack (default behavior is to use the previous role if available, or current user permissions otherwise)."
-  default     = null
+  default     = "us-east-1"
+}
+
+variable "tags" {
+  description = "Tags to apply to resources"
+  type        = map(string)
+  default     = {}
 }