{"id":13774002,"url":"https://github.com/extism/go-sdk","last_synced_at":"2025-04-04T20:11:24.108Z","repository":{"id":186541647,"uuid":"667739470","full_name":"extism/go-sdk","owner":"extism","description":"Extism Go SDK - easily run WebAssembly modules in your Go applications","archived":false,"fork":false,"pushed_at":"2025-03-19T13:14:59.000Z","size":7603,"stargazers_count":111,"open_issues_count":6,"forks_count":10,"subscribers_count":8,"default_branch":"main","last_synced_at":"2025-03-28T23:47:35.711Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://pkg.go.dev/github.com/extism/go-sdk","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/extism.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-07-18T07:41:57.000Z","updated_at":"2025-03-27T08:37:50.000Z","dependencies_parsed_at":"2023-12-22T19:35:37.995Z","dependency_job_id":"0c7b8eef-8f94-42ac-9c89-9d83c41a74f3","html_url":"https://github.com/extism/go-sdk","commit_stats":null,"previous_names":["extism/go-sdk"],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Fgo-sdk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Fgo-sdk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Fgo-sdk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/extism%2Fgo-sdk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/extism","download_url":"https://codeload.github.com/extism/go-sdk/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247242678,"owners_count":20907134,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T17:01:22.805Z","updated_at":"2025-04-04T20:11:24.092Z","avatar_url":"https://github.com/extism.png","language":"Go","readme":"# Extism Go SDK\n\nThis repo houses the Go SDK for integrating with the [Extism](https://extism.org/) runtime. Install this library into your host Go applications to run Extism plugins.\n\nJoin the [Extism Discord](https://extism.org/discord) and chat with us!\n\n## Installation\n\nInstall via `go get`:\n\n```\ngo get github.com/extism/go-sdk\n```\n\n## Reference Docs\n\nYou can find the reference docs at [https://pkg.go.dev/github.com/extism/go-sdk](https://pkg.go.dev/github.com/extism/go-sdk).\n\n## Getting Started\n\nThis guide should walk you through some of the concepts in Extism and this Go library.\n\n### Creating A Plug-in\n\nThe primary concept in Extism is the [plug-in](https://extism.org/docs/concepts/plug-in). You can think of a plug-in as a code module stored in a `.wasm` file.\n\nPlug-in code can come from a file on disk, object storage or any number of places. Since you may not have one handy let's load a demo plug-in from the web. Let's\nstart by creating a main func and loading an Extism Plug-in:\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"github.com/extism/go-sdk\"\n\t\"os\"\n)\n\nfunc main() {\n\tmanifest := extism.Manifest{\n\t\tWasm: []extism.Wasm{\n\t\t\textism.WasmUrl{\n\t\t\t\tUrl: \"https://github.com/extism/plugins/releases/latest/download/count_vowels.wasm\",\n\t\t\t},\n\t\t},\n\t}\n\n\tctx := context.Background()\n\tconfig := extism.PluginConfig{}\n\tplugin, err := extism.NewPlugin(ctx, manifest, config, []extism.HostFunction{})\n\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to initialize plugin: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n}\n```\n\u003e **Note**: See [the Manifest docs](https://pkg.go.dev/github.com/extism/go-sdk#Manifest) as it has a rich schema and a lot of options.\n\n### Calling A Plug-in's Exports\n\nThis plug-in was written in Rust and it does one thing, it counts vowels in a string. As such, it exposes one \"export\" function: `count_vowels`. We can call exports using [extism.Plugin.Call](https://pkg.go.dev/github.com/extism/go-sdk#Plugin.Call).\nLet's add that code to our main func:\n\n```go\nfunc main() {\n    // ...\n\n\tdata := []byte(\"Hello, World!\")\n\texit, out, err := plugin.Call(\"count_vowels\", data)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(int(exit))\n\t}\n\n\tresponse := string(out)\n\tfmt.Println(response)\n    // =\u003e {\"count\": 3, \"total\": 3, \"vowels\": \"aeiouAEIOU\"}\n}\n```\n\nRunning this should print out the JSON vowel count report:\n\n```bash\n$ go run main.go\n# =\u003e {\"count\":3,\"total\":3,\"vowels\":\"aeiouAEIOU\"}\n```\n\nAll exports have a simple interface of optional bytes in, and optional bytes out. This plug-in happens to take a string and return a JSON encoded string with a report of results.\n\n\u003e **Note**: If you want to pass a custom `context.Context` when calling a plugin function, you can use the [extism.Plugin.CallWithContext](https://pkg.go.dev/github.com/extism/go-sdk#Plugin.CallWithContext) method instead.\n\n\n### Plug-in State\n\nPlug-ins may be stateful or stateless. Plug-ins can maintain state between calls by the use of variables. Our count vowels plug-in remembers the total number of vowels it's ever counted in the \"total\" key in the result. You can see this by making subsequent calls to the export:\n\n```go\nfunc main () {\n    // ...\n\n    exit, out, err := plugin.Call(\"count_vowels\", []byte(\"Hello, World!\"))\n    if err != nil {\n        fmt.Println(err)\n        os.Exit(int(exit))\n    }\n    fmt.Println(string(out))\n    // =\u003e {\"count\": 3, \"total\": 6, \"vowels\": \"aeiouAEIOU\"}\n\n    exit, out, err = plugin.Call(\"count_vowels\", []byte(\"Hello, World!\"))\n    if err != nil {\n        fmt.Println(err)\n        os.Exit(int(exit))\n    }\n    fmt.Println(string(out))\n    // =\u003e {\"count\": 3, \"total\": 9, \"vowels\": \"aeiouAEIOU\"}\n}\n\n```\n\nThese variables will persist until this plug-in is freed or you initialize a new one.\n\n### Configuration\n\nPlug-ins may optionally take a configuration object. This is a static way to configure the plug-in. Our count-vowels plugin takes an optional configuration to change out which characters are considered vowels. Example:\n\n```go\nfunc main() {\n    manifest := extism.Manifest{\n        Wasm: []extism.Wasm{\n            extism.WasmUrl{\n                Url: \"https://github.com/extism/plugins/releases/latest/download/count_vowels.wasm\",\n            },\n        },\n        Config: map[string]string{\n            \"vowels\": \"aeiouyAEIOUY\",\n        },\n    }\n\n    ctx := context.Background()\n    config := extism.PluginConfig{}\n\n    plugin, err := extism.NewPlugin(ctx, manifest, config, []extism.HostFunction{})\n\n    if err != nil {\n        fmt.Printf(\"Failed to initialize plugin: %v\\n\", err)\n        os.Exit(1)\n    }\n\n    exit, out, err := plugin.Call(\"count_vowels\", []byte(\"Yellow, World!\"))\n    if err != nil {\n        fmt.Println(err)\n        os.Exit(int(exit))\n    }\n\n    fmt.Println(string(out))\n    // =\u003e {\"count\": 4, \"total\": 4, \"vowels\": \"aeiouAEIOUY\"}\n}\n```\n\n### Host Functions\n\nLet's extend our count-vowels example a little bit: Instead of storing the `total` in an ephemeral plug-in var, let's store it in a persistent key-value store!\n\nWasm can't use our KV store on it's own. This is where [Host Functions](https://extism.org/docs/concepts/host-functions) come in.\n\n[Host functions](https://extism.org/docs/concepts/host-functions) allow us to grant new capabilities to our plug-ins from our application. They are simply some Go functions you write which can be passed down and invoked from any language inside the plug-in.\n\nLet's load the manifest like usual but load up this `count_vowels_kvstore` plug-in:\n\n```go\nmanifest := extism.Manifest{\n    Wasm: []extism.Wasm{\n        extism.WasmUrl{\n            Url: \"https://github.com/extism/plugins/releases/latest/download/count_vowels_kvstore.wasm\",\n        },\n    },\n}\n```\n\n\u003e *Note*: The source code for this is [here](https://github.com/extism/plugins/blob/main/count_vowels_kvstore/src/lib.rs) and is written in rust, but it could be written in any of our PDK languages.\n\nUnlike our previous plug-in, this plug-in expects you to provide host functions that satisfy our its import interface for a KV store.\n\nWe want to expose two functions to our plugin, `kv_write(key string, value []bytes)` which writes a bytes value to a key and `kv_read(key string) []byte` which reads the bytes at the given `key`.\n```go\n// pretend this is Redis or something :)\nkvStore := make(map[string][]byte)\n\nkvRead := extism.NewHostFunctionWithStack(\n    \"kv_read\",\n    func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {\n        key, err := p.ReadString(stack[0])\n        if err != nil {\n            panic(err)\n        }\n\n        value, success := kvStore[key]\n        if !success {\n            value = []byte{0, 0, 0, 0}\n        }\n\n        stack[0], err = p.WriteBytes(value)\n    },\n    []ValueType{ValueTypePTR},\n    []ValueType{ValueTypePTR},\n)\n\nkvWrite := extism.NewHostFunctionWithStack(\n    \"kv_write\",\n    func(ctx context.Context, p *extism.CurrentPlugin, stack []uint64) {\n        key, err := p.ReadString(stack[0])\n        if err != nil {\n            panic(err)\n        }\n\n        value, err := p.ReadBytes(stack[1])\n        if err != nil {\n            panic(err)\n        }\n\n        kvStore[key] = value\n    },\n    []ValueType{ValueTypePTR, ValueTypePTR},\n    []ValueType{},\n)\n```\n\n\u003e *Note*: In order to write host functions you should get familiar with the methods on the [extism.CurrentPlugin](https://pkg.go.dev/github.com/extism/go-sdk#CurrentPlugin) type. The `p` parameter is an instance of this type.\n\nWe need to pass these imports to the plug-in to create them. All imports of a plug-in must be satisfied for it to be initialized:\n\n```go\nplugin, err := extism.NewPlugin(ctx, manifest, config, []extism.HostFunction{kvRead, kvWrite});\n```\n\nNow we can invoke the event:\n\n```go\nexit, out, err := plugin.Call(\"count_vowels\", []byte(\"Hello, World!\"))\n// =\u003e Read from key=count-vowels\"\n// =\u003e Writing value=3 from key=count-vowels\"\n// =\u003e {\"count\": 3, \"total\": 3, \"vowels\": \"aeiouAEIOU\"}\n\nexit, out, err = plugin.Call(\"count_vowels\", []byte(\"Hello, World!\"))\n// =\u003e Read from key=count-vowels\"\n// =\u003e Writing value=6 from key=count-vowels\"\n// =\u003e {\"count\": 3, \"total\": 6, \"vowels\": \"aeiouAEIOU\"}\n```\n\n### Enabling Compilation Cache\nWhile Wazero (the underlying Wasm runtime) is very fast in initializing modules, you can make subsequent initializations even faster by enabling the compilation cache:\n\n```go\nctx := context.Background()\ncache := wazero.NewCompilationCache()\ndefer cache.Close(ctx)\n\nmanifest := Manifest{Wasm: []Wasm{WasmFile{Path: \"wasm/noop.wasm\"}}}\n\nconfig := PluginConfig{\n    EnableWasi:    true,\n    ModuleConfig:  wazero.NewModuleConfig(),\n    RuntimeConfig: wazero.NewRuntimeConfig().WithCompilationCache(cache),\n}\n\n_, err := NewPlugin(ctx, manifest, config, []HostFunction{})\n```\n\n### Integrate with Dylibso Observe SDK\nDylibso provides [observability SDKs](https://github.com/dylibso/observe-sdk) for WebAssembly (Wasm), enabling continuous monitoring of WebAssembly code as it executes within a runtime. It provides developers with the tools necessary to capture and emit telemetry data from Wasm code, including function execution and memory allocation traces, logs, and metrics.\n\nWhile Observe SDK has adapters for many popular observability platforms, it also ships with an stdout adapter:\n\n```\nctx := context.Background()\n\nadapter := stdout.NewStdoutAdapter()\nadapter.Start(ctx)\n\nmanifest := manifest(\"nested.c.instr.wasm\")\n\nconfig := PluginConfig{\n    ModuleConfig:   wazero.NewModuleConfig().WithSysWalltime(),\n    EnableWasi:     true,\n    ObserveAdapter: adapter.AdapterBase,\n}\n\nplugin, err := NewPlugin(ctx, manifest, config, []HostFunction{})\nif err != nil {\n    panic(err)\n}\n\nmeta := map[string]string{\n    \"http.url\":         \"https://example.com/my-endpoint\",\n    \"http.status_code\": \"200\",\n    \"http.client_ip\":   \"192.168.1.0\",\n}\n\nplugin.TraceCtx.Metadata(meta)\n\n_, _, _ = plugin.Call(\"_start\", []byte(\"hello world\"))\nplugin.Close()\n```\n\n### Enable filesystem access\n\nWASM plugins can read/write files outside the runtime. To do this we add `AllowedPaths` mapping of \"HOST:PLUGIN\" to the `extism.Manifest` of our plugin.\n\n```go\npackage main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\n\textism \"github.com/extism/go-sdk\"\n)\n\nfunc main() {\n\tmanifest := extism.Manifest{\n\t\tAllowedPaths: map[string]string{\n\t\t\t// Here we specifify a host directory data to be linked\n\t\t\t// to the /mnt directory inside the wasm runtime\n\t\t\t\"data\": \"/mnt\",\n\t\t},\n\t\tWasm: []extism.Wasm{\n\t\t\textism.WasmFile{\n\t\t\t\tPath: \"fs_plugin.wasm\",\n\t\t\t},\n\t\t},\n\t}\n\n\tctx := context.Background()\n\tconfig := extism.PluginConfig{\n\t\tEnableWasi: true,\n\t}\n\tplugin, err := extism.NewPlugin(ctx, manifest, config, []extism.HostFunction{})\n\n\tif err != nil {\n\t\tfmt.Printf(\"Failed to initialize plugin: %v\\n\", err)\n\t\tos.Exit(1)\n\t}\n\n\tdata := []byte(\"Hello world, this is written from within our wasm plugin.\")\n\texit, _, err := plugin.Call(\"write_file\", data)\n\tif err != nil {\n\t\tfmt.Println(err)\n\t\tos.Exit(int(exit))\n\t}\n}\n```\n\n\u003e *Note*: In order for filesystem APIs to work the plugin needs to be compiled with WASI target. Source code for the plugin can be found [here](https://github.com/extism/go-pdk/blob/main/example/fs/main.go) and is written in Go, but it could be written in any of our PDK languages.\n\n## Build example plugins\n\nSince our [example plugins](./plugins/) are also written in Go, for compiling them we use [TinyGo](https://tinygo.org/):\n\n```sh\ncd plugins/config\ntinygo build -target wasi -o ../wasm/config.wasm main.go\n```\n","funding_links":[],"categories":["\u003ca name=\"extism\"\u003e\u003c/a\u003e[Extism](https://github.com/extism/extism) \u003csup\u003e[top⇈](#contents)\u003c/sup\u003e","Go","WebAssembly"],"sub_categories":["Utility/Miscellaneous","Routers","路由器"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fextism%2Fgo-sdk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fextism%2Fgo-sdk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fextism%2Fgo-sdk/lists"}