Getting Started
This guide walks you through setting up Transit from scratch. By the end, you’ll be calling functions across JS, Rust, Java, and Python.
Prerequisites
Section titled “Prerequisites”Before you begin, make sure you have:
| Tool | Why you need it | How to check |
|---|---|---|
| Node.js >= 20 | Runs your JS code | node --version |
| bun | Package manager (npm also works) | bun --version |
| Rust | For the scanner and Rust functions | rustc --version |
| Java JDK 21+ | For Java functions | java --version |
| Python 3.10+ | For Python functions | python3 --version |
To install transit, use:
bun install -g transit-cli # you can use npm tooIf you only want to use Rust (no Java or Python), you only need Node.js, bun, and Rust.
1. Create a new project
Section titled “1. Create a new project”mkdir my-transit-appcd my-transit-appbun init -ybun install transit-cli2. Initialize your project (optional)
Section titled “2. Initialize your project (optional)”Transit can scan your project and create a config file for you:
transit inittransit init scans your source files for transit.rust(), transit.java(), and transit.python() calls, detects which languages you are using, and creates transit.config.json. It is idempotent — safe to run multiple times.
If you prefer to set things up manually, skip this step.
3. Set up your first language
Section titled “3. Set up your first language”Let’s start with Rust since it has the best performance.
Create the Rust module
Section titled “Create the Rust module”Create a file at rust/src/lib.rs:
use napi_derive::napi;
#[napi]pub fn greet(name: String) -> String { format!("Hello from Rust, {}!", name)}
#[napi]pub fn add(a: i32, b: i32) -> i32 { a + b}Create rust/Cargo.toml:
[package]name = "my-rust-module"version = "0.1.0"edition = "2021"
[lib]crate-type = ["cdylib", "lib"]
[dependencies]napi = { version = "3", features = ["serde-json"] }napi-derive = "3"serde = { version = "1", features = ["derive"] }serde_json = "1"
[build-dependencies]napi-build = "3"Create rust/build.rs (required by napi-rs):
fn main() { napi_build::setup();}Build it:
cd rustcargo build --releasecp target/release/libmy_rust_module.so index.nodecd ..Call it from JS
Section titled “Call it from JS”Create index.js:
import { transit } from "transit"import { resolve } from "node:path"
const __dirname = import.meta.dirname
// Point Transit at the Rust directoryconst rs = transit.rust(resolve(__dirname, "./rust"))
// Call the functionsconst greeting = await rs.greet("World")console.log(greeting) // "Hello from Rust, World!"
const sum = await rs.add(10, 20)console.log(sum) // 30Run it:
node index.jsYou should see:
Hello from Rust, World!304. Add Java
Section titled “4. Add Java”Create the Java service
Section titled “Create the Java service”Create java/src/main/java/com/example/App.java:
package com.example;
import transit.java.TransitServer;
public class App { public String processJob(String argsJson) { return "{\"output\": \"Java says: job received\"}"; }
public String getVersion(String argsJson) { return "{\"version\": \"1.0.0\"}"; }
public static void main(String[] args) throws Exception { TransitServer server = new TransitServer(); App app = new App(); server.registerFunction("processJob", app::processJob); server.registerFunction("getVersion", app::getVersion); server.start(); }}Build the Java classes
Section titled “Build the Java classes”You need the Transit Java runtime (which provides TransitServer). Copy TransitServer.java into your project, or use the version from the Transit package:
# Build the Transit Java runtimemkdir -p packages/transit-java-runtime/buildjavac -d packages/transit-java-runtime/build \ node_modules/transit/packages/transit-java-runtime/src/main/java/transit/java/*.java
# Build your appmkdir -p java/buildjavac -cp packages/transit-java-runtime/build \ -d java/build \ java/src/main/java/com/example/*.javaCall from JS
Section titled “Call from JS”Update your index.js:
import { transit } from "transit"import { resolve } from "node:path"
const __dirname = import.meta.dirname
const rs = transit.rust(resolve(__dirname, "./rust"))const jv = transit.java(resolve(__dirname, "./java/src/main/java"))
// Call Rustconsole.log(await rs.greet("World"))
// Call Javaconst jobResult = await jv.processJob({})console.log(jobResult) // {"output": "Java says: job received"}
const version = await jv.getVersion({})console.log(version) // {"version": "1.0.0"}5. Add Python
Section titled “5. Add Python”Copy the Transit server into your project
Section titled “Copy the Transit server into your project”Transit needs a small Python server to handle communication with JavaScript. Copy it from the Transit package into your Python directory:
mkdir -p pythoncp node_modules/transit/packages/transit-py-runtime/transit_server.py python/Create the Python service
Section titled “Create the Python service”Create python/service.py (or any name you like — Transit will find it):
import jsonfrom transit_server import TransitServer, register_function
def process_data(args_json): """Process some data and return a result.
IMPORTANT: args_json is a JSON STRING, not a dictionary! You must call json.loads() to parse it. """ args = json.loads(args_json) items = args.get("items", []) return json.dumps({ "output": f"Python processed {len(items)} items", "processed": True })
def get_stats(args_json): """Return some stats.""" return json.dumps({"status": "healthy", "language": "python"})
if __name__ == "__main__": server = TransitServer() register_function("processData", process_data) register_function("getStats", get_stats) server.start()Call from JS
Section titled “Call from JS”import { transit } from "transit"import { resolve } from "node:path"
const __dirname = import.meta.dirname
const rs = transit.rust(resolve(__dirname, "./rust"))const jv = transit.java(resolve(__dirname, "./java/src/main/java"))const py = transit.python(resolve(__dirname, "./python"))
// Call all three languagesconsole.log(await rs.greet("Transit"))console.log(await jv.processJob({}))console.log(await py.processData({ items: [1, 2, 3] }))6. See what Transit found
Section titled “6. See what Transit found”transit.info()// rust (./rust): 2 functions// - greet [tier 1]// - add [tier 1]// java (./java/src/main/java): 2 functions// - processJob [tier 1]// - getVersion [tier 1]// python (./python): 2 functions// - processData [tier 1]// - getStats [tier 1]Dev mode vs build mode
Section titled “Dev mode vs build mode”Transit has two modes:
| Mode | Command | What happens |
|---|---|---|
| Dev mode | node index.js or transit dev |
Uses a Proxy to dynamically dispatch function calls. Great for development — no build step needed. |
| Build mode | transit build |
Generates typed TypeScript stubs and compiles native addons. Better for production — gives you type safety and faster startup. |
In dev mode (the default), Transit uses a JavaScript Proxy to intercept function calls and route them to the right bridge. This means you can call functions immediately without any code generation.
In build mode, Transit generates explicit TypeScript functions for each discovered function. This gives you autocomplete, type checking, and slightly faster startup.
For most projects, dev mode is fine. Use build mode when you want type safety or are deploying to production.
Using the CLI
Section titled “Using the CLI”Transit includes a CLI to help manage your project.
Initialize your project
Section titled “Initialize your project”transit initThis scans your source files and creates a transit.config.json with your language directories.
Development mode
Section titled “Development mode”transit devWatches for file changes and re-scans automatically. No restart needed when you add new functions.
Build for production
Section titled “Build for production”transit buildGenerates typed TypeScript stubs (transit.gen.ts) and compiles Rust/Java. Writes dist/transit-manifest.json.
Run in production
Section titled “Run in production”transit start --entry index.jsStarts resident processes (Java, Python) and runs your app. Handles graceful shutdown on Ctrl+C.
How function discovery works
Section titled “How function discovery works”You don’t need to register functions manually. Transit scans your code and finds them automatically:
| Language | What Transit finds |
|---|---|
| Rust | #[napi] pub fn functions (Tier 1) |
| Java | public methods with signature (String) -> String (Tier 1) |
| Python | Top-level def functions (Tier 1) |
If you have multiple files with functions of the same name, use the qualified form:
await rustTransit["lib"]["processJob"](job)// orawait rustTransit.lib.processJob(job)File layout
Section titled “File layout”A typical Transit project looks like this:
my-project/ rust/ src/lib.rs # Your Rust functions Cargo.toml build.rs # Required for napi-rs java/ src/main/java/... # Your Java functions build/ # Compiled classes python/ transit_server.py # Copied from Transit package service.py # Your Python functions index.js # Your JS entry point transit.config.json # Generated by transit initTroubleshooting
Section titled “Troubleshooting”“Scanner not available” — Build the scanner first:
cd packages/transit-scannercargo build --releasecp target/release/libtransit_scanner.so index.node“Python entry point not found” — Make sure your Python file is named one of: transit_service.py, service.py, main.py, app.py, server.py, or filters.py. Or specify a custom entry point:
const py = transit.python("./python", { serverScript: "my_file.py" })Also make sure transit_server.py is in the same directory:
cp node_modules/transit/packages/transit-py-runtime/transit_server.py python/“Java class not found” — Compile your Java code and specify the classpath:
const jv = transit.java("./java", { classpath: resolve(__dirname, "./java/build"), mainClass: "com.example.App"})Functions not showing up in transit.info() — Check that your functions match the expected signatures. Rust needs #[napi] and pub fn, Java needs public methods returning String, Python needs top-level def functions.
The first Python/Java call is slow — This is normal! The first call starts the Python/Java process. After that, all calls are fast because the process stays running.
Next steps
Section titled “Next steps”- API Reference — full API documentation
- Export Tiers — how function discovery works in detail
- Binary Protocol — how JS ↔ Java/Python communication works (advanced, for contributors)
- Architecture — system design deep dive (advanced, for contributors)
- Contributing — help improve Transit