Solid Gold: Building a Modular Minecraft Pyramid with Terraform
As a fun experiment using the Terraform Minecraft provider, I created a symmetrical pyramid entirely out of modules. The build uses a combination of local variables and structured iteration to layer solid cuboids upward into a clean, golden shape.
Beyond the visual result, the real takeaway here is how Terraform module composition and scoped iteration patterns can be used to manage complexity and assign clear responsibilities across layers of abstraction.
High-Level Design
The goal was to create a square-based pyramid that tapers as it rises, with each level formed from a solid cuboid. The pyramid is symmetrical and built upward from a defined starting position. Each layer shrinks inward by two blocks on both the X and Z axes, eventually culminating in a 2×2 apex. While the end product is visual and fun, the implementation is focused on clarity, reusability, and proper scoping of logic across modules.
Diamond Block instantiation of the module
Module Interface
The outer pyramid module takes in just three inputs:
variable "material" {
type = string
}
variable "start_position" {
type = object({
x = number
y = number
z = number
})
}
variable "length" {
type = number
}
These inputs define what block type to use (material), where the structure starts (start_position), and how wide the base should be (length). The pyramid is always square in plan, so this single length drives both width and depth.
module "pyramid" {
source = "./modules/solid-pyramid"
material = "minecraft:gold_block"
start_position = {
x = -1650,
y = 62,
z = -1100
}
length = 20
}
This makes it super simply to construct a huge pyramid in Minecraft with just a material, starting position, and a size.
Layer Calculation with Locals
The real work of shaping the pyramid happens in a locals block, where I calculate each horizontal layer of the pyramid. This approach decouples the geometry logic from the actual block placement, letting Terraform iterate over cleanly defined values:
locals {
layers = flatten([
for i in range(0, 100) : [
{
offset_x = i
offset_z = i
length = var.length - 2 * i
width = var.length - 2 * i
y = var.start_position.y + i
}
]
if var.length - 2 * i >= 2 && var.length - 2 * i >= 2
])
}
Each loop iteration defines a single layer:
- offset_x and offset_z shift the layer inward as it shrinks.
- length and width define the layer’s footprint, shrinking by 2 blocks per level.
- y increments upward to stack layers vertically.
The if guard ensures that iteration stops before the dimensions drop below 2×2, at which point the pyramid’s apex is formed.
Delegating to the Cuboid Module
Once the layers are defined, I delegate to a cuboid module for each layer:
module "pyramid_layers" {
for_each = {
for i, layer in local.layers : "layer_${i}" => layer
}
source = "../cuboid"
material = var.material
start_position = {
x = var.start_position.x + each.value.offset_x
y = each.value.y
z = var.start_position.z + each.value.offset_z
}
width = each.value.length
length = 1
depth = each.value.width
}
This is where the principle of scoping iteration outside the module comes into play. Rather than having the cuboidmodule calculate its own offsets or manage multiple layers, the outer pyramid module iterates explicitly and feeds each layer to a distinct instance of the cuboid module.
This pattern keeps modules single-purpose. Each module only needs to know about its own concern:
- The pyramid module handles geometric logic and stacking.
- The cuboid module builds a solid rectangular prism.
- Inside the cuboid, I use further module composition to build individual pillar blocks, and those pillar modules themselves perform their own internal iteration to stack Minecraft blocks along the Y-axis.
The result is a clean chain of delegation, where each module has a clear responsibility and works together in tandem.
The Math Behind the Layers
The pyramid’s geometry is derived from a simple arithmetic progression. Each new layer of the pyramid is offset by one block inward along both the X and Z axes and rises by one block along the Y-axis. At every step, the width and depth of the layer shrink by 2 — one from each side — until the base has narrowed to a minimum viable platform of 2×2.
This creates a predictable pattern where the total number of layers is roughly:
total_layers = floor((length - 2) / 2) + 1
For example, with a base length of 10:
- Layer 0: 8×8
- Layer 1: 6×6
- Layer 2: 4×4
- Layer 3: 2×2 (apex)
This gives us 5 total layers. The logic ensures a clean taper, and the +1 accounts for the final 2×2 apex layer.
This mathematical relationship is directly encoded in the locals block used to generate the layer data.

The use of flatten() and range(0, 100) is a practical way to generate candidate layers and then filter out the ones that no longer meet the minimum size requirement. Since the iteration halts at the 2×2 apex, this makes the process deterministic and robust for a wide range of input sizes.
Conclusion
Using the Terraform Minecraft provider, I was able to construct a pyramid in the game world with a single block of code. With local variables to drive intermediate calculations and strict boundaries between module responsibilities, the build is both visually and structurally elegant. And since everything is modular, it’s easy to tweak: change the material, shift the base, adjust the height — and the rest just works.
This was a fun project, but also a valuable exercise in thinking modularly with Terraform — whether you’re deploying infrastructure or building golden pyramids in Minecraft.
