The CI Diet Plan: 5 Code Smells to Eliminate—& How to Keep Them Off for Good
Barrel files, wildcard imports, and deep-relative paths can keep your CI pipeline in the red no matter how smart your Nx/Bazel/Turborepo cache is. This guide shows you how to detect five high-impact “build-bloat” smells, track their burndown in Codemod Insights, and reclaim double-digit minutes from every build—without touching your build-tool flags.
Why prune flags can’t fix code-level calories
Nx’s affected:build
, Bazel’s remote cache, and Turborepo’s hashing are great at skipping work, but they trust that your source tree is lean.
Code patterns that balloon dependency graphs—barrel re-exports, wildcard imports, fixtures living in src/
—force “clean” rebuilds even when nothing meaningful changed.
Getting Started: Baseline your build time
- Grab today’s CI average
gh api repos/:owner/:repo/actions/runs --paginate \\-q '[.workflow_runs[].run_duration_ms] | add / 60000'# → prints average minutes per workflow run
- Spin up a “CI Diet” dashboard in Codemod Insights
- Go to Insights → Create Dashboard and name it
CI Diet
. - For each smell below, create a Timeseries widget:
- Rule type:
ast-grep
- Edit rule → add ast-grep YAML rule
- Match type:
Match Count
(default) - Repo → select your project’s repository
- Query name: use the smell name or any label you prefer
- Optional:
- Group by codeowners
- Filter: add include/exclude glob patterns
- Rule type:
- Optional: create one Single-Number widget that holds all five queries (A-E) inside itself, then set the formula to
A+B+C+D+E
. That widget will show the aggregate bloat count at a glance.
- Go to Insights → Create Dashboard and name it
You now have a chart-per-smell that updates on every push—perfect for sharing progress with the team.
The Five Biggest Offenders & Ready-to-Use Rules
Paste each YAML block into Edit Rule when configuring the widget.
An example dashboard. Note that you can estimate time/cost savings using Insights' forumlas based on your own CI build costs.
#1 Barrel Re-exports
Pattern: export * from "./lib"
Open in Codemod Studio
Impact: Touching any file inside the barrel's folder invalidates every downstream import.
#2 Wildcard Imports
Pattern: import * as _ from "lodash"
, default import
of whole libs Open in Codemod Studio
Impact: Pulls whole sub-modules → bigger bundles, more hash misses.
#3 Deep Relative Paths
Pattern: ../../../../utils
Open in Codemod Studio
Impact: Signals leaky boundaries; more files marked "dirty."
#4 Test Fixtures Inside src/
Pattern: __fixtures__/
Open in Codemod Studio
Impact: Large JSON/images counted in production hash.
#5 Duplicate CSS-in-JS Blocks
Pattern: CSS-in-JS blocks > 5 KB Open in Codemod Studio
Impact: Re-computes style hash on every consumer.
Each widget instantly shows how many matches live in the repo commit by commit—no builds required.
Mini-Benchmark: How much time can you save?
Capture a clean baseline
Fetch the last 200 successful runs of your main workflow:
WORKFLOW_ID=<your_main_workflow_id> # grab this from the Actions UIgh api /repos/$ORG/$REPO/actions/workflows/$WORKFLOW_ID/runs \-q '.workflow_runs[] | select(.conclusion=="success") | .run_duration_ms' \--paginate > baseline.txt
Create a ci-diet
branch and fix the five smells
1. Open Codemod Insights → create a dashboard → add the five ast-grep widgets (barrel, wildcard, deep-path, fixtures, CSS-dup).
2. Sort widgets by match-count so the worst offenders surface first.
3. In your repo:
git checkout -b ci-diet
4. For each smell (worst offenders first), look for matches (using Run in CLI in Codemod Studio), refactor it (either manually or by creating a codemod with Codemod Studio), commit, repeat until the count drops.
git add -Agit commit -m "CI diet: trim barrel imports" # example message
5. Push and open a draft PR:
git push -u origin ci-diet
Let CI run at least ten times
Merge a couple of trivial PRs or re-run the workflow so the new branch accrues ~10 runs—enough to smooth out network variance.
Pull the “diet” timings
gh api /repos/$ORG/$REPO/actions/workflows/$WORKFLOW_ID/runs \-q '.workflow_runs[]| select(.conclusion=="success" and .head_branch=="ci-diet")| .run_duration_ms' \--paginate > diet.txt
Crunch the numbers
old=$(jq -s 'add/length' baseline.txt) # average baseline msnew=$(jq -s 'add/length' diet.txt) # average diet msweekly_builds=50 # adjust to match your teamprintf "⏱️ Saved %.0f s per build\n" $(( (old-new)/1000 ))printf "📉 ≈%.1f min reclaimed per week\n" \$(bc -l <<< "scale=1; ($old-$new)/60000 * $weekly_builds")
Example: trimming just 30 s off a pipeline that runs 50 times a week frees ~25 min weekly → ~21 hrs yearly of engineer waiting time.
Ready to try it?
Run a free Insights scan on your repo, paste the barrel-file rule, and see your first bloat metric in < 10 minutes—free-tier available. Get started now
Codemod Insights
Plan and track your code migrations like never before. Spin up a custom dashboard with Codemod AI in under a minute—or reach out for advanced fleet-wide intelligence and migration support.