# Binding Rust Functions to Node Using NAPI-RS * Status: proposed * Deciders: @ryan-z, @link-verses, @prasaanth-verses, @tom-mason-verses * Date: 2024-04-03 Technical Story: https://verses.atlassian.net/browse/GPDT-48 ## Context and Problem Statement We have three language-specific SDKs (Rust, Node, Python) that provide the same functionality: authentication and operations on Genius DB. While they offer a great developer experience, they also result in duplicate code and potential performance inefficiencies. By binding Rust functions to Node/Typescript, we can leverage the performance benefits of Rust and reduce code duplication. However, the challenge lies in doing this in a way that is efficient, maintains Rust's safety guarantees, and is easily understandable by Node developers who may not be familiar with Rust. ## Decision Drivers * Performance: The solution must introduce minimal overhead. * Safety: The solution must uphold Rust's safety guarantees. * Maintainability: Preference for solutions with active maintenance and community support. * Developer Experience: The solution should be easily understandable by Node developers without requiring them to learn extensive new technologies. ## Considered Options * [Neon](https://neon-bindings.com/) * [NAPI-RS](https://napi.rs/) * [node-bindgen](https://github.com/infinyon/node-bindgen) ## Decision Outcome Chosen option: "NAPI-RS", because it is actively maintained, specifically designed for creating JS/TS bindings to Rust using the [Node API](https://nodejs.org/api/n-api.html). It meets all our key decision drivers: performance, safety, maintainability, and developer experience. ### Positive Consequences * Maintains the high performance of Rust within Node applications. * Ensures the safety features of Rust are not compromised. * Includes Typescript definitions out of the box * Provides a simple interface for Node developers to import Rust functions ### Negative Consequences * The semantics of the underlying Rust may not always transfer to the JS implmentation. But, this is a limitation of any binding technology * There may be some performance impact passing large objects back and forth, during de/serialization. Again though, a general issue with bindings and true of the other libs. * Typings by default may need manual adjustments ## Pros and Cons of the Options ### Option 1: NAPI-RS NAPI-RS was built from the ground up using the Node API to allow Node applications to utilize pre-compiled Rust addons. #### NAPI-RS is good, because * Actively maintained and widely used. * Directly addresses the need for binding Rust to Typescript without intermediate layers. * Provides automatic generation of Typescript defintions. #### NAPI-RS is bad, because * NAPI-RS is only specific to Node; other language SDKs will not be able to reuse these bindings. * Requires Rust knowledge for setup and optimization. * Node developers may need to learn Rust concepts. ### Option 2: Neon Neon is a slightly older project, with a similar sized community, and similar interface to NAPI-RS #### Neon is good, because * Was designed with a similar goal in mind. * Has a slightly larger community, being a bit more mature #### Neon is bad, because * Implemented the Node Api later in its lifecycle, not from day 1 * Does not generate Typescript definitions. ### Option 3: node-bindgen Similar to the other options, node-bindgen provides a simple interface to generate bindings #### node-bindgen is good, because * Allows renaming of functions * Similar easy to use interface as the others #### node-bindgen is bad, because * Additional work to create TS types * Smallest project by far ## Links * [Documentation] * [Neon](https://github.com/neon-bindings/neon) * [Documentation] * [NAPI-RS](https://napi.rs/docs/introduction/getting-started) * [Documentation] * [node-bindgen](https://github.com/infinyon/node-bindgen)