terrably
Core concepts

Types & Schema

The TfType system, Attribute, Block, NestedBlock, and Schema — terrably's building blocks for describing provider resources.

Types

Every attribute in a schema requires a TfType. Types are created via the types factory — each call returns a fresh instance.

import { types } from "terrably";

Prop

Type

Composing types

types.list(types.string())          // list of strings
types.map(types.number())           // map of numbers
types.set(types.string())           // set of strings
types.list(types.map(types.bool())) // list of maps of booleans

Custom TfType<T>

Implement this interface to define a custom type –

interface TfType<T = unknown> {
  encode(value: T | null | UnknownType): unknown;
  decode(value: unknown): T | null | UnknownType;
  semanticallyEqual(a: T | null, b: T | null): boolean;
  tfType(): Uint8Array; // JSON bytes, e.g. Buffer.from('"string"')
}

Attribute

Describes a single field in a resource or provider schema.

import { Attribute, types } from "terrably";

new Attribute(name: string, type: TfType, options?: AttributeOptions)

AttributeOptions

Prop

Type

Common patterns

// Required user input
new Attribute("name", types.string(), { required: true })

// Server-assigned, read-only
new Attribute("id", types.string(), { computed: true })

// User may set; provider fills in a default if not set
new Attribute("size", types.string(), { optional: true, computed: true, default: "small" })

// Sensitive — masked in plan output
new Attribute("token", types.string(), { required: true, sensitive: true })

// Force-replace when this changes (e.g. region or OS image)
new Attribute("region", types.string(), { required: true, requiresReplace: true })

optional: true, computed: true together means "user can set it, or the provider will compute a default". This is useful for auto-assigned values like name or region that the user might want to control.


NestedBlock

Represents a block that can appear zero or more times (e.g. network_interface, tags).

import { NestedBlock, Block, Attribute, types } from "terrably";

new NestedBlock(
  typeName: string,
  nestingMode: NestMode,
  block: Block,
  options?: NestedBlockOptions
)
NestModeTerraform equivalentTypeScript shape
"single"At most one blockobject | null
"list"Ordered list of blocksobject[]
"set"Unordered set of blocksobject[]
"map"Map of blocks keyed by a labelRecord<string, object>
"group"Exactly one block (implicit)object

Example — resource with a tags nested block

import { Schema, Attribute, Block, NestedBlock, types } from "terrably";

new Schema([
  new Attribute("id",   types.string(), { computed: true }),
  new Attribute("name", types.string(), { required: true }),
], [
  new NestedBlock("tags", "set", new Block([
    new Attribute("key",   types.string(), { required: true }),
    new Attribute("value", types.string(), { required: true }),
  ]), { minItems: 0, maxItems: 10 }),
])

SET blocks are order-insensitive. "set" nesting uses semantic equality — two NestedBlock values whose items are identical but in a different order are treated as unchanged. Use "list" when order matters.

BlockOptions

Pass BlockOptions as the third argument to new Block(...) to set documentation or deprecation on the block itself — distinct from per-attribute options.

Prop

Type

new NestedBlock("legacy_config", "single", new Block(
  [new Attribute("endpoint", types.string(), { optional: true })],
  [],
  { deprecated: true, deprecationMessage: "Use the top-level endpoint attribute instead." }
))
# Terraform config using the tags block
resource "mycloud_server" "example" {
  name = "web-1"

  tags {
    key   = "env"
    value = "production"
  }
  tags {
    key   = "team"
    value = "platform"
  }
}

Schema

Top-level schema for a resource, data source, or provider.

import { Schema } from "terrably";

new Schema(
  attributes: Attribute[] = [],
  blockTypes: NestedBlock[] = [],
  version: number = 0,
  blockOpts?: BlockOptions       // optional — description/deprecation for the block itself
)

version starts at 0. Increment it whenever the shape of stored state changes (renamed or removed attributes) and implement Resource.upgrade() to migrate old state. See Schema migration for patterns.

Use blockOpts to set a description or deprecation message on the resource's top-level block (shown in terraform providers schema and the Terraform Registry) –

new Schema(
  [new Attribute("id", types.string(), { computed: true })],
  [],
  1,
  { description: "Manages a cloud server instance.", deprecated: false }
)

Last updated on

On this page