Buildable

1.0.0

Buildable - Production-grade Builders for Swift, without the boilerplate. Powered by Swift Macros.
xtro/buildable

What's New

2026-02-08T20:33:51Z

Buildable
Production-grade Builders for Swift, without the boilerplate. Powered by Swift Macros.

Buildable generates fluent, type-safe builders for your models so you can focus on behavior, not repetitive setup code.
This is especially useful in tests, fixtures, prototyping, and anywhere model construction starts to drown out intent.


Why Buildable Exists

In real projects, builders are everywhere:

  • Test data setup
  • Complex nested models
  • Enums with associated values
  • Avoiding 12-parameter initializers no one enjoys reading

And yet they are:

  • Repetitive
  • Error-prone
  • Painfully boring to maintain

Buildable turns builders into generated infrastructure, the way they always should have been.


Features

  • Zero manual builder boilerplate
  • Immutable fluent builders or mutable builders
  • Nested builders via @Built
  • Default value handling
  • Enum support (associated values, labels, tuples)
  • Explicit, predictable failure modes

Requirements

  • Swift 5.9+
  • Xcode 15+

Macros are non-negotiable. Blame Apple.


Installation (Swift Package Manager)

Add the package via Xcode (File → Add Packages…), then:

import Buildable

Example 1: Realistic Test Fixture

Model

@Buildable
struct User {
    let id: UUID
    let email: String
    var isAdmin: Bool = false
}

Usage

let user = UserBuilder()
    .id(UUID())
    .email("user@example.com")
    .build()

XCTAssertEqual(user?.isAdmin, false)

You get readable intent without noise. Defaults behave like defaults.


Example 2: Nested Models You Actually See in Apps

Models

@Buildable
struct Address {
    let city: String
    let country: String
}

@Buildable
struct Profile {
    let name: String
    @Built let address: Address
}

Usage

let profile = ProfileBuilder()
    .name("Gábor")
    .address {
        $0.city("Budapest")
         .country("Hungary")
         .build()
    }
    .build()

Nested builders read top-down, exactly like the object graph.


Example 3: Mutable Builder for Complex Setup

Some test setups are easier with mutation. That is allowed.

Model

@Buildable(isMutable: true)
struct Order {
    let id: String
    let amount: Int
    var isPaid: Bool = false
}

Usage

let builder = OrderBuilder()
builder.id = "order-42"
builder.amount = 3
builder.isPaid = true

let order = try builder.build()

Failure Behavior

Missing required values throw:

BuilderError.missingParameter("amount")

No guessing. No silent corruption.


Example 4: Enums from Real Domains

Model

@Buildable
enum AppAction {
    case login(email: String, password: String)
    case logout
    case deepLink(URL)
}

Usage

let login = AppActionBuilder()
    .login(email: "test@site.com", password: "123456")
    .build()

let logout = AppActionBuilder().logout().build()

Labels are preserved. Intention survives refactors.


Example 5: Enum Case with Nested Builder

Model

@Buildable
enum Event {
    @Built case purchase(Order)
    case cancel(reason: String)
}

Usage

let event = EventBuilder()
    .purchase { builder in
        builder.id("order-1")
        .amount(5)
        .build()
    }
    .build()

Note: @Built enum cases currently support a single associated value only.


Default Value Rules

  • let value: T → required
  • let value: T? → optional
  • var value: T = default → optional in builder, default used on build
  • Computed properties are ignored

Immutable builders return nil if required values are missing.
Mutable builders throw explicit errors.


When to Use Which Builder

  • Immutable

    • Short fixtures
    • Declarative tests
    • Snapshot-style setup
  • Mutable

    • Large object graphs
    • Step-by-step configuration
    • Conditional setup logic

You can mix both in the same codebase.


Design Philosophy

  • Builders are infrastructure, not handwritten art projects
  • Generated code must be predictable and boring
  • Errors should surface immediately
  • Readability beats cleverness

Contributing

PRs are welcome if they:

  • Add tests
  • Preserve API stability
  • Don’t introduce magical behavior

If it makes builders mysterious, it probably won’t be merged.


License

MIT

Description

  • Swift Tools 6.2.0
View More Packages from this Author

Dependencies

Last updated: Sun Feb 08 2026 13:12:09 GMT-1000 (Hawaii-Aleutian Standard Time)