Core concepts
Provider-defined functions
Expose pure, stateless functions callable from Terraform configuration with provider::name::function().
Terraform ≥ 1.8 lets providers expose pure functions callable directly from HCL configuration –
output "upper" {
value = provider::mycloud::uppercase("hello")
# → "HELLO"
}Functions are stateless and have no side effects. They run during plan, not apply.
Implementing a function
import type { TerrablyFunction, FunctionSignature, FunctionCallContext, Provider } from "terrably";
import { types } from "terrably";
export class UppercaseFunction implements TerrablyFunction {
constructor(_provider: Provider) {}
getName(): string { return "uppercase"; }
getSignature(): FunctionSignature {
return {
parameters: [
{ name: "input", type: types.string(), description: "The string to convert." },
],
returnType: { type: types.string() },
summary: "Convert a string to uppercase",
};
}
call(_ctx: FunctionCallContext, args: unknown[]): unknown {
return String(args[0]).toUpperCase();
}
}Registering functions
Add getFunctions() to your Provider implementation –
import { UppercaseFunction } from "./functions/uppercase.js";
export class MyCloudProvider implements Provider {
// ...existing methods...
getFunctions(): FunctionClass[] {
return [UppercaseFunction];
}
}FunctionSignature
Prop
Type
FunctionParameter
Prop
Type
Variadic functions
Declare a variadicParameter to accept a variable number of trailing arguments –
export class ConcatFunction implements TerrablyFunction {
getName() { return "concat"; }
getSignature(): FunctionSignature {
return {
parameters: [
{ name: "separator", type: types.string() },
],
variadicParameter: { name: "values", type: types.string() },
returnType: { type: types.string() },
summary: "Join strings with a separator",
};
}
call(_ctx: FunctionCallContext, args: unknown[]): unknown {
const [separator, ...values] = args as string[];
return values.join(separator);
}
}output "joined" {
value = provider::mycloud::concat(", ", "apple", "banana", "cherry")
# → "apple, banana, cherry"
}Error handling
Report errors via ctx.diagnostics. Terraform aborts plan/apply and displays the error alongside the output:
call(ctx: FunctionCallContext, args: unknown[]): unknown {
const n = args[0] as number;
if (n < 0) {
ctx.diagnostics.addError(
"Invalid argument",
`Expected a non-negative number, got ${n}.`,
);
return 0; // return a safe default; Terraform discards it on error
}
return Math.sqrt(n);
}Throwing a JavaScript exception also surfaces as a FunctionError to Terraform:
call(_ctx: FunctionCallContext, args: unknown[]): unknown {
const n = args[0] as number;
if (n < 0) throw new Error(`Expected non-negative, got ${n}`);
return Math.sqrt(n);
}Prefer ctx.diagnostics for user-facing validation errors — they produce cleaner Terraform output.
Last updated on