Architecture
This page explains how Transit works under the hood. You do not need to read this to use Transit, but it helps if you are curious or debugging issues.
The Big Picture
Section titled “The Big Picture”When you write this code:
const rs = transit.rust("./rust");const c = transit.c("./c");const greeting = await rs.greet("World");const chunk = await c.processChunk({ data: [1, 2] });Transit does three things:
- Scans your Rust/C/C++ files to find functions
- Loads the compiled native code
- Calls the function directly in-process and returns the result
Here is a simplified diagram of what happens:
Your JavaScript code | v transit.rust("./rust") or transit.c("./c") | v Scanner finds: greet, add (from pub fn or generated headers) | v Loads the compiled native code (index.node or .so file) | v Returns a "proxy" object that looks like your functions | v rs.greet("World") -> calls the actual native function -> returns resultThe Components
Section titled “The Components”Transit has several parts that work together:
1. The Scanner (transit-scanner)
Section titled “1. The Scanner (transit-scanner)”The scanner is a tool written in Rust that reads your source files and finds functions. It uses a technology called “tree-sitter” to understand the structure of your code.
What it does:
- Reads your
.rs,.py,.java,.c,.cpp,.js,.tsfiles - Finds functions that are public
- Detects special comments like
// transit:file - Produces a list of discovered functions (called a “manifest”)
Why it is fast: The scanner is written in Rust, which is very fast at reading and parsing files. It also caches results so it does not re-scan files that have not changed.
2. The JavaScript API (transit-js)
Section titled “2. The JavaScript API (transit-js)”This is the code you interact with. It provides the transit.rust(), transit.java(), transit.python(), transit.c(), and transit.cpp() functions.
What it does:
- Creates language handles (the
rs,jv,py,c,cppobjects) - Manages communication with Rust, Java, Python, C, and C++
- Handles errors and timeouts
- Caches language handles so you do not create duplicates
3. The Rust Bridge (RustDevBridge)
Section titled “3. The Rust Bridge (RustDevBridge)”When you call a Rust function, Transit loads a compiled Rust file (called a “native addon”) directly into your JavaScript process. The same bridge is shared for C and C++ functions — RustDevBridge detects the language and loads the appropriate compiled addon.
How it works:
- Your Rust/C/C++ code is compiled into a
.nodeor.sofile - Transit loads this file using Node.js’s native addon system
- Function calls go directly to the native code — no network, no serialization
- This is very fast (nanosecond-level latency)
What you need:
- Rust:
#[napi]annotatedpub fnfunctions withcrate-type = ["cdylib"]inCargo.toml - C: Functions declared via
#include <transit_c_glue.gen.h>(generated from your function signatures) - C++: Functions declared via
#include <transit_cpp_glue.gen.h>(generated from your function signatures) - The compiled
.nodefile must be in your project directory
4. The Python Bridge (PythonDevBridge)
Section titled “4. The Python Bridge (PythonDevBridge)”When you call a Python function, Transit starts a Python process in the background and communicates with it over a network connection.
How it works:
- Transit starts your Python script as a separate process
- The Python script prints its port number to the console
- Transit connects to that port using TCP
- Function calls are sent as binary messages
- The Python script processes the call and sends back a result
Why a separate process? JavaScript and Python cannot share a process directly. They communicate over a network connection (on your computer only, not the internet).
Why it is fast after the first call: The Python process stays running. Subsequent calls skip the startup time.
5. The Java Bridge (JavaDevBridge)
Section titled “5. The Java Bridge (JavaDevBridge)”Works the same way as the Python bridge — starts a Java process and communicates over TCP.
What you need:
- Java code compiled with
javac - A
TransitServerclass that handles communication - Your functions registered with
server.registerFunction()
How Communication Works
Section titled “How Communication Works”Rust, C, and C++ (In-Process)
Section titled “Rust, C, and C++ (In-Process)”JavaScript -> Loads .node file -> Calls Rust/C/C++ function directly -> Returns resultNo network involved. The native code runs inside your JavaScript process. This is the fastest option.
Python and Java (TCP)
Section titled “Python and Java (TCP)”JavaScript -> Sends message to localhost:PORT -> Python/Java processes it -> Sends result backThe message is small (just the function name and arguments as JSON). Communication happens over your computer’s internal network (loopback), which is very fast.
Error Handling
Section titled “Error Handling”When something goes wrong, Transit gives you useful error messages:
Function not found:
Function "nonexistent" not found in rust. Available: greet, addPython/Java error:
[python] processData: Division by zeroProcess crashed:
Python process exited (code=1, signal=null)For Python and Java, if the process crashes, Transit automatically restarts it (up to 3 times).
Performance
Section titled “Performance”| Language pair | Latency | Why |
|---|---|---|
| JavaScript <-> Rust | ~nanoseconds | Runs in the same process |
| JavaScript <-> C | ~nanoseconds | Runs in the same process |
| JavaScript <-> C++ | ~nanoseconds | Runs in the same process |
| JavaScript <-> Python | ~milliseconds | Network communication |
| JavaScript <-> Java | ~milliseconds | Network communication |
The first call to Python or Java is slower because it includes process startup time. After that, all calls are fast because the process stays running.
Security
Section titled “Security”- Python and Java processes only listen on
127.0.0.1(your computer only) - They reject connections from outside your computer
- Each request has a unique ID to prevent confusion
- No sensitive data leaves your machine
What Happens When You Add a New Function
Section titled “What Happens When You Add a New Function”- You write a new
pub fnin Rust (ordefin Python,publicmethod in Java, or a C/C++ function with the right signature) - You recompile if needed (Rust:
cargo build --release, C/C++:npm run build, Java:javac) - The next time Transit scans your code, it finds the new function
- You can call it immediately — no restart needed
In development mode with transit dev, the scanner watches for file changes and updates automatically.