Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

34 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

costctl

Database cost optimization CLI. Scan your warehouse, find waste, fix it.

Created by Arthi Arumugam

PyPI version Python version License: MIT

English | 中文 | 日本語 | हिन्दी | 한국어 | Español | Français | Deutsch | Italiano | Português | Nederlands | Polski | Русский | Türkçe | Svenska | العربية | বাংলা | اردو | தமிழ் | فارسی | עברית | Bahasa Indonesia | Tiếng Việt | ไทย | Filipino | Bahasa Melayu | Українська | Ελληνικά | Čeština | Română | Magyar | Dansk | Norsk | Suomi | Kiswahili


costctl scans your database infrastructure, identifies cost optimization opportunities, and generates actionable fixes — across BigQuery, Snowflake, PostgreSQL, Databricks, Redshift, and MySQL.

costctl dashboard showing savings by analyzer, severity breakdown, and findings table


Install

pip install "costctl[bigquery]"      # Google BigQuery
pip install "costctl[snowflake]"     # Snowflake
pip install "costctl[postgres]"      # PostgreSQL
pip install "costctl[databricks]"    # Databricks (Unity Catalog)
pip install "costctl[redshift]"      # Amazon Redshift
pip install "costctl[mysql]"         # MySQL
pip install "costctl[all]"           # all database backends
pip install "costctl[web]"           # web dashboard (Flask)

Quick Start

# Scan using a named connection from .costctl.yaml
costctl scan --connection prod-bq

# Scan with inline flags
costctl scan --type bigquery --project my-gcp-project --dataset production

# Save results for later comparison
costctl scan --type snowflake --account xy12345 --warehouse WH --save baseline.json

What It Finds

costctl runs 6 analyzers against your database metadata and query history:

Analyzer What it detects Example fix
Partitioning Tables missing date/range partitions that would reduce scan bytes PARTITION BY DATE(event_date)
Clustering Columns queried in WHERE/JOIN that aren't clustered CLUSTER BY (customer_id, status)
Query Patterns Repeated full-table scans, SELECT *, expensive recurring queries Column-specific SELECT lists
Idle Tables Tables not read or written in N days (configurable) DROP TABLE or archive
Storage Bloated tables, vacuum gaps, excessive retention, redundant snapshots VACUUM, retention policies
Resources Oversized warehouses, always-on compute, unutilized reserved slots Downsize or auto-suspend

Each finding includes an estimated monthly savings in USD and a ready-to-run DDL fix where applicable.


Commands

costctl scan        Scan for cost issues and estimate savings
costctl plan        Generate a JSON remediation plan
costctl apply       Execute fixes interactively (with confirmation prompts)
costctl report      Generate a report (terminal, JSON, or CSV)
costctl diff        Compare two scans to track progress over time
costctl forecast    Predict cost trends from scan history
costctl dashboard   Launch a web UI with charts, filters, and sorting

Example Output

$ costctl scan --connection prod-bq

costctl v0.1.0  |  connection: prod-bq

Scanning 142 tables across datasets: production, analytics...

  PARTITIONING
  x  production.events          Add daily partition on event_date  -> save ~$420/mo
  x  analytics.pageviews        Add daily partition on ts          -> save ~$180/mo

  CLUSTERING
  x  production.orders          Cluster on (customer_id, status)   -> save ~$95/mo

  IDLE TABLES  (>30 days unused)
  x  analytics.temp_export_2024     last read: 94 days ago  (12 GB)
  x  production.legacy_sessions     last read: 61 days ago  (3.4 GB)

  QUERY PATTERNS
  x  3 queries use SELECT * on tables >10 GB
  x  1 recurring query scans 2.1 TB/day -- add partition filter

  Total estimated savings:  $695-$740 / month
  Issues found: 8   |   Run 'costctl plan' to generate fixes

Diff and Forecast

Track cost changes over time by saving scans and comparing them:

# Compare two saved scans — see what's resolved, new, or remaining
costctl diff before.json after.json

# Compare a baseline against a live scan
costctl diff --baseline baseline.json --type bigquery --project my-proj

# Forecast cost trends from 2+ snapshots
costctl forecast scan-jan.json scan-feb.json scan-mar.json --json

Web Dashboard

Launch an interactive dashboard from any saved scan file:

# Single scan
costctl dashboard scan-results.json

# Multiple scans — adds a cost trend chart
costctl dashboard scan-jan.json scan-feb.json scan-mar.json --port 8080

costctl web dashboard with charts, filters, and sortable findings table

Dashboard features:

  • Savings by analyzer (bar chart) and severity breakdown (doughnut chart)
  • Cost trend line when comparing multiple scans
  • Filter by severity, analyzer, or database type
  • Click any column header to sort
  • JSON API at /api/findings

costctl dashboard with cost trend chart comparing before and after scans


GitHub Action

Run costctl in CI to catch cost regressions automatically:

- name: Scan for cost issues
  uses: arthi-arumugam-git/costctl@main
  with:
    type: bigquery
    connection-args: "--project my-proj --dataset production"
    format: json
    fail-on-critical: "true"

The action outputs findings-count, critical-count, and total-savings for use in downstream steps. See action.yml for all inputs and outputs.


Output Formats

costctl report --type bigquery --project my-proj              # terminal (default)
costctl report --type bigquery --project my-proj --json       # JSON
costctl report --type bigquery --project my-proj --csv        # CSV
costctl scan --type snowflake --account X --save results.json # save to file

Configuration

Create .costctl.yaml in your project root or ~/.costctl.yaml for global config:

connections:
  prod-bq:
    type: bigquery
    project: my-gcp-project
    datasets: [production, analytics]

  prod-snowflake:
    type: snowflake
    account: xy12345.us-east-1
    warehouse: ANALYTICS_WH

  prod-pg:
    type: postgres
    host: prod-db.example.com
    database: myapp

  prod-databricks:
    type: databricks
    host: adb-123.azuredatabricks.net
    http_path: /sql/1.0/warehouses/abc
    token: dapi...
    catalog: main

  prod-redshift:
    type: redshift
    host: cluster.abc.us-east-1.redshift.amazonaws.com
    database: analytics
    user: admin
    password: ${REDSHIFT_PASSWORD}

  prod-mysql:
    type: mysql
    host: db.example.com
    database: myapp
    user: readonly
    password: ${MYSQL_PASSWORD}

thresholds:
  stale_days: 30            # days before a table is considered idle
  large_table_gb: 100       # tables above this get extra scrutiny
  expensive_query_tb: 1     # queries scanning more than this trigger a finding
  databricks_dbu_rate: 0.22 # cost per DBU for Databricks savings estimates

Contributing

git clone https://github.com/arthi-arumugam-git/costctl.git
cd costctl
pip install -e ".[dev]"
pytest

301 tests across all connectors, analyzers, reporters, and CLI commands. Contributions, bug reports, and feature requests are welcome. Please open an issue before submitting a large pull request.


License

MIT — see LICENSE.

About

cost monitoring and optimization tool

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages