<!-- mobian-agent-page publisher="dailydev" canonical="https://daily.dev/posts/how-to-build-a-code-graph-in-typescript-using-vs-code-s-language-apis-1zkruisbx" -->

---
title: How to Build a Code Graph in TypeScript Using VS Code&#x27;s...
description: A step-by-step tutorial walks through building a VS Code extension that models a TypeScript codebase as a call graph, using VS Code&#x27;s built-in language APIs...
canonical: https://daily.dev/posts/how-to-build-a-code-graph-in-typescript-using-vs-code-s-language-apis-1zkruisbx
twitter:card: summary_large_image
twitter:site: @dailydotdev
og:type: website
og:site_name: daily.dev
og:title: How to Build a Code Graph in TypeScript Using VS Code&#x27;s Language APIs | daily.dev
og:description: A step-by-step tutorial walks through building a VS Code extension that models a TypeScript codebase as a call graph, using VS Code&#x27;s built-in language APIs...
og:url: https://daily.dev/posts/how-to-build-a-code-graph-in-typescript-using-vs-code-s-language-apis-1zkruisbx
og:image: https://api.daily.dev/og/posts/1zKruISbx.png
og:image:alt: How to Build a Code Graph in TypeScript Using VS Code&#x27;s Language APIs
og:image:width: 1200
og:image:height: 630
og:locale: en
---

> ## Documentation Index
> Fetch the complete documentation index at: https://daily.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# How to Build a Code Graph in TypeScript Using VS Code's Language APIs

**[freeCodeCamp](https://daily.dev/sources/freecodecamp)** · 22 min read · 0 upvotes · 0 comments

## Summary

A step-by-step tutorial walks through building a VS Code extension that models a TypeScript codebase as a call graph, using VS Code's built-in language APIs rather than writing a custom parser. It covers using commands like vscode.executeDocumentSymbolProvider, vscode.prepareCallHierarchy, and the incoming/outgoing call APIs to discover functions and methods, designing a graph data model with stable symbol IDs, traversing the call graph with BFS while handling concurrency and cycles, bounding graph size, filtering out dependency directories, handling stale call hierarchy state, rendering results in a VS Code Webview with ELK for layout, and testing the crawler against a mocked language service. It closes by noting the limitations of static call-graph analysis (dynamic dispatch, reflection, event emitters, etc.) and links to a working open-source implementation on GitHub.

## Full article

daily.dev links to this article rather than hosting it. Read it at the original source: <https://www.freecodecamp.org/news/how-to-build-a-code-graph-in-typescript-using-vs-code-language-apis>

## Questions this post answers

### How do I get a list of function callers in a TypeScript file using VS Code's extension API?

Use the vscode.prepareCallHierarchy command to resolve a cursor position to a CallHierarchyItem, then pass that item to vscode.provideIncomingCalls to get the calling symbols, or vscode.provideOutgoingCalls for callees. These built-in commands delegate to the TypeScript language service, so no custom parser is needed to resolve calls across imports, files, and classes.

_daily.dev surfaces deep dives like this for developers building editor tooling around call hierarchies._

### Why do some function calls disappear from a call hierarchy graph built with VS Code's APIs?

A CallHierarchyItem is tied to language-service session state, and if that state goes stale, calling provideIncomingCalls or provideOutgoingCalls on it can silently return an empty array instead of an error. The fix is storing plain NodeRef data instead of live items, tracking an epoch counter per item to detect staleness, and retrying with a freshly prepared item when a result looks suspiciously empty.

_developers debugging flaky language-tooling integrations can track these patterns through daily.dev._

### How do I avoid infinite loops when traversing a call graph with cycles using BFS?

Instead of a simple visited Set, track the remaining traversal depth per node in a Map keyed by direction and node id, and only revisit a node when the new traversal can go deeper than a prior visit did. This lets BFS safely handle real codebases with cycles while still exploring nodes that were previously cut off too early.

_daily.dev helps engineers researching graph traversal techniques keep useful implementation details handy._

## Similar posts on daily.dev

- [Enforce TypeScript Architecture Boundaries via AST Import Graphs](https://daily.dev/posts/enforce-typescript-architecture-boundaries-via-ast-import-graphs-3k2xiuqvu) · SitePoint · 1 upvotes · 0 comments
- [Untapped Way to Learn a Codebase: Build a Visualizer](https://daily.dev/posts/untapped-way-to-learn-a-codebase-build-a-visualizer-maesktxb7) · Hacker News · 3 upvotes · 0 comments
- [How do you visualize a TypeScript dependency graph?](https://daily.dev/posts/how-do-you-visualize-a-typescript-dependency-graph--ygrmcfywr) · LogRocket · 5 upvotes · 0 comments
- [Set up a live code editor in Next.js with CircleCI](https://daily.dev/posts/set-up-a-live-code-editor-in-next-js-with-circleci-dbot2nebo) · CircleCI · 0 upvotes · 0 comments

---

Tags: [#typescript](https://daily.dev/tags/typescript), [#lsp](https://daily.dev/tags/lsp)

[View this post on daily.dev](https://daily.dev/posts/how-to-build-a-code-graph-in-typescript-using-vs-code-s-language-apis-1zkruisbx)

```json
{"@context":"https://schema.org","@graph":[{"@type":"Organization","@id":"https://daily.dev/#organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180},"sameAs":["https://twitter.com/dailydotdev","https://github.com/dailydotdev","https://www.linkedin.com/company/daily-dev-ltd"]},{"@type":"WebSite","@id":"https://daily.dev/#website","url":"https://daily.dev","name":"daily.dev","publisher":{"@id":"https://daily.dev/#organization"},"potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://daily.dev/search?q={search_term_string}"},"query-input":"required name=search_term_string"}}]}
{"@context":"https://schema.org","@type":"TechArticle","headline":"How to Build a Code Graph in TypeScript Using VS Code's Language APIs","url":"https://daily.dev/posts/how-to-build-a-code-graph-in-typescript-using-vs-code-s-language-apis-1zkruisbx","mainEntityOfPage":{"@type":"WebPage","@id":"https://daily.dev/posts/how-to-build-a-code-graph-in-typescript-using-vs-code-s-language-apis-1zkruisbx"},"datePublished":"2026-10-01T14:19:19.274Z","dateModified":"2026-10-01T14:19:42.596Z","description":"A step-by-step tutorial walks through building a VS Code extension that models a TypeScript codebase as a call graph, using VS Code's built-in language APIs...","image":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e7ad8bc9bb939cb0ad7e546a30e4e3b9?_a=AQAEuop","thumbnailUrl":"https://media.daily.dev/image/upload/f_auto,q_auto/v1/posts/e7ad8bc9bb939cb0ad7e546a30e4e3b9?_a=AQAEuop","isAccessibleForFree":true,"articleSection":"freeCodeCamp","inLanguage":"en","publisher":{"@type":"Organization","name":"daily.dev","url":"https://daily.dev","logo":{"@type":"ImageObject","url":"https://daily.dev/apple-touch-icon.png","width":180,"height":180}},"author":{"@type":"Organization","name":"freeCodeCamp","logo":"https://media.daily.dev/image/upload/t_logo,f_auto/v1628412854/logos/freecodecamp","url":"https://daily.dev/sources/freecodecamp"},"commentCount":0,"discussionUrl":"https://daily.dev/posts/how-to-build-a-code-graph-in-typescript-using-vs-code-s-language-apis-1zkruisbx","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":0},{"@type":"InteractionCounter","interactionType":{"@type":"CommentAction"},"userInteractionCount":0}],"keywords":"typescript,lsp","timeRequired":"PT22M"}
{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://daily.dev"},{"@type":"ListItem","position":2,"name":"freeCodeCamp","item":"https://daily.dev/sources/freecodecamp"},{"@type":"ListItem","position":3,"name":"How to Build a Code Graph in TypeScript Using VS Code's Language APIs"}]}
{"@context":"https://schema.org","@type":"FAQPage","@id":"https://daily.dev/posts/how-to-build-a-code-graph-in-typescript-using-vs-code-s-language-apis-1zkruisbx#faq","mainEntity":[{"@type":"Question","name":"How do I get a list of function callers in a TypeScript file using VS Code's extension API?","acceptedAnswer":{"@type":"Answer","text":"Use the vscode.prepareCallHierarchy command to resolve a cursor position to a CallHierarchyItem, then pass that item to vscode.provideIncomingCalls to get the calling symbols, or vscode.provideOutgoingCalls for callees. These built-in commands delegate to the TypeScript language service, so no custom parser is needed to resolve calls across imports, files, and classes. daily.dev surfaces deep dives like this for developers building editor tooling around call hierarchies."}},{"@type":"Question","name":"Why do some function calls disappear from a call hierarchy graph built with VS Code's APIs?","acceptedAnswer":{"@type":"Answer","text":"A CallHierarchyItem is tied to language-service session state, and if that state goes stale, calling provideIncomingCalls or provideOutgoingCalls on it can silently return an empty array instead of an error. The fix is storing plain NodeRef data instead of live items, tracking an epoch counter per item to detect staleness, and retrying with a freshly prepared item when a result looks suspiciously empty. developers debugging flaky language-tooling integrations can track these patterns through daily.dev."}},{"@type":"Question","name":"How do I avoid infinite loops when traversing a call graph with cycles using BFS?","acceptedAnswer":{"@type":"Answer","text":"Instead of a simple visited Set, track the remaining traversal depth per node in a Map keyed by direction and node id, and only revisit a node when the new traversal can go deeper than a prior visit did. This lets BFS safely handle real codebases with cycles while still exploring nodes that were previously cut off too early. daily.dev helps engineers researching graph traversal techniques keep useful implementation details handy."}}]}
```

