Your First Tengo Extension

A lighter-weight extension entirely in Tengo.

You don't always need a Go binary. If your extension only reacts to events, registers filters, or exposes a simple HTTP route, you can ship it as a pure Tengo package — no gRPC plugin, no migrations, no admin UI required. The reference implementation is resend-provider: the entire transport for Resend email is a settings schema and a Tengo file.

The folder layout

extensions/my-extension/
  extension.json         # manifest, no plugins[] entry
  scripts/
    extension.tengo      # entry point
    handlers/*.tengo     # event handlers
    filters/*.tengo      # filter handlers
    routes/*.tengo       # route handlers (optional)

The manifest

Tengo extensions skip the plugins array. They still declare capabilities — the guard applies whether you call CoreAPI from Go or from Tengo. Common capabilities for a small Tengo extension are settings:read, events:subscribe, http:fetch, log:write.

The entry point

events := import("core/events")
filters := import("core/filters")
routes  := import("core/routes")

events.on("node.created",  "./handlers/on_node_created")
filters.add("node.title",  "./filters/title_suffix", 90)
routes.register("POST",    "/hooks/incoming", "./routes/incoming")

Handler scripts

Each handler runs in its own short-lived Tengo VM. The script receives a payload map (for events / filters) or a request object (for routes). Set response = {ok: true} for events, response = transformed_value for filters, or response = {status, headers, body} for routes.

What you can't do

The Tengo sandbox blocks arbitrary network connections, arbitrary file reads, and subprocess spawns. Memory and execution time are bounded. If you need any of those things, you're shipping a gRPC plugin — see the previous post.

Resend in twenty lines

The whole resend-provider extension is essentially: declare an email-settings slot in the manifest, subscribe to email.send, and POST the payload to the Resend API via http.fetch. That's it. The Settings UI integrates via the slot exposed by email-manager; nothing to build.

If your idea fits that mould — “react to event X, then talk to service Y” — Tengo is faster to ship and easier to maintain than a gRPC plugin. Reach for Go when you need raw performance, complex state, or a real admin UI.

← all posts