Available since: v4.0.0
ext is the component of the Surreal CLI for Surrealism extensions: it scaffolds a project, builds it into a .surli archive, inspects and runs the archive, signs it, and installs it into a database. The component is versioned with the database, and its executable is surreal-ext.
surreal ext [OPTIONS] <COMMAND> Before SurrealDB 4.0, the same commands were part of the database as surreal db module, also run as surreal module. In 4.0, surreal db module, surreal db extension and surreal module only print where the commands have moved.
| Subcommand | Purpose |
|---|---|
init | Scaffold a new extension project. |
build | Build the project into a .surli archive. |
run | Run a function of an archive with arguments. |
sig | Show a function's signature. |
info | List the functions an archive exports. |
config | Read and change the project's package.toml. |
sign | Sign an archive with an SSH key or through Sigstore. |
install | Check an archive's signer and capabilities, and define it in a database. |
upgrade | Redefine an installed extension from a new archive. |
Writing an extension
An extension is a Rust library whose functions are marked with the #[surrealism] attribute. The commands on this page create the project, compile it and package it, but the functions themselves are Rust code that you write. Building one needs the Rust toolchain and its WebAssembly target:
rustup target add wasm32-wasip2init creates a project whose src/lib.rs holds three example functions:
use surrealism::surrealism;
#[surrealism(default)]
fn hello() -> String {
format!("Hello from Surrealism!")
}
#[surrealism]
fn greet(name: String) -> String {
format!("Hello, {name}!")
}
#[surrealism]
fn add(a: i64, b: i64) -> i64 {
a + b
}Replace them with your own functions, using any Rust crate that compiles to WebAssembly, then build the project. Once the extension is defined in a database as demo, greet is called as ext::demo::greet('Ada'), and the function marked default as ext::demo(). The quick tutorial walks through a complete extension, and the attribute reference covers database access through a Transaction, init, comments and namespaced exports.
surreal ext init
Scaffold a new extension project: a Rust crate with a package.toml, a .cargo/config.toml and the starter src/lib.rs shown in Writing an extension.
surreal ext init [OPTIONS] [PATH]surreal ext init --headless --org acme --name demo ./demoThe package.toml it writes names the package, and lists under [capabilities] what the extension will ask for when it is installed:
target = "rust"
abi = 4
[package]
organisation = "acme"
name = "demo"
version = "1.0.0"
[capabilities]
allow_scripting = false
allow_arbitrary_queries = false
allow_write = false
allow_functions = []
allow_net = []
strict_timeout = trueA project from SurrealDB 3.3 or earlier has a surrealism.toml instead, which is still read when there is no package.toml. The .cargo/config.toml holds the tokio_unstable flag, commented out. Uncomment it when a dependency needs Tokio's net feature.
surreal ext build
Compile the project's Rust code to WebAssembly (wasm32-wasip2), package it into a .surli archive, and print the archive's digest. The build needs the Rust toolchain described in Writing an extension.
surreal ext build [OPTIONS] [SOURCE_PATH]surreal ext buildBuilding WASM module (target: wasm32-wasip2, profile: release)...
Optimizing bundle...
Pre-initialising...
Extracting function signatures...
Packed ./acme-demo-1.0.0.surli (digest sha256:7b36da7d8386c1561b7d61f83f39a3bf590e25b774d935d9f8252604e80134b5)The build runs the extension's init function once and stores the result in the archive, so every call starts from that state with fresh memory. The digest is the SHA-256 hash of the archive's MANIFEST, which lists every file in the archive with its own hash. A definition's DIGEST pins this value.
surreal ext run
Run one function of an archive, without a database. Repeat --arg for each argument, written as a SurrealQL value.
surreal ext run [OPTIONS] --fnc <FNC> <FILE>surreal ext run --fnc greet --arg '"Ada"' acme-demo-1.0.0.surli✅ 'Hello, Ada!'surreal ext sig
Show the signature of one function in an archive.
surreal ext sig [OPTIONS] --fnc <FNC> <FILE>surreal ext sig --fnc greet acme-demo-1.0.0.surliSignature:
- greet(name: string) -> string [readonly]surreal ext info
List the package and the functions an archive exports. <mod> stands for the name the extension is given when it is defined.
surreal ext info [OPTIONS] <FILE>Add --json (-j) to print the exports as a JSON document, for use in scripts. sig takes --json too.
surreal ext info acme-demo-1.0.0.surliInfo for @acme/demo@1.0.0
===========================
- <mod>::greet(name: string) -> string [readonly]
- <mod>::add(a: int, b: int) -> int [readonly]
- <mod>() -> string [readonly]surreal ext config
Read and change the project's package.toml. Each subcommand takes --path to name the project directory, which defaults to the current directory, and keeps the file's comments and ordering.
| Subcommand | Purpose |
|---|---|
show | Print the package file. |
get <KEY> | Print one value, such as package.version or capabilities.allow_net. |
set <KEY> <VALUE> | Set one value. |
add <KEY> <VALUE> | Add a value to capabilities.allow_net or capabilities.allow_functions. |
remove <KEY> <VALUE> | Remove a value from one of those lists. |
signer ssh <FILE> | Name an SSH public key as the package's signer. |
signer github --repo <OWNER/NAME> --workflow <FILE> | Name a GitHub Actions workflow as the signer, for Sigstore keyless signing. |
signer gitlab | Name a GitLab CI pipeline as the signer. |
signer remove | Remove the signer. |
fs add <DIR> [--as <PATH>] | Bundle a directory into the archive's read-only filesystem. |
fs remove <PATH> | Remove a bundled directory. |
The capabilities requested in package.toml are what install shows and asks to grant. An extension receives only the capabilities that its definition grants.
surreal ext config add capabilities.allow_net api.colour.io:443
surreal ext config add capabilities.allow_functions http::get
surreal ext config set capabilities.allow_write truesurreal ext sign
Sign an archive, which adds a SIGNATURE file to it. The project's package.toml must name a signer first, with config signer, and the archive must be built after that, so that the signer is part of the signed MANIFEST.
surreal ext sign [OPTIONS] <FILE>Without --key or --bundle, the command signs keyless through Sigstore, which needs the identity of a CI workflow, such as GitHub Actions. With an SSH key:
surreal ext config signer ssh ~/.ssh/release.pub
surreal ext build
surreal ext sign --key ~/.ssh/release acme-demo-1.0.0.surliSigned acme-demo-1.0.0.surli (sha256:7b36da7d8386c1561b7d61f83f39a3bf590e25b774d935d9f8252604e80134b5)Signing does not change the digest, because the signature is a separate file that the MANIFEST does not list.
surreal ext install
Install an archive into a database. The command reads the archive, shows its package, signer, digest, functions and the capabilities it requests, and asks which to accept. It then runs DEFINE EXTENSION with the DIGEST, SIGNER and CAPABILITIES filled in.
surreal ext install [OPTIONS] --as <NAME> --namespace <NAMESPACE> --database <DATABASE> <SOURCE>The command also takes the usual connection options: --endpoint, --username and --password or --token, --auth-level, --namespace and --database, or the matching SURREAL_* environment variables. The user needs permission to define extensions in the database, and read access to the bucket for a bucket source.
surreal ext install 'f"extensions:/acme-colour-1.0.0.surli"' --as colour \
-e ws://localhost:8000 -u root -p secret --ns app --db main \
--trust-signer SHA256:WAbQymSgov5xQFo9qtOeZGglO/HWeqqovf6ztZ0HM7U \
--with-capability net:api.colour.io:443 Package acme/colour 1.0.0 from f"extensions:/acme-colour-1.0.0.surli"
Signed by key ssh-ed25519 SHA256:WAbQymSgov5xQFo9qtOeZGglO/HWeqqovf6ztZ0HM7U
✓ matches package.toml [signer]: key SHA256:WAbQymSgov5xQFo9qtOeZGglO/HWeqqovf6ztZ0HM7U
Anchor the key itself (confirm its fingerprint with the publisher)
Digest sha256:8be7b49f1f3116e0f723c55ca0c9658452165fd2338995ab36a9ecf3b29c79fa
Adds ext::colour::blend, ext::colour::recolour
Needs network api.colour.io:443
· functions http::get requested, not granted (--with-capability grants it)
Trust this signer? yes (--trust-signer)
Capabilities: as granted by --with-capability
Installed ext::colourEvery decision is a named flag, and there is no option that accepts everything. Without a terminal, a run that leaves a decision open fails and names the flag it needs:
Trust this signer? needs an answer: run in a terminal, or pass --trust-signer <signer|any>surreal ext upgrade
Redefine an installed extension from a new archive with DEFINE EXTENSION OVERWRITE. The command compares the new archive with the installed definition, keeps the PERMISSIONS and COMMENT, and starts from the capabilities granted at install, so that only capabilities the new archive requests beyond the installed one need approval.
surreal ext upgrade [OPTIONS] --namespace <NAMESPACE> --database <DATABASE> <NAME> [SOURCE]surreal ext upgrade colour 'f"extensions:/acme-colour-1.1.0.surli"' \
-e ws://localhost:8000 -u root -p secret --ns app --db main \
--trust-signer SHA256:WAbQymSgov5xQFo9qtOeZGglO/HWeqqovf6ztZ0HM7UUpload each release under its own file name, as above. When a new archive replaces the installed file under the same name, the installed archive can no longer be read, so the command cannot check for a downgrade or a change of package, and in a script it then needs both --allow-downgrade and --allow-package-change.
Command help
surreal ext --helpDevelop, build, inspect and run Surrealism WASM modules
Usage: surreal-ext [OPTIONS] <COMMAND>
Commands:
init Initialize a new Surrealism module project
run Run a function with arguments
sig Show the function signature
info Show the module information
build Build a WASM module
sign Sign a .surli archive: Sigstore keyless from CI, an SSH key, or an imported bundle
config Read and change the project's package.toml
install Install an extension into a database: inspect, approve, define
upgrade Upgrade an installed extension: compare signer and capabilities, redefine
help Print this message or the help of the given subcommand(s)
Options:
-v, --version Print version
-j, --json Emit machine-readable JSON on stdout
-h, --help Print helpFurther reading
Surrealism overview: the end-to-end workflow
DEFINE EXTENSION:DIGEST,SIGNER,UNSIGNEDandCAPABILITIESCreating custom extensions: attributes,
package.tomland bundled filesystems