Inside TypeDB Studio: Part 1 - Architecture

TypeDB Studio is the official interactive environment for TypeDB – a database that reimagines data modelling around entities, relations, and attributes rather than tables or documents. Studio gives developers a visual, multi-modal interface for building TypeQL queries, visualising schema and exploring data instances, all from the browser or as a native desktop app.
This post is a deep dive into how Studio is built: the technology choices, the architectural patterns, and the engineering tradeoffs behind a tool that aims to make TypeDB convenient and easy to use for all.
The Stack at a Glance
| Layer | Technology | Why? |
|---|---|---|
| Core | Angular 20 | Mature, battle-tested framework backed by Google, strongly typed all the way down |
| Language | TypeScript 5.8 (strict) | For strongly typed frontend development |
| Styling | SCSS + Angular Material 20 | To make use of what Angular provides out of the box |
| Code editor | CodeMirror 6 + TypeDB Lezer grammar | State of the art open-source modular code editor framework |
| Graph visualisation | Sigma.js, Graphology | Modular graphics and graphing OSS packages |
| Database connectivity | @typedb/driver-http (HTTP API) | The official HTTP TypeScript driver for TypeDB |
| Desktop shell | Tauri 2 (Rust) | Very slim Electron alternative with much tinier artifact size |
| State management | RxJS | Provided out of the box by Angular |
We’ll dive more into these choices further down the article, but let’s start with the first one. Why Angular in a Web ecosystem dominated by React? At TypeDB we’re accustomed to a rigorous engineering process. The core database was rewritten in Rust not just for potential performance wins, but also for Rust’s excellent compiler that brings guaranteed memory safety in exchange for being notoriously difficult to satisfy. The core of TypeDB is built in Bazel, a Google-backed build system designed for highly optimised builds, superior caching and parallelisation of work.
In this landscape it made sense for us to adopt a technology built with type safety and strict architectural guidance at its heart – without going for anything too new and experimental. So we picked Angular with TypeScript, the same framework that powers TypeDB Cloud’s frontend and even the main TypeDB website.
TypeDB Studio is fully open source, and you can browse its source code at https://github.com/typedb/typedb-studio.
Application Architecture
Studio is structured around three layers: modules, framework and services.
Modules (src/module/) are Angular standalone components that compose the UI. The routing is flat and guard-driven:
/welcome → HomeComponent/connect → ConnectionCreatorComponent/query → QueryPageComponent... etc.
A homeGuard reads the last-used tool from AppData and redirects / accordingly, so the app always resumes where you left off.
ℹ️ If you’re on the desktop app, it still has the notion of “routes”, i.e. URLs – although these are largely opaque to the user. The desktop app runs in a native WebView.
Framework (src/framework) : This is where we keep all the reusable components – tables, spinners and so on – many of which are themselves thin wrappers around Angular Material. We piggyback on Angular Material components to save time, even though styling their components is sometimes tricky!
Services (src/service/) are Angular @Injectable singletons that own all mutable state. Each service exposes RxJS observables and methods that mutate the underlying BehaviorSubjects.
DriverState– the comms layer to TypeDB. It holds the connection, the currently selected database, the transaction, the database list, and a write-lock semaphore. Every query flows through here.AppData– a structured local persistence layer. Nested sub-services (Connections,Preferences,QueryTabs,DataExplorerTabs,ChatConversations) each own a slice oflocalStoragewith typed read/write accessors. This service allows users to close and reopen Studio and come back to find things as they left them.QueryPageState,SchemaState,ChatState, etc. – These Angular services are simply responsible for holding the state of each tool in Studio. This design practice allows for the state of pages to persist between navigations. As a user, you wouldn’t expect to navigate away from the query page and lose your queries or their results, and this state management pattern enables that necessary persistence.
ℹ️ On hindsight, it would have been a better architecture decision to persist to IndexedDB, not localStorage. This would have yielded a more scalable solution, because browsers typically limit local storage to 5MB on disk. In the future, we plan to ship a TypeDB Studio update that uses IndexedDB, and automatically migrates existing local storage data to IndexedDB to ensure user data remains intact.
The TypeQL Editor: CodeMirror 6 + Lezer
The query editor is built on CodeMirror 6 with a custom Lezer grammar for TypeQL. Lezer is CodeMirror’s incremental parser generator – it produces a compact LR parser from a declarative grammar definition, and the result is fast enough to re-parse on every keystroke.
The grammar file (codemirror-lang-typeql/typeql.grammar) defines the full TypeQL syntax. On top of it, the language integration layer configures:
- Syntax highlighting via
styleTags– query stage keywords (match,insert,delete) are styled as headings; constraint keywords (isa,has,links) as keywords; variables, types, and literals each get distinct highlight tags. - Code folding on
QueryStagenodes, so multi-stage pipelines can be collapsed. - Real-time linting – a tree walker finds parser error nodes and surfaces them as inline diagnostics.
- Schema-aware autocomplete – a
TypeQLAutocompleteSchemaobject is updated whenever the schema refreshes, so typing a type name suggests entity types, relation types, and attributes from the actual database.

The autocomplete architecture is worth calling out. A NodePrefixAutoComplete handler walks the syntax tree at the cursor position, determines the grammatical context, and merges static TypeQL keyword suggestions with dynamic schema suggestions. The schema state feeds into the autocomplete system through a global updateAutocompleteSchemaFromDB() function, keeping the two synchronised without tight coupling.
Lezer grammar is a CodeMirror-specific syntax. Writing yet another grammar for TypeQL was a notable hurdle during development – we already have our PEST grammar for the database core and Prism grammar for the Web.
ℹ️ For developing tooling using the grammar files, always retrieve the latest grammar from the TypeQL Git repository. The PEST grammar is the most authoritative source – the database core uses it.
Reactive State Flow
The entire application is organized around observable streams that cascade from DriverState outward. When the connection changes, the database list refreshes. When the database changes, the schema refreshes, the data explorer tabs restore, and the chat conversations switch. When the schema refreshes, the autocomplete updates.
This is achieved without a centralized store. Each service subscribes to the observables it depends on and publishes its own. The dependency graph is implicit in the constructor injection and subscription setup, but it follows a clear hierarchy:
DriverState (connection, database, transaction) ├── SchemaState (schema, autocomplete) ├── QueryPageState (query execution, output formatting) ├── DataEditorState (data tabs, instance browsing) ├── ChatState (conversations, streaming responses) └── AppData (persistence, preferences)
RxJS operators like switchMap, combineLatest, distinctUntilChanged, and shareReplay handle the subscription lifecycle. Components use takeUntilDestroyed(destroyRef) or the async pipe to clean up subscriptions automatically.
DriverState is akin to the central processing unit of Studio, and is architecturally interesting in and of itself. It will be covered in a separate blog post coming soon!
Error Handling and Resilience
Error handling is always finicky to get right in any application – even with TypeScript, because the return type of most errors is any. Studio largely adopts a unified strategy where we override the default Angular ErrorHandler with our own that sends snackbar notifications for any errors, and these can be expanded to view the full error details.
Desktop Packaging with Tauri
Studio ships as both a web app and a native desktop application. Tauri 2 wraps the Angular build in a lightweight Rust shell. The Tauri configuration is minimal – a single window, platform-specific installers (MSI, DMG, DEB), and a thin Rust backend that currently only provides URL-opening capabilities via tauri-plugin-opener.
As far as Tauri examples go, Studio is very much barebones. There are no modifications to the Rust process code from the Tauri boilerplate. As such, it might seem like the choice of Tauri (vs. Electron, say) is quite academic – but Tauri does do one thing very well. Unlike Electron, a Tauri application relies on the presence of a WebView runner on the host’s OS. This keeps builds very fast and distributions very lightweight. However, it does slightly reduce compatibility with older browsers and operating systems.
| Electron | Tauri | |
| Multi-platform support | ✓ | ✓ |
| Strong components ecosystem | ✓ | ✓ |
| Build speed | Average | Fast |
| Distribution size | Large | Small |
| Compatibility | Excellent | Modern OSes / browsers only |
There are two honorable mentions here: the other main competitor in the running here was Dioxus, a very exciting-looking project where both the backend and frontend are written in Rust, and the Web version runs in WebAssembly. Then there is the framework that Studio for TypeDB v2 used – Compose Multiplatform.
We ruled out both of the above for TypeDB Studio 3 because neither of them are JavaScript and HTML-based. The Web ecosystem gives us so many UI components for free out of the box, and this saves precious dev hours that we can instead spend building cool new product features. If anyone has tried Dioxus and has thoughts on it, let us know!
Conclusion
TypeDB Studio is a relatively compact codebase (~15 services, ~12 feature modules) that manages significant complexity: a custom language grammar, a multi-stage graph visualization pipeline, dual transaction modes, per-database persistent state, and multi-platform desktop packaging. The architecture achieves this by leaning heavily on a few well-chosen primitives – standalone Angular components, RxJS services, the Graphology/Sigma.js graph stack, and CodeMirror 6’s composable extension system.
Maintaining a scalable and cohesive architecture makes bugs easier to spot and new features easier to develop – by hand or by AI. These days it is easier than ever to churn out new Studio features with the help of AI-assisted development. I’ve personally found it’s remarkably good even at whipping up UIs, but plenty of human intervention is still required to fix clear visual inconsistencies.
Coming soon
TypeDB Studio is a beast to unpack! Over the coming weeks we’ll be releasing more follow-up blogs that, between them, will cover the remaining pieces of the puzzle. The next chapter will cover:
- TypeDB connection management using
@typedb/driver-http, the TypeDB HTTP TypeScript driver - How Studio handles and renders the results of TypeQL queries
- The architecture of Studio’s AI (Agent) mode
Try TypeDB Studio
- https://studio.typedb.com – Open the TypeDB Studio web app
- https://typedb.com/docs/home/install/studio – Install the TypeDB Studio desktop app
- https://typedb.com/docs/tools/studio – Read the TypeDB Studio docs
- Get in touch with the TypeDB team for any enquiries you may have
- Connect with us on Discord
