Skip to main content

Language bindings

YARA-X is written in Rust, but you do not have to write Rust to use it. Besides the yr command-line tool, the project maintains official bindings for several languages, all backed by the same engine. This means you can compile rules and scan data in-process — without spawning the CLI — from Python, Go, C/C++, Rust, or JavaScript running on WebAssembly.

note

All of the bindings expose the same core concepts you already know from the rule language and CLI: a compiler turns rule source into compiled Rules, and a scanner runs those rules over a block of data. Only the surface API differs between languages.

Available bindings

The table below lists each official binding, where its source lives in the VirusTotal/yara-x repository, and how you install or depend on it.

LanguageSource directoryPackage / crateInstall or import
Pythonpy/yara-x (PyPI)pip install yara-ximport yara_x
Gogo/github.com/VirusTotal/yara-x/gogo get github.com/VirusTotal/yara-x/go
C / C++capi/yara-x-capi (crate)build with cargo cinstall, then #include <yara_x.h>
Rustlib/yara-x (crates.io)cargo add yara-x
JavaScript / WASMjs-wasm/@virustotal/yara-x (npm)npm install @virustotal/yara-x
info

The Python package is published on PyPI as yara-x (with a hyphen), but the module you import in code is yara_x (with an underscore). This is a common Python naming convention — the distribution name and the import name differ.

Python

The Python bindings are installed with pip install yara-x and imported as yara_x. Wheels are published for Linux, macOS, and Windows, so no Rust toolchain is needed to install them. See the Python API docs for the full surface, including the Compiler, Rules, and Scanner classes.

Go

The Go bindings live under github.com/VirusTotal/yara-x/go and use the C API under the hood via cgo.

tip

Because the Go bindings wrap the C library through cgo, you must build and install the C library first before the Go package can be compiled. Follow the C/C++ instructions to install it, then run go get github.com/VirusTotal/yara-x/go.

C / C++

The C API is built with cargo-c. Running cargo cinstall builds both static and dynamic libraries, generates the yara_x.h header (via cbindgen), and writes a pkg-config .pc file so other build systems can locate the library. The public functions are prefixed with yrx_, for example yrx_compile. This is the same C library the Go bindings depend on.

Rust

To use YARA-X as a native Rust library, add the yara-x crate with cargo add yara-x. API documentation is published on docs.rs/yara-x.

JavaScript / WebAssembly

The js-wasm/ directory provides JavaScript bindings built on WebAssembly, published to npm as @virustotal/yara-x. The whole yara-x crate can be compiled to WASM, which is what powers the online YARA-X playground. The JavaScript API exposes Compiler, Rules, and Scanner objects, and uses explicit .free() calls (or the using keyword) to release WASM memory.

Python compile-and-scan example

The snippet below is the canonical way to compile a rule and scan a byte string with the Python bindings. The simplest path is yara_x.compile(), which returns a Rules object you can call .scan() on directly.

Illustrative example

The following is a minimal, illustrative example intended to show the shape of the API. Adapt the rule and the data you scan to your own use case.

import yara_x

# Compile a single rule from a source string.
rules = yara_x.compile('''
rule test {
strings:
$a = "foobar"
condition:
$a
}
''')

# Scan an in-memory byte string.
results = rules.scan(b"foobar")

# Inspect what matched.
matched = results.matching_rules[0]
print(matched.identifier) # -> "test"

pattern = matched.patterns[0]
print(pattern.identifier) # -> "$a"
print(pattern.matches[0].offset, pattern.matches[0].length) # -> 0 6

For more advanced scenarios — multiple namespaces, global variables, or reusing compiled rules across many scans — build the rules with a Compiler and run them through a Scanner:

import yara_x

compiler = yara_x.Compiler()
compiler.new_namespace("foo")
compiler.add_source('rule a { condition: true }')
compiler.new_namespace("bar")
compiler.add_source('rule b { condition: false }')
rules = compiler.build()

scanner = yara_x.Scanner(rules)
scanner.set_timeout(60)
results = scanner.scan(b"some data")
tip

yara_x.compile() is convenient for one-off cases, but a Scanner is the right choice when you scan many inputs against the same rules — you compile once and reuse the compiled Rules, which avoids paying the compilation cost on every scan.

Sources