Migrating from CUE to defkit
If you have existing KubeVela definitions written in raw CUE or YAML manifests, this guide shows the mechanical mapping to defkit Go code. The generated CUE output is semantically equivalent — the cluster sees the same definitions.
Existing CUE definitions continue to work alongside defkit-based definitions. You can migrate incrementally, one definition at a time.
This guide covers ComponentDefinition and TraitDefinition — the most common migration targets. PolicyDefinition and WorkflowStepDefinition follow the same parameter patterns.
Step 0 — Scaffold a new module
vela def init-module --name my-platform \
--components webservice,worker \
--traits scaler,env
go get github.com/oam-dev/kubevela/pkg/definition/defkit@latest
Step 1 — Migrate Parameters
Every field in a CUE parameter: block maps directly to a defkit constructor.
parameter: {
// +usage=Container image
image: string
// +usage=Number of replicas
replicas: *1 | int
// +usage=Enable debug mode
debug: *false | bool
// +usage=Allowed log levels
logLevel: *"info" | "debug" | "warn" | "error"
// +usage=CPU request, e.g. "500m"
cpu?: string
// +usage=Environment variables
env?: [...{
name: string
value?: string
}]
// +usage=Port mappings
ports?: [...{
port: int
protocol: *"TCP" | "UDP"
expose: *false | bool
}]
// +usage=Extra labels to add
labels?: [string]: string
}
image := defkit.String("image").
Description("Container image")
replicas := defkit.Int("replicas").Default(1).
Description("Number of replicas")
debug := defkit.Bool("debug").Default(false).
Description("Enable debug mode")
logLevel := defkit.Enum("logLevel").
Values("info", "debug", "warn", "error").
Default("info").
Description("Allowed log levels")
cpu := defkit.String("cpu").Optional().
Description(`CPU request, e.g. "500m"`)
env := defkit.List("env").Optional().
Description("Environment variables").
WithFields(
defkit.String("name"),
defkit.String("value").Optional(),
)
ports := defkit.Array("ports").Optional().
Description("Port mappings").
WithFields(
defkit.Int("port"),
defkit.Enum("protocol").Values("TCP","UDP").Default("TCP"),
defkit.Bool("expose").Default(false),
)
labels := defkit.StringKeyMap("labels").Optional().
Description("Extra labels to add")
Mapping rules:
| CUE | defkit |
|---|---|
*default | type | .Default(value) |
field: (non-optional) | bare param, no modifier (this is the default) |
field?: (optional, may be absent) | .Optional() |
field!: (user must explicitly set) | .Required() |
[string]: string | defkit.StringKeyMap() |
[...{...}] with fixed schema | defkit.Array().WithFields() |
[...] open/heterogeneous list | defkit.List() |
// +usage=... comments | .Description("...") |
In defkit, a bare parameter (no .Optional(), no .Default()) compiles to a CUE required field (field: type). This matches the CUE convention but means you must call .Optional() for any param that was previously optional (field?: type in CUE). Failing to do so will make the parameter mandatory in the generated schema.
Step 2 — Migrate the Template Body
output: {
apiVersion: "apps/v1"
kind: "Deployment"
metadata: name: context.name
spec: {
replicas: parameter.replicas
template: spec: containers: [{
name: context.name
image: parameter.image
if parameter.cpu != _|_ {
resources: limits: cpu: parameter.cpu
}
if parameter.env != _|_ {
env: parameter.env
}
ports: [for p in parameter.ports {
containerPort: p.port
protocol: p.protocol
}]
}]
}
}
func myTemplate(tpl *defkit.Template) {
vela := defkit.VelaCtx()
cpu := defkit.String("cpu")
env := defkit.List("env")
ports := defkit.Array("ports")
replicas := defkit.Int("replicas")
image := defkit.String("image")
containerPorts := defkit.NewArray().ForEachWith(ports,
func(item *defkit.ItemBuilder) {
v := item.Var()
item.Set("containerPort", v.Field("port"))
item.Set("protocol", v.Field("protocol"))
})
deployment := defkit.NewResource("apps/v1", "Deployment").
Set("metadata.name", vela.Name()).
Set("spec.replicas", replicas).
Set("spec.template.spec.containers[0].name", vela.Name()).
Set("spec.template.spec.containers[0].image", image).
Set("spec.template.spec.containers[0].ports", containerPorts).
SetIf(cpu.IsSet(), "spec.template.spec.containers[0].resources.limits.cpu", cpu).
SetIf(env.IsSet(), "spec.template.spec.containers[0].env", env)
tpl.Output(deployment)
}
Mapping rules:
| CUE | defkit |
|---|---|
if parameter.x != _|_ { ... } | .SetIf(x.IsSet(), path, value) or .If(x.IsSet())...EndIf() |
[for v in parameter.ports { ... }] | defkit.NewArray().ForEachWith(ports, func(item) { ... }) |
context.name | defkit.VelaCtx().Name() |
context.appName | defkit.VelaCtx().AppName() |
context.namespace | defkit.VelaCtx().Namespace() |
output: { ... } | tpl.Output(resource) |
outputs: foo: { ... } | tpl.Outputs("foo", resource) |