npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@0x5278/blastradius

v0.1.1

Published

Find what a terraform plan actually breaks: BFS the plan's own dependency graph past the resources being changed.

Readme

blastradius

CI npm License: MIT

terraform plan tells you what it's changing. It doesn't tell you what breaks as a result. blastradius reads the plan's own dependency graph and BFS-traces every resource downstream of a delete/replace/update - including resources Terraform marks no-op, which can still fail at runtime when something they depend on vanishes.

-  DELETE  aws_security_group.db_sg  (blast risk: 18)
     └─ aws_db_instance.main  [depth 1, risk 9]
       └─ aws_db_instance.replica  [depth 2, risk 9]

That depth-2 catch - the read replica nobody was thinking about - is the entire point. terraform plan is depth-0 by design; it only lists what changes, not what breaks as a consequence.

Install

npm install -g @0x5278/blastradius
# or just: npx @0x5278/blastradius --plan plan.json

Usage

terraform plan -out=tfplan
terraform show -json tfplan > plan.json

blastradius --plan plan.json                  # human-readable CLI report
blastradius --plan plan.json --format markdown # for PR comments
blastradius --plan plan.json --format json     # for scripting

# or pipe directly, no intermediate file
terraform show -json tfplan | blastradius

Exit code is non-zero when any change has a totalRisk >= 20 (default threshold, override with --threshold), so it gates CI out of the box.

In CI

- run: terraform plan -out=tfplan
- run: terraform show -json tfplan > plan.json
- run: npx @0x5278/blastradius --plan plan.json --format markdown >> $GITHUB_STEP_SUMMARY
- run: npx @0x5278/blastradius --plan plan.json   # exits 1 if totalRisk >= 20

PR reviewers see the risk table before approving, not after the incident.

As a library

const { run, formatReport } = require('@0x5278/blastradius');

const results = run(planJsonString, { minSeverity: 'update' });
console.log(formatReport(results, 'cli'));

results is an array, one entry per qualifying change:

{
  address: 'aws_security_group.db_sg',
  type: 'aws_security_group',
  severity: 'delete',
  totalRisk: 18,
  affected: [
    { address: 'aws_db_instance.main', type: 'aws_db_instance', depth: 1, risk: 9 },
    { address: 'aws_db_instance.replica', type: 'aws_db_instance', depth: 2, risk: 9 },
  ],
}

Options:

  • minSeverity: skip changes below this severity (create, update, replace, delete). Default: create.
  • includeNoOps: include changes whose only action is no-op (can still fail at runtime when a dependency is deleted). Default: false.

How it works

lib/parser.js    validate plan JSON, extract resource_changes + configuration
lib/graph.js     walk expressions[].references recursively -> reverse dependency graph
lib/analyzer.js  BFS from each change over the reverse graph, score by resource type
lib/report.js    cli / json / markdown formatters
bin/cli.js       stdin or --plan, exits non-zero above the risk floor
main.js          library entry point

The reference graph isn't reconstructed from HCL - Terraform's own plan JSON already contains it under configuration.root_module.resources[].expressions.*.references. blastradius walks data that is already there.

Module calls are recursed too: configuration.root_module.module_calls[name].module is walked with address flattening, so module.ec2.aws_security_group.sg and outputs (module.ec2.main_arn) resolve correctly across module boundaries.

Risk scoring is a static weight table per resource type, summed over the affected dependents. It is deliberately a guess; the long-term plan is to train these weights off a team's own incident history.

Try it

git clone https://github.com/JoeyKoch1/blastradius.git
cd blastradius
npm install
npm run example

Runs against examples/example-plan.json - a security group deletion that cascades through an RDS instance to a read replica two hops away - and examples/example-module-plan.json, the same scenario with the replica reached through a module boundary.

Known limitations / roadmap

  • for_each/count addresses are normalized (index suffixes are stripped when matching references), but the index itself is not derived from expressions.
  • Risk weights are hardcoded guesses, not learned from anything. The real long-term differentiator is training these off a team's own incident history instead of a static table.
  • No cross-state support. Graphs that span terraform_remote_state boundaries are not stitched together.

License

MIT - see LICENSE.