npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@snelusha/balrun

v0.6.3

Published

Run Ballerina anywhere!

Readme

banner

[!WARNING] This project is actively evolving, and APIs may change frequently.

Installation

npm install @snelusha/balrun

CLI

npx @snelusha/balrun ./main.bal

Accepts a .bal file, a package directory, or . for the current package.

Print the package and embedded interpreter provenance with:

npx @snelusha/balrun --version

Usage

import { Ballerina } from "@snelusha/balrun";

const ballerina = new Ballerina({ colors: false });
const exitCode = await ballerina.run("./main.bal", { colors: true });

Options passed to run() override the constructor defaults for that call only.

Version information

BALRUN_VERSION is the npm package version. Ballerina#version() also reports the version and Git revision embedded in the loaded interpreter WASM, which can differ when using wasmSource or core.

import { BALRUN_VERSION, Ballerina } from "@snelusha/balrun";

console.log(BALRUN_VERSION);
console.log(await new Ballerina().version());

Stopping a run

Use stop() to stop a running Ballerina program. The default mode is graceful; pass "immediate" to stop immediately.

const running = ballerina.run("./service.bal");

await ballerina.stop();
const exitCode = await running;

The CLI forwards SIGINT and SIGTERM as graceful stops, and SIGQUIT as an immediate stop.

React

import { BallerinaProvider, useBallerina } from "@snelusha/balrun/react";

const fs = new SomeFS();

function App() {
  return (
    <BallerinaProvider fs={fs}>
      <RunButton />
    </BallerinaProvider>
  );
}

function RunButton() {
  const { isReady, error, run } = useBallerina();

  return (
    <button disabled={!isReady} onClick={() => run("./main.bal")}>
      {error ? error.message : "Run Ballerina"}
    </button>
  );
}

BallerinaProvider accepts the same options as Ballerina and initializes one shared runtime for its descendants. useBallerina() must be called within a provider. In browser environments, provide an fs implementation.

See examples/vite for a Vite + React browser example.

Options

colors

Diagnostics use ANSI colors by default. Pass colors: false to disable. The CLI auto-detects based on stderr.isTTY.

stdout / stderr

Redirect runtime output by passing any object that implements StreamWriter:

import type { StreamWriter } from "@snelusha/balrun";

const writer: StreamWriter = { write(chunk: string) {} };

Example:

import { Ballerina, type StreamWriter } from "@snelusha/balrun";

const buffer: string[] = [];
const writer: StreamWriter = {
  write(chunk) {
    buffer.push(chunk);
  },
};

await new Ballerina({ stdout: writer, stderr: writer }).run("./main.bal");

fs

Ballerina reads files through the FS interface. In Node.js environments, this defaults to the built-in Node adapter. In browsers, pass an fs implementation explicitly.

import { Ballerina, type FS } from "@snelusha/balrun";

class MemFS implements FS {
  // When running a single file, only `open` and `stat` are required.
  // When running a package, `readDir` is also required.
}

await new Ballerina({ fs: new MemFS() }).run("main.bal");

To use the Node adapter explicitly:

import { Ballerina } from "@snelusha/balrun";
import { NodeFS } from "@snelusha/balrun/fs/node";

await new Ballerina({ fs: new NodeFS() }).run("./main.bal");

See examples/memfs for a full implementation.

env

In browsers, Ballerina's environment-variable operations use a copy of the supplied map for each run. User and home-directory lookups and subprocess execution are unavailable in browsers and panic when called. Node.js and Bun use the host environment and support all OS operations, including os:exec.

import { Ballerina } from "@snelusha/balrun";
import { NodeFS } from "@snelusha/balrun/fs/node";

const env = new Map([["GREETING", "hello"]]);
await new Ballerina({ fs: new NodeFS(), env }).run("main.bal");

HTTP services

Node.js and Bun bind Ballerina HTTP listeners to a local socket. Browsers cannot bind sockets; use dispatchHttpRequest to forward requests to the running service instead. onListenerReady provides the listener address in either environment.

const running = ballerina.run("service.bal", {
  onListenerReady: async ({ host, port }) => {
    const response = await ballerina.dispatchHttpRequest({ host, port, path: "/ping" });
    console.log(new TextDecoder().decode(response.body));
    await ballerina.stop();
  },
});
await running;

wasmSource / core

By default, Ballerina loads the bundled ballerina.wasm. Pass wasmSource to load a different local path or HTTP(S) URL:

await new Ballerina({ wasmSource: "https://example.com/ballerina.wasm" }).run("main.bal");

ballerina.wasm is available as a standalone GitHub Release asset starting with v0.6.3. Pin the release version when loading it directly:

await new Ballerina({
  wasmSource: "https://github.com/snelusha/balrun/releases/download/v0.6.3/ballerina.wasm",
}).run("main.bal");

For custom loading, pass a BallerinaCore directly. WasmBridge.load() accepts a local path, URL, Response, or Promise<Response>:

import { Ballerina, WasmBridge } from "@snelusha/balrun";

const core = await WasmBridge.load(fetch("/ballerina.wasm"));
await new Ballerina({ core }).run("main.bal");

Bundler note

ballerina.wasm must be available in the final build output at runtime.

Vite handles this automatically: it detects the default WASM URL and emits ballerina.wasm into dist/assets during vite build. Other bundlers may not copy the file automatically. If your built app cannot find ballerina.wasm, copy it from node_modules/@snelusha/balrun/dist/ballerina.wasm into your app's output directory, or use wasmSource to point to where you serve it.

Acknowledgements

Built on ballerina.