Custom DataSources
Pull data from SaaS APIs, proprietary databases, or any custom source. Data flows into DuckDB just like built-in sources.
Plugins let you extend bino with capabilities that go beyond what YAML manifests and SQL queries can express. A single plugin binary can provide any combination of:
Custom DataSources
Pull data from SaaS APIs, proprietary databases, or any custom source. Data flows into DuckDB just like built-in sources.
Visual Components
Ship Web Component JS/CSS and generate HTML for custom chart types, widgets, or layout elements.
Lint Rules
Validate manifests with domain-specific rules. Lint rules can access datasets and query the host’s DuckDB.
Pipeline Hooks
React to pipeline events (post-load, post-dataset, post-render) to transform data, inject content, or collect telemetry.
Plugins are standalone executables that communicate with the bino CLI over gRPC.
bino launches each plugin as a subprocess, sends an Init call, and then invokes
RPCs as the pipeline progresses. When the command finishes, plugins are shut down
gracefully.
This architecture means plugins can be written in any language that supports gRPC, though the official Plugin SDK is for Go.
Build the plugin binary
cd my-bino-plugin
go build -o bino-plugin-myplugin .Place it where bino can find it
bino searches for plugins in this order:
| Priority | Location | Example |
|---|---|---|
| 1 | Explicit path in bino.toml | path = "./bin/bino-plugin-myplugin" |
| 2 | Project-local | <project>/.bino/plugins/bino-plugin-myplugin |
| 3 | User-global | ~/.bino/plugins/bino-plugin-myplugin |
| 4 | System PATH | Any directory in $PATH |
The binary must be named bino-plugin-<name> where <name> matches the
key in bino.toml.
Declare it in bino.toml
[plugins.myplugin]
# path = ".bino/plugins/bino-plugin-myplugin" # optional, if not on PATH
[plugins.myplugin.config]
api_key = "${MY_API_KEY}"Verify
bino plugin listSince plugins are native executables, you need a separate binary per platform. The naming convention is:
| Platform | Binary name |
|---|---|
| macOS / Linux | bino-plugin-myplugin |
| Windows | bino-plugin-myplugin.exe |
On macOS, you may need to sign the binary before it can run:
codesign --force --sign - bino-plugin-mypluginPlugins receive their configuration from bino.toml at startup:
[plugins.salesforce]
path = ".bino/plugins/bino-plugin-salesforce" # optional explicit path
version = "1.2.0" # optional version pin (future)
[plugins.salesforce.config]
instance_url = "https://myorg.salesforce.com"
api_version = "58.0"The config map is passed to the plugin’s Init RPC as key-value pairs.
Environment variable substitution (${VAR}) works in config values.
A plugin can register new kind values that behave like built-in DataSources.
When bino encounters a document with a plugin-provided kind, it calls the
plugin’s CollectDataSource RPC to fetch data.
apiVersion: bino.bi/v1alpha1
kind: SalesforceDataSource # provided by plugin
metadata:
name: opportunities
spec:
object: Opportunity
query: "SELECT Id, Name, Amount FROM Opportunity WHERE StageName = 'Closed Won'"Plugins can return data as JSON rows (registered as a DuckDB view) or as a
DuckDB SQL expression (e.g., read_parquet('s3://...')).
Plugins can ship Web Components and render custom HTML for visual kinds:
apiVersion: bino.bi/v1alpha1
kind: ExampleChart # provided by plugin
metadata:
name: revenue_chart
spec:
dataset: monthly_revenue
chartType: bar
title: Monthly RevenueThe plugin generates HTML (e.g., <bn-example-chart ...>) and provides the
JS/CSS assets that implement the Web Component.
Plugin lint rules run alongside bino’s built-in rules during bino lint,
bino build, and bino preview (with --lint):
bino lint
# ✓ Checked 12 rule(s) (including 3 plugin rules)
# ⚠ salesforce/deprecated-api-version: ...Plugins subscribe to pipeline checkpoints:
post-load — after manifests are loadedpost-dataset-execute — after SQL queries runpost-render-html — after HTML is generatedpost-render-pdf — after PDF is renderedHooks can inspect and modify the pipeline payload (e.g., transform HTML, validate datasets, collect metrics).
Plugins can add subcommands to bino:
bino plugin exec salesforce:auth --instance https://myorg.salesforce.com
bino plugin exec salesforce:sync --object AccountPlugin callbacks can query the host’s state:
This enables data-aware plugins that make decisions based on the current report’s data and configuration.
See the Plugin SDK documentation for a complete guide to building plugins with Go, including the API reference and a working sample plugin.
A minimal plugin looks like:
package main
import sdk "github.com/bino-bi/bino-plugin-sdk"
func main() {
sdk.Serve(&sdk.PluginOpts{
Name: "myplugin",
Version: "0.1.0",
// ... register capabilities
})
}