One of the key concepts that make Prisma unique compared to other database abstractions is the Prisma schema – a human-readable declarative representation of your data model. The Prisma schema is your primary touchpoint for database-related workflows like data modeling and the source of truth for a lot of Prisma's magic under the hood – automatically generating database migrations and the fully typed Prisma Client.
Schemas are a powerful concept in software development – they allow you to take a declarative approach and maintain a separation of concerns to a considerable degree by decoupling business logic from the shape of data.
Moreover, schemas have the property of being parsable, which opens the window to automated tooling that equips developers with a tight feedback loop informing you about errors in your schema, automatic formatting, and suggestions to avoid common pitfalls in your database schema design.
The Prisma schema language tries to strike the right balance between being self-explanatory and expressive. Self-explanatory means that even with no familiarity, you can still comprehend the data model, and expressive –in this context– means that you can effectively design your desired database schema without falling back to raw SQL (with relational databases).
To make it even easier to learn and evolve the Prisma schema, we've built the Prisma Visual Studio Code extension that helps create a tight feedback loop right within your code editor and has already been downloaded by over 170 thousand developers.
In essence, the Prisma VS Code extension removes much of the burden of learning yet another DSL (domain-specific language) with the following functionality:
Syntax highlighting eases visual comprehension of the Prisma schema
Formatting ensures consistent indentation of your models for easy readability
Linting shows inline errors in the schema, and autocompletion assists in defining the correct type
Quick suggestions assist in defining field types, models, and relations while formatting automatically defines back relations
Easily navigate definitions, i.e. models in the Prisma schema
Visual Studio Code extensions use the Language Server Protocol (LSP) to standardize communication between language-specific tooling and the VS Code. This approach decouples the responsibilities into two parts:
- Language Client: Module in the Prisma VS Code extension (Node.js) that communicates using LSP with the Prisma Language Server.
- Language Server: A language analysis tool running in a separate process.
The benefit of this approach is that LSP-compliant extensions can be written in any language (e.g. Rust) for any language (e.g. the Prisma schema language). Separating the Language Server into a separate process ensures CPU-bound tasks don't slow down the editing experience.
This allows VS Code extensions to implement language-specific autocomplete, error-checking, jump-to-definition, static analysis, and many other language features supported by VS Code.
At Prisma, we love Rust and use it to build much of Prisma's core functionality. Rust is a highly optimized systems programming language that can be compiled to binaries for multiple platforms.
For the VS Code plugin to provide useful feedback about your Prisma schema, we rely on the
prisma-fmt engine, which is written in Rust. The engine takes the Prisma schema as input, parses, formats it, performs static analysis (linting), and provides the formatted schema along with feedback such as errors and suggestions.
From a technical perspective, the Prisma VS Code extension has three main responsibilities:
- Define the Prisma schema language grammar for syntax highlighting.
- Downloading, starting, and managing the communication with the
- Relay schema feedback data from
prisma-fmtto VS Code through the Prisma Language Server, so it's visible to you.
Because the runtime for VS Code extensions is Node.js, while the
prisma-fmt engine is written in Rust, the Language Server code needs to start a side-car binary.
Architecture diagram of the extension before the change
This approach introduces significant complexity:
- The Prisma engine binary must be compiled for each operating system which requires building and distribution infrastructure to ensure wide cross-platform support.
- Logic to download the correct binary at the initial runtime of the extension.
- Lifecycle management of the binary.
- Executing a downloaded binary can trigger user permission requests and false alarms by antivirus software that can scare users.
Historically we saw a cluster of problems that were difficult to reproduce and fix due to this complexity. This prompted us to research ways to simplify the extension codebase.
WebAssembly is a new type of code that can be run in modern web browsers and Node.js — it is a low-level assembly-like language with a compact binary format that runs with near-native performance. Seeing as VS Code is built with Node.js,
prisma-fmt engine is written in Rust, it can also be compiled to WebAssembly, thanks to Rust's mature WebAssembly tooling. This means that WebAssembly modules can be imported natively into VS Code extensions.
Compiling the Prisma engine to a WebAssembly module instead of a platform-specific binary has several benefits:
- The Prisma engine (compiled into a Wasm module) can be packaged in the Prisma Language Server npm package, thereby simplifying distribution.
- Since WebAssembly is natively cross-platform compatible, we can do away with multiple compilation targets for
prisma-fmtthat were previously used by the Prisma Language Server (currently there are 22 compilation targets).
- The Prisma Language Server doesn't need to download an additional binary after installation, potentially eliminating a whole class of errors.
Architecture diagram of the changes
The Prisma VS Code extension is a key pillar for Prisma's developer experience, creating a tight feedback loop as you design and evolve your Prisma schema.
Reducing the complexity of the underlying implementation can increase stability and allow us to introduce new features more rapidly.
WebAssembly has played a significant role in this, giving us seamless interoperability between Node.js and Rust code while simplifying and consolidating publishing with npm.
This is all cutting-edge technology. While it has passed rigorous testing internally and we're confident about its stability, such fundamental changes can introduce bugs. If you encounter any problems or bugs, be sure to open an issue.
For Prisma, this is exciting as it is the first time we deploy WebAssembly to production and opens the door to many other potential improvements.
Upgrade the extension in VS Code for the same developer experience you love.
If you found this blog post interesting and want to work on the future of developer tools for databases, Prisma is hiring! Check out our current open positions.