Skip to content
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
331 changes: 331 additions & 0 deletions documentation/content/en/book/04-using-functions/wasm-functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,331 @@
---
title: "Using WASM Functions"
linkTitle: "Using WASM Functions"
weight: 5
description: >
How to run, develop, and deploy WebAssembly (WASM) functions with kpt.
---

WASM functions are an alternative to container-based KRM functions. They're faster to start, smaller to distribute, and run in a sandboxed environment.

## Why use WASM functions?

{{< warning type=warning title="Note" >}}
WASM support in kpt is currently in alpha and not ready for production use. The API and behavior may change in future releases.
{{< /warning >}}

WASM functions have some advantages over container-based functions:

- Faster startup - no container runtime needed
- Smaller size - WASM modules are typically much smaller than container images
- Better security - sandboxed execution with no host access by default
- More portable - run anywhere WASM is supported
- Lower resource usage

## Running WASM functions

WASM support is an alpha feature. You need to use the `--allow-alpha-wasm` flag to enable it.

Comment on lines +27 to +28
### With `fn render`

Add the WASM function to your Kptfile pipeline:

```yaml
# Kptfile
apiVersion: kpt.dev/v1
kind: Kptfile
metadata:
name: my-package
pipeline:
mutators:
- image: gcr.io/my-org/my-wasm-fn:v1.0.0
configMap:
key: value
```

```shell
kpt fn render my-package --allow-alpha-wasm
```

kpt will detect the function as WASM if the OCI image has a `js/wasm` platform manifest.

### With `fn eval`

Run WASM functions imperatively:

```shell
kpt fn eval my-package --allow-alpha-wasm -i gcr.io/my-org/my-wasm-fn:v1.0.0 -- key=value
```

### Using local WASM files

You can run local `.wasm` files with the `--exec` flag:

```shell
kpt fn eval my-package --allow-alpha-wasm --allow-exec --exec ./my-function.wasm
```
Comment on lines +60 to +66

You can also declare local WASM files in your `Kptfile`:

```yaml
# Kptfile
apiVersion: kpt.dev/v1
kind: Kptfile
metadata:
name: my-package
pipeline:
mutators:
- exec: ./functions/my-function.wasm
```

```shell
kpt fn render my-package --allow-alpha-wasm --allow-exec
```

Note: Using local WASM files makes your package less portable since the file needs to exist on every system.

## Publishing WASM functions

### Push a WASM module

Compress and push a WASM module to an OCI registry:

```shell
kpt alpha wasm push ./my-function.wasm gcr.io/my-org/my-wasm-fn:v1.0.0
```

What this does:
1. Compresses the WASM file into a tar archive
2. Creates an OCI image with `js/wasm` platform
3. Pushes to the registry

### Pull a WASM module

Download and decompress a WASM module:

```shell
kpt alpha wasm pull gcr.io/my-org/my-wasm-fn:v1.0.0 ./my-function.wasm
```

Useful for:
- Testing WASM functions locally
- Inspecting modules
- Offline caching

## Developing WASM functions

WASM functions follow the [KRM Functions Specification](https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md). They receive a `ResourceList` as input and return a `ResourceList` as output.

### What you need

- A language that compiles to WASM (Go, Rust, etc.)
- WASM build toolchain
- KRM functions SDK

### Example: Go WASM function
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would avoid adding code examples to the docs and maybe ref/link to an example function instead


Here's how to build a Go KRM function for WASM. You need two files - one for regular builds and one for WASM:

`main.go` (regular build):

```go
//go:build !(js && wasm)

package main

import (
"os"

"github.com/kptdev/krm-functions-sdk/go/fn"
)

func main() {
if err := fn.AsMain(fn.ResourceListProcessorFunc(process)); err != nil {
os.Exit(1)
}
}

func process(rl *fn.ResourceList) (bool, error) {
for i := range rl.Items {
// Your transformation logic
rl.Items[i].SetAnnotation("processed-by", "my-fn")
}
return true, nil
}
```

`main_js.go` (WASM build):

```go
//go:build js && wasm

package main

import (
"syscall/js"

"github.com/kptdev/krm-functions-sdk/go/fn"
)

// Keep js.Func values referenced at package level to prevent garbage collection.
var (
processResourceListFunc js.Func
processResourceListErrorsFunc js.Func
)

func main() {
if err := run(); err != nil {
panic(err)
}
}

func run() error {
resourceList := []byte("")

processResourceListFunc = resourceListWrapper(&resourceList)
js.Global().Set("processResourceList", processResourceListFunc)
processResourceListErrorsFunc = resourceListErrors(&resourceList)
js.Global().Set("processResourceListErrors", processResourceListErrorsFunc)

// Keep the program running
select {}
}

// process applies the same transformation logic as in the non-WASM build.
func process(rl *fn.ResourceList) (bool, error) {
for i := range rl.Items {
// Your transformation logic
rl.Items[i].SetAnnotation("processed-by", "my-fn")
}
return true, nil
}

func transform(input []byte) ([]byte, error) {
return fn.Run(fn.ResourceListProcessorFunc(process), input)
}

func resourceListWrapper(resourceList *[]byte) js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) any {
if len(args) != 1 {
return "Invalid number of arguments"
}
input := args[0].String()
output, err := transform([]byte(input))
*resourceList = output
if err != nil {
return "unable to process: " + err.Error()
}
return string(output)
})
}

func resourceListErrors(resourceList *[]byte) js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) any {
rl, err := fn.ParseResourceList(*resourceList)
if err != nil {
return ""
}
errors := ""
for _, r := range rl.Results {
if r.Severity == "error" {
errors += r.Message
}
}
return errors
})
}
```

### Build for WASM

```shell
GOOS=js GOARCH=wasm go build -o my-function.wasm .
```

### Test locally

```shell
kpt fn eval ./test-package --allow-alpha-wasm --allow-exec --exec ./my-function.wasm
```

### Publish

Push to a registry:

```shell
kpt alpha wasm push ./my-function.wasm gcr.io/my-org/my-wasm-fn:v1.0.0
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid referencing gcr.io
Maybe use a dummy registry example


# Test the published version
kpt fn eval ./test-package --allow-alpha-wasm -i gcr.io/my-org/my-wasm-fn:v1.0.0
```

## Complete example

From development to deployment:

```shell
# 1. Write your function code (main.go and main_js.go)

# 2. Build
GOOS=js GOARCH=wasm go build -o my-function.wasm .

# 3. Test locally
kpt fn eval ./test-package --allow-alpha-wasm --allow-exec --exec ./my-function.wasm

Comment on lines +162 to +164
# 4. Publish
kpt alpha wasm push ./my-function.wasm gcr.io/my-org/my-wasm-fn:v1.0.0

# 5. Use in a package
cat <<EOF > Kptfile
apiVersion: kpt.dev/v1
kind: Kptfile
metadata:
name: my-package
pipeline:
mutators:
- image: gcr.io/my-org/my-wasm-fn:v1.0.0
EOF

# 6. Render
kpt fn render my-package --allow-alpha-wasm
```

## Limitations

### Alpha status

WASM support is alpha, which means:
- API may change
- Requires `--allow-alpha-wasm` flag
- Some features may be limited

### Security

WASM functions run in a sandbox:
- No network access
- No filesystem access (except input/output resources)
- Can't execute system commands
Copy link

Copilot AI Feb 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The “Security” section states WASM functions have no network/filesystem access and no host access by default. kpt supports both wasmtime (default) and node.js-based runtimes (selectable via KPT_FN_WASM_RUNTIME), and the node.js runtime can expose broader host capabilities to Go WASM via syscall/js. Please qualify these claims (e.g., “with wasmtime runtime…”) to avoid overstating the sandbox guarantees.

Copilot uses AI. Check for mistakes.

This is more secure but also more restrictive.

### Performance

- Faster startup than containers
- CPU-intensive operations may be slower
- Different memory patterns
- Benchmark if performance is critical

### Compatibility

Not all container functions can convert to WASM:
- Functions needing network access
- Functions with complex dependencies
- Platform-specific code

## See also

- [KRM Functions Specification](https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md)
- [Functions Catalog](https://catalog.kpt.dev/)
- [kpt alpha wasm push](../../../reference/cli/alpha/wasm/push/)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use relrefs, and make sure the docs preview renders the links correctly.
eg: ({{% relref "/reference/cli/alpha/wasm/push" %}})

- [kpt alpha wasm pull](../../../reference/cli/alpha/wasm/pull/)
Comment on lines +219 to +220
Comment on lines +219 to +220
Comment on lines +219 to +220
- [WASM function examples](https://github.com/kptdev/krm-functions-catalog/tree/main/functions/go)