Core Concepts
This section explains the building blocks of a Facets module. You’ll learn how modules declare what they offer, what they require, and how they connect with others using a shared type system.
This section introduces the foundational constructs that define how modules work in Facets. These concepts make it easier to build modular, composable infrastructure by standardizing how configuration and connections are defined.
We’ll start with the most fundamental building block: types, and then explore how they apply to inputs, outputs, and wiring.
🧭 Module Anatomy Overview
╭────────────────────────╮ ╭────────────────────────────╮ ╭────────────────────────────╮
│ Module A (VPC) │ │ Type System │ │ Module B (GKE) │
│ ─ Outputs: │ │ - @outputs/vpc │ │ ─ Inputs: │
│ - default │──────▶ │ - Declared in facets.yaml │◀────── │ - network: @outputs/vpc │
╰────────────────────────╯ ╰────────────────────────────╯ ╰────────────────────────────╯
▲ │
│ ▼
Written by module author Consumed by another module
╭────────────────────────╮
│ Developer View │
│ ─ spec: │
│ - region │
│ - node_count │
│ - schedule │
╰────────────────────────╯
▲
│
Consumed via Facets UI/API
This diagram shows how modules define and consume inputs and outputs using a shared type system. Types enable compatibility across independently authored modules, while the spec
defines the user-facing configuration shown to developers.
This diagram shows how modules define what they expose and what they expect — using a type-driven model. These types are declared in the facets.yaml
, and the system uses them to wire modules together safely.
🧬 Types
Types define the shape and purpose of values that flow between modules. They follow a common pattern: @outputs/xyz
, where xyz
is the type name — like:
@outputs/vpc
@outputs/project
@outputs/cluster
Types are:
- Defined by module authors or organizations
- Stored and versioned in the Facets registry
- Reused across modules to ensure compatibility
Think of types as shared contracts. They let modules snap together, even if they were developed independently.
📊 Developer Inputs (spec)
Each module defines a spec
, which represents the set of inputs that a developer is allowed to configure. These inputs map to familiar concepts in your organization such as region
, node_count
, or project_id
.
These values:
- Are structured and validated
- Power the form-based UI and JSON input options
- Allow developers to focus only on what they need to configure
The
spec
defines the developer-facing contract. It is used in the Facets UI and API to provide a clean configuration experience.
🧩 Inputs from Other Modules
Modules can also accept values that come from the outputs of other modules. These are defined in the inputs:
section of the module's definition.
Each entry in the inputs:
section defines:
- A key name (e.g.,
network
) - The expected type (e.g.,
@outputs/vpc
)
At deployment time, Facets connects these inputs to outputs from upstream modules of the same type.
Example:
- A Kubernetes cluster module may require a VPC with
@outputs/vpc
- That input could be fulfilled by any module exposing that type — such as a VPC module or a landing zone setup
This model allows modules to be reused flexibly across environments and use cases.
📤 Outputs
Modules expose one or more outputs that can be consumed by other modules. Each output has:
- A key (e.g.,
default
,attributes.project_id
) - A type (e.g.,
@outputs/project
,@outputs/project_id
)
These outputs are referenced by other modules using the type system — ensuring compatibility and discoverability.
Example:
A GCP project module might expose:
default
: of type@outputs/project
attributes.project_id
: of type@outputs/project_id
Outputs make a module usable by others. Types make that usage safe and predictable.
In the next section, we’ll walk through how to structure and build a Facets module using these principles. Coding specifics will be covered separately.
Updated 6 days ago