Visualizing Open Source Licenses to Analyze Compliance and Reduce Legal Risk

Managing open-source license compliance in large projects is complex. Dependencies pull in other dependencies, often hundreds or thousands, making it nearly impossible to track every license manually. Hidden obligations buried in transitive dependencies can slip into your application without you realizing, potentially introducing restrictive terms or legal risks.

Today, we’re releasing license-kit visualize, a CLI tool that scans your project, maps the full dependency graph, and presents an interactive view of licenses for every package. It lets you explore subgraphs, review license categories, generate AI-assisted summaries, and spot potential risks early. It gives developers, maintainers, and legal teams the clarity they need to ensure compliance.

The tool will open a local web interface with your dependency graph, license breakdowns, and detailed package information. Whether you need to eliminate a problematic dependency, understand the structure of your project, or prepare a compliance report, this visualization makes it easier to act on complex license data.

To get started, run:

npx license-kit visualize

or continue reading to learn more about how it works and why it matters.

Use Cases

Example use cases of the visualize command could be as follows:

  • Having an overview of your dependencies: it’s important that you know what’s happening.
  • Eliminating a single package: due to cyclic nature of node_modules dependencies graph, it's not always enough to just remove a dependency, as it may be required by other dependencies. Thanks to visualization, you can see which packages depend on it and try to replace that subgraph with alternative packages that would allow you to achieve the same, but are offered under more suitable licenses for your case
  • Reviewing the level of permissiveness within your dependencies and the relations between them.
  • Viewing the relations between packages themselves: you may see unnecessary packages that are duplicates in terms of offered functionalities; maybe you would be able to migrate to the ones already introduced to your project to flatten this graph & benefit from a smaller bundle size.

Anatomy of Open Source dependencies

A typical application using Open Source software is a project (your package.json) bringing in a set of dependencies you are using in your code. These dependencies, however, introduce others and so on. Such dependencies are typically called transitive dependencies. Thankfully, license-kit handles transitive dependencies for you.

Before we proceed, we have to define the term dependency. By a dependency in this article, we will mean an ordered pair (package, version). A single package, e.g., X, may be present N times in the project in different versions; therefore, it’s crucial to distinguish unique combinations thereof. Each combination may even be distributed under a different license. Sounds overstretched? Not really, you might not have known that, but React itself was licensed under BSD + patents for versions ≤ 15.X (15.3.2 license here) and changed its licensing model starting from 16.0.0 to MIT (19.1.0 license here).

Keep in mind this may happen unattended anytime you do npm i (or the equivalent in your package manager), since the resolutions may change (e.g., a package depending on X@^6.1.0 without changes to your package.json  may once resolve to 6.1.0 and the next time you run it, if patch upgrade(s) had been published in the meantime, it may resolve e.g., to 6.1.5).

Moreover, as you probably know, dependencies in a project form a rooted graph structure, which is a graph with one node (vertex) designated as the root. The root is your package.json, which introduces dependencies, which in turn bring in transitive dependencies and so on; therefore, each node (dependency) has relations (edges) to other nodes (their dependencies). Notice that I mentioned it’s just a graph, which has directed relations (from parents to their dependencies); ideally, it should be a directed acyclic graph (DAG), yet rarely it may happen that poorly designed packages may finally introduce dependency cycles. This structure cannot be called a true tree since it collides with the definition:

[…] the remaining nodes (excluding the root) are partitioned into m ≥ 0 disjoint sets […]

Source: Donald Knuth. The Art of Computer Programming: Fundamental Algorithms, Third Edition. Addison-Wesley, 1997. ISBN 0-201-89683-4 . Section 2.3: Trees, pp. 308–423.

The disjoint requirement forces that each node can only belong to one of the m subtrees, which is violated by one entirely possible edge case: a situation in which a dependency is introduced by multiple packages at once, resolving to that same version each time. Such a case can be seen below, where side-channel-map depends on call-bound and get-intrinsic, but also call-bound itself depends on get-intrinsic:

In the visualize tool, we support all such cases thanks to the logic handling both this and other “edge cases”, such as monorepositories or multiple versions of the same package being installed at once in our API package @callstack/licenses that powers both the license-kit CLI and our react-native-legal package.

‍

Getting Started

To have full control and complete knowledge about what licenses are present in your dependency graph (and why), you can use the visualizer tool. To run it, just run npx license-kit to use a temporary installation of it, or add it as a dev dependency to your project if you plan to use it more often in your project.

Then, you can visualize your dependency graph by running npx license-kit visualize, which will launch a local web server providing a web GUI for analysis and open the webpage by default.

Loading the report

You will be greeted with the following screen:

You can either drag-and-drop a report generated with npx license-kit report ... --output report.json or use the “auto-load from the server” button for the visualize command to scan the package.json in your current working directory. The lockfile (of any package manager you might be using) will be watched for changes to auto-regenerate and stream the new report with Server-Sent Events (SSE) to all connected browser sessions.

The visualize command supports all scan-related flags that report does as well. For instance, you can point it to the directory containing a package.json file by passing --root /path/to/project. For a list of all options (including dependency type filters), run npx license-kit --help or check out this article on our blog. Bind hostname & port can be adjusted with --host and --port, respectively.

Features

Interactive package preview

After loading the report (which may take a few seconds, depending on the size of your project, due to rendering a large quantity of nodes and edges), you will see the graph centered at your root package node and a sidebar presenting you with various accordion sections and a detailed view of the last-hovered node:

With the details view, you will be able to quickly review the full license text of a package, its license category, resolved and specified versions, its type (dependency / dev / optional / transitive dependency), author and description.

Licenses & graph state overview

Breakdown of the share of licenses in general and within license type categories, giving you an overview of what the possible culprits for your case are.

License statistics

Another tool is a visualization of specific license types shares within categories & in general.

This tool allows you to have a visual overview of what is going on within the licenses in your project.

AI-turbocharged project state summary

The last tool is an AI-turbocharged summary generator that summarizes the licenses-packages graph using the in-browser Summarization API (currently only available in Chrome or Chromium-based browsers). This means you can use a local, browser-provided API for summarizing the findings and have a quick-start at what to look at in the graph.

Of course, as always with Language Models (LLMs), be aware that the outputs may not be accurate or may not be complete.

Browsing a subgraph

To easily review the subgraph of a package, click it to filter the graph just to the subgraph rooted at that node. The tool will automatically trace a path from that node up to the project root to visualize the full trace of why this package was included in the project. In cases when a package has multiple parents at once (like below), all paths will be included.

Summary

The license-kit visualize gives you a clear, interactive view of your project’s dependency graph and the licenses within it—helping you spot restrictive terms, duplicates, and hidden obligations before they become issues. With subgraph exploration, license statistics, and AI-assisted summaries, it streamlines compliance checks for developers, maintainers, and legal teams alike.

Check out the repo on Github, give it a star, and start exploring your own project’s licenses today.

Insights

Learn more about Open Source

cover

Mar 26Podcast

How Definitely Typed Changed TypeScript Forever

Discover the story behind Definitely Typed with its creator, Boris Yankov, and learn how it became essential for type-safe JavaScript in the TypeScript ecosystem.

cover

Oct 14Article

Introducing the OMH Cloud Storage Module

Discover the OMH Cloud Storage Module. This open-source solution simplifies cloud storage integration for React Native apps.

cover

Jul 12Article

Introduction to the React Native OMH Maps Library

Discover how the React Native OMH Maps library simplifies map integration with cross-platform compatibility, ease of use, and customization options.

cover

Apr 22Podcast

Behind the Scenes of React Native 0.74 Release

Join the release crew members to find out what new features and improvements React Native 0.74 brings to the cross-platform development world.

cover

Apr 27Podcast

Callstack OSS Update

April 2023 Callstack OSS Update: RFC for Expo Config Plugins, Re.Pack & Paper news.

cover

Dec 6Article

React Native Paper 5.0 - What’s New?

React Native Paper 5.0 is here! Dive into the latest updates and improvements.

cover

Feb 8Article

Stripe React Native: the Most Common Questions - Tipsi Migration Guide, Part 5

Check out the list of the most common questions about Stripe react Native Library prepared by Jakub Kłobus, software engineer at Callstack.

cover

Feb 6Article

Stripe React Native Migration Function by Function - Tipsi Migration Guide, Part 3

In the third part of the Tipsi Migration Guide we describe the Stripe React Native migration function by function.

cover

Dec 6Article

Stripe React Native Configuration - Tipsi Migration Guide, Part 2

In the second part of the Tipsi Migration Guide by Callstack, you'll learn how to properly configure the stripe-react-native library.

cover

Mar 19Tutorial

The Hard Way vs. The React Native AI SDK Way: Stop Writing Custom Modules for Every Model

Learn how React Native AI uses a unified provider model to switch between cloud and on-device LLMs without rewriting application logic, enabling reliable AI experiences online and offline.

cover

Mar 12Tutorial

Build Smarter Apps: Tool Calling & AI Orchestration Explained

Learn how on-device models in React Native can call tools, interact with external APIs, and return structured outputs you can use directly in application logic.

cover

Mar 5Tutorial

MLC LLM + React Native: On-Device AI Without the Pain

Learn how to run third-party on-device LLMs in React Native using MLC LLM. Choose your models, run them efficiently across platforms, and keep a unified JavaScript API with React Native AI.

cover

Feb 24Tutorial

Intelligent Fallbacks with Apple Intelligence in React Native

Learn how to use Apple’s built-in Foundation Models in React Native apps, reduce memory usage, and enable fast, fully on-device AI with React Native AI Apple.

cover

Feb 10Tutorial

What Is the React Native AI SDK? A Complete Intro & Quickstart

Learn why on-device AI matters for React Native apps, how local LLMs behave offline, and what problems React Native AI is designed to solve from day one.

cover

Jan 29Tutorial

Implementing an Android TurboModule with Kotlin

Learn how to implement a React Native TurboModule on Android, from the TypeScript spec and Codegen to the Kotlin implementation and package registration.

cover

Jan 19Tutorial

Working with Different Threads in Swift TurboModules

Learn how JavaScript, native module, background, and main threads interact in React Native TurboModules, and how to use GCD queues to run async work safely in Swift.

cover

Jan 9Tutorial

How to Add Type-Safe Constants to Swift TurboModules

Learn how to expose typed, immutable constants from a Swift TurboModule using Codegen, and get full end-to-end type safety between native and JavaScript.

cover

Dec 30Tutorial

Adding Event Emitters to Your TurboModule in Swift

Learn how to emit native events from a Swift TurboModule and subscribe to them in JavaScript, including proper memory management and Codegen integration.

cover

Dec 22Tutorial

Writing Your First TurboModule in Swift

Learn how to build a fully working TurboModule in Swift, integrate it with Codegen, and bridge it through Objective‑C inside an Expo app.