← Back to list

A Guide to Generating Swift Code with Swift Mustache (Part 1)

About the song.  Can Swift code generate Swift code?  Approach 1: Swift Mustache. Conclusion (to Part 1!)

Esraa Eid in Deloitte UK Engineering Blog · 2025-10-07 10:11 · 75 claps · 10.6 min read
#ios-development #code-generation #swift #open-source #mobile-app-development
Open on Medium ↗
Wiki topics: 📱 · Mobile Development 🔓 · Open Source 🎵 · Music & Audio

A Guide to Generating Swift Code with Swift Mustache (Part 1)

**About the song. [Can Swift code generate Swift code? ](#24af) [Approach 1: Swift Mustache.](#4269) Conclusion (to Part 1!)**

The following section contains a short cultural story about the song “Enta Omri” by Umm Kulthum. If you’re not interested in this topic, feel free to skip it.

About the song

Umm Kulthum is a name that echoes through the corridors of history. Her most famous song, “Enta Omri” (“You Are My Life”), composed by Mohamed Abdel Wahab, was a significant milestone in her illustrious career.

The title, ‘Enta Omri,’ is a term of endearment in Arabic, often used to express deep affection. This song, famously dubbed ‘The Meeting of the Clouds,’ marked the first artistic collaboration between Umm Kulthum and Abdel Wahab. With ‘Enta Omri,’ Abdel Wahab blended traditional Egyptian music with innovative Western elements, incorporating the electric guitar and a long instrumental intro. This fusion made the song particularly special, securing its place in Egyptian musical history.

I chose to share this song because the lyrics of Enta Omri are rich with profound emotional depth. The line, “All I lived before your eyes met mine, was wasted time, how could it still count as mine?” by Ahmed Shafiq Kamel, beautifully captures the transformative power of discovery. It speaks to that moment when something or someone changes your entire perspective, making everything before it feel incomplete.

Thank you for taking a moment to discover this cultural gem with me. I’d love to hear your thoughts if it resonates with you, too.

Can Swift code generate Swift code?

Is it possible to give Xcode a JSON schema and make it generate a Swift struct? What if the struct is more complex and could have functions inside it? Is that all possible to generate? Do I need to learn some low-level language to do that? Those are all questions I kept asking myself during a previous open-source project. I was working on a Swift project to make it easy for developers to write AWS SAM deployment descriptors in the Swift programming language.

My main goal? To transform JSON Schema to Swift and generate Swift struct based on complex JSON Schema Specifications. The process involved reading a JSON Schema and generating Swift structs that conform to its detailed specifications — I will touch on this later.

While trying to make this happen, I explored three different Swift code generation techniques:

  • Swift Mustache (a template-based generator)
  • Swift Syntax (a tree-based code generator)
  • Swift OpenAPI Generator (for generating code from OpenAPI specifications)

Understanding JSON Schema

Before generating code, it’s essential to grasp the concept of JSON Schema.

JSON, short for JavaScript Object Notation, is a widely used data format, especially in web APIs. JSON Schema builds on that by providing a formal way to define the structure and validation rules for JSON data.

In this section, I implemented the approach using a dedicated Swift package project I created for this article, available on GitHub: SwiftCodeGenerator

In this project, I used JSON Schema as a blueprint to generate Swift struct.

Here’s a simplified example of a JSON Schema:

{
"type": "object",
"properties": {
"name": { "type": "string" },
"age": { "type": "integer" }
 }
}

And here’s the Swift struct that could be generated from it:

struct Person: Codable {
let name: String
let age: Int
}

This article walks you through each approach of the Swift code generation techniques, highlighting its benefits and challenges. So, keep Umm Kulthum playing in the background, and let’s dive in! 🎶

Approach 1: Swift Mustache

Swift Mustache is a logic-less templating engine that uses predefined templates to generate code by replacing placeholders with actual values. It is widely used for generating text-based content, including code, HTML, and configuration files.

What is a “Template”?

A template is a pre-designed format that you can fill in with different content, similar to a fill-in-the-blanks worksheet. If you’ve used Shopify to build a website, you may have encountered the term “template” in relation to Liquid, a templating language used to generate dynamic web pages. Liquid is an open-source template language created by Shopify and written in Ruby. It powers Shopify themes and allows dynamic content generation for storefronts. After you provide data, the templating tool replaces placeholders with real values, producing the final output.

*Swift Mustache is a logic-less templating engine that uses predefined templates to generate code by replacing placeholders with actual values. It is widely used for generating text-based content, including code, HTML, and configuration files.*

Templates + Data = Final Output.

What Does “Logic-less” Mean?

A logic-less template avoids complex code. Instead of if conditions or loops, Mustache uses simple placeholders and sections to format the output. So, it’s not about “no logic” just minimal logic.

How Does Swift Mustache Work?

With Swift Mustache, you define a template for a Swift struct, and then use JSON Schema data to populate it.

Example Mustache Template for a Struct:

//This Mustache template generates a Swift struct with Codable conformance 
// based on a provided name and a list of properties.

struct {{name}}: Codable {
{{#properties}}
let {{variable}}: {{type}}
{{/properties}}
}

Generated Swift Code:

struct Person: Codable {
let name: String
let age: Int
}

Integrating Swift Mustache in Your Project

Inside the SwiftCodeGenerator repository, we’ll create a new package to integrate Swift Mustache. If you’re unfamiliar with Swift packages, check out this tutorial.

In Package.swift, add:

// swift-tools-version: 6.0 
// The swift-tools-version declares the minimum version of Swift required to build this package. 

// Import the necessary module to describe the package 
import PackageDescription 

let package = Package( 
   name: "SwiftGenerator", 

    // MARK: - Platform Requirements 
    // Specifies that this package requires macOS 12.0 or later 
    // This ensures compatibility with the required Swift and dependency versions 
   platforms: [ 
        .macOS(.v12) 
    ], 

    // MARK: - Products 
    // Defines what this package provides to consumers 
   products: [ 
// Library: Can be imported and used by other Swift packages/apps 
       .library( 
           name: "SwiftGenerator",  
           targets: ["SwiftGenerator"]),  
   ], 

   // MARK: - Dependencies 
   // External packages this project depends on 
   dependencies: [ 
 // Hummingbird Mustache: Template engine for generating Swift code 
       .package(url: "https://github.com/hummingbird-project/hummingbird-mustache.git", from: "1.0.3"), 
   ], 

    // MARK: - Targets 
    // Defines the modules/components of this package 
   targets: [ 
// Main library target: Contains the core SwiftGenerator functionality 
       .target(name: "SwiftGenerator" , dependencies: [ 
           .product(name: "HummingbirdMustache", package: "hummingbird-mustache"), 
       ]), 
  // Test target: Unit tests for the SwiftGenerator library 
       .testTarget( 
           name: "SwiftGeneratorTests", 
           dependencies: ["SwiftGenerator"] 
       ), 
   ] 
) 

2- Create Project Structure:

Inside your Sources/SwiftGenerator folder:

  • StructTemplate.swift → defines the struct template.
  • MustacheTemplateGenerator.swift → helper functions for rendering templates.
  • main.swift → entry point to generate code.

The directory structure should look like this:

In StructTemplate.swift, add:

extension Templates {
    static let structTemplate = """
struct {{name}}: Codable {
    {{#properties}}
    let {{variable}}: {{type}}
    {{/properties}}
}
"""
};

In MustacheTemplateGenerator.swift, add:

import HummingbirdMustache
// MARK: - Mustache Template Generator 
// This enum provides functionality to generate Swift structs using Mustache templates. 
// It acts as a bridge between the data models and the template rendering system. 

public enum Templates { 
    static func generateStruct(from data: [String: Any]) -> String { 
        do { 
            // Create a Mustache template instance from the struct template string 
            // This template is defined in SturctTemplate.swift 

            let template = try HBMustacheTemplate(string: Templates.structTemplate) 
            // Render the template with the provided data 
            // This replaces all Mustache placeholders with actual values 
            return template.render(data) 

        } catch { 
            // Handle template rendering errors gracefully 
            // Common errors include malformed template syntax or invalid data structure 
            print("Error rendering template: \(error)") 
            return "" 
        } 
    } 
} 

In SwiftGenerator.swift adds a dictionary with key-value pairs as an example to generate a struct dynamically:

public struct SwiftGenerator { 
   public init() {} 

  //MARK: - Hummingbird Mustache 
   public func generateWithSwiftMustache() { 
       let data: [String: Any] = [ 
           "name": "User", 
           "properties": [ 
               ["variable": "id", "type": "Int"], 
               ["variable": "name", "type": "String"], 
               ["variable": "email", "type": "String"] 
           ] 
       ] 
// Generate Swift code using the Mustache template 
       let generatedCode = Templates.generateStruct(from: data) 
       print(generatedCode) 
   } 
} 

3- Executable Target:

To execute the package, update Package.swift file to include an executable target:

let package = Package( 
   name: "SwiftGenerator", 
   platforms: [ 
        .macOS(.v12) 
    ], 
   products: [ 

// Executable: Command-line tool that can be run directly 
       .executable( 
               name: "SwiftGeneratorExecutable", 
               targets: ["SwiftGeneratorExecutable"] 
           ),       
      .library( 
           name: "SwiftGenerator", 
           targets: ["SwiftGenerator"]), 
   ], 
   dependencies: [ 
       .package(url: "https://github.com/hummingbird-project/hummingbird-mustache.git", from: "1.0.3"), 
   ], 
   targets: [ 
       .target(name: "SwiftGenerator" , dependencies: [ 
           .product(name: "HummingbirdMustache", package: "hummingbird-mustache"), 
       ]), 

// Executable target: Command-line interface for the generator 
       .executableTarget( 
           name: "SwiftGeneratorExecutable", 
           dependencies: [ 
// Depends on the main SwiftGenerator library 
               .byName(name: "SwiftGenerator"), 
           ] 
       ), 
       .testTarget( 
           name: "SwiftGeneratorTests", 
           dependencies: ["SwiftGenerator"] 
       ), 
   ] 
) 

4- Generate the Code:

In main.swift, call the function generateWithSwiftMustache to generate the struct:

// MARK: - SwiftGenerator Executable 
// This is the command-line interface for the SwiftGenerator tool. 
// It demonstrates how to use the SwiftGenerator library to generate Swift code. 
import SwiftGenerator 

// MARK: - Initialize Generator 
// Create an instance of SwiftGenerator to access its code generation capabilities 
let generator = SwiftGenerator() 

// Option 1: Generate using Hummingbird Mustache (template-based approach) 
// This method uses Mustache templates to generate Swift code 
generator.generateWithSwiftMustache() 

Then run the project in the terminal using:

swift run

You should see the generated structure printed on the terminal like this:

struct User: Codable {
let id: Int
let name: String
let email: String
}

Let’s Spice It Up

Want to support optional fields and arrays? Just update the logic in your data model and the Mustache template:

In SwiftGenerator.swift add the following lines:

public func generateWithSwiftMustache() {
        let data: [String: Any] = [
            "name": "User",
            "properties": [
                [
                    "variable": "id",
                    "type": "Int",
                    "isOptional": false,
                    "isArray": false
                ],
                [
                    "variable": "name",
                    "type": "String",
                    "isOptional": true,
                    "isArray": false
                ],
                [
                    "variable": "email",
                    "type": "String",
                    "isOptional": false,
                    "isArray": true
                ]
            ]
        ]
      let generatedCode = Templates.generateStruct(from: data)
      print(generatedCode)
    }

In the StructTemplate.swift, update the struct template for generating Swift code:

extension Templates {
    static let structTemplate = """
struct {{name}}: Codable {
    {{#properties}}
    let {{variable}}: {{#isArray}}[{{/isArray}}{{type}}{{#isOptional}}?{{/isOptional}}{{#isArray}}]{{/isArray}}
    {{/properties}}
}
"""
}

Mustache Syntax Breakdown:

{{name}}: Simple variable substitution

  • Replaces with the struct name (e.g., “User”, “Person”).

{{#properties}}: Section tag (loop)

  • Iterates through each property in the properties array.
  • Everything between {{#properties}} and {{/properties}} is repeated for each property.

{{variable}}: Property name (e.g., “id”, “name”, “email”)

{{#isArray}}[{{/isArray}}{{type}}{{#isOptional}}?{{/isOptional}}{{#isArray}}]{{/isArray}}: Complex conditional logic

  • {{#isArray}}[{{/isArray}}: If isArray is true, add opening bracket [.
  • {{type}}: The Swift type (e.g., “String”, “Int”).
  • {{#isOptional}}?{{/isOptional}}: If isOptional is true, add ?.
  • {{#isArray}}]{{/isArray}}: If isArray is true, add closing bracket ].

Then run the project in the terminal using:

swift run

Voila! You should see the generated structure printed on the terminal like this:

struct User: Codable {
    let id: Int
    let name: String?
    let email: [String]
}

Writing to a File & Using Structs with Swift Mustache

To improve readability and reusability, instead of printing the output directly to the terminal, let’s write the generated code to a file.

Step 1: Add a File Writing Helper In your SwiftGenerator.swift, add the following function to handle file writing:

 // MARK: - File Writing Helpers 
    private func writeToFile(_ content: String, filename: String, directory: String = "Generated") throws { 
        let fileManager = FileManager.default 
        let currentDirectory = fileManager.currentDirectoryPath 
        let outputDirectory = "\(currentDirectory)/\(directory)" 

        // Create directory if it doesn't exist 
        // This ensures the output directory exists before writing files 
        if !fileManager.fileExists(atPath: outputDirectory) { 
            try fileManager.createDirectory(atPath: outputDirectory, withIntermediateDirectories: true) 
        } 

        // Write the generated code to the file 
        let filePath = "\(outputDirectory)/\(filename)" 
        try content.write(toFile: filePath, atomically: true, encoding: .utf8) 
        print(" Generated file: \(filePath)") 
    } 

Step 2: Add Struct and Property Models Create a new Model folder inside Sources/SwiftGenerator, and add two files, StructData.swift and Property.swift.

  • In the StructData.swift:
import Foundation  

public struct StructData { 
    let name: String 
    let properties: [Property] 

    public init(name: String, properties: [Property]) { 
        self.name = name 
        self.properties = properties 
    } 

    // Convert to dictionary for Mustache template 
    func toDictionary() -> [String: Any] { 
        return [ 
            "name": name, 
            "properties": properties.map { property in 
                [ 
                    "variable": property.variable, 
                    "type": property.type, 
                    "isOptional": property.isOptional, 
                    "isArray": property.isArray 
                ] 
            } 
        ] 
    } 
} 

// MARK: - Convenience Initializers 
extension StructData { 
    public static func user() -> StructData { 
        return StructData( 
            name: "User", 
            properties: [ 
                Property(variable: "id", type: "Int"), 
                Property.optional("name", type: "String"), 
                Property.array("emails", type: "String") 
            ] 
        ) 
    } 

    public static func person() -> StructData { 
        return StructData( 
            name: "Person", 
            properties: [ 
                Property(variable: "id", type: "UUID"), 
                Property.optional("firstName", type: "String"), 
                Property.optional("lastName", type: "String"), 
                Property.array("phoneNumbers", type: "String"), 
                Property(variable: "age", type: "Int") 
            ] 
        ) 
    } 
}

In the Property.swift:

import Foundation 

public struct Property { 
    let variable: String 
    let type: String 
    let isOptional: Bool 
    let isArray: Bool 

    public init(variable: String, type: String, isOptional: Bool = false, isArray: Bool = false) { 
        self.variable = variable 
        self.type = type 
        self.isOptional = isOptional 
        self.isArray = isArray 
    } 
} 

// MARK: - Convenience Initializers 
extension Property { 
    public static func optional(_ variable: String, type: String) -> Property { 
        return Property(variable: variable, type: type, isOptional: true) 
    } 

    public static func array(_ variable: String, type: String) -> Property { 
        return Property(variable: variable, type: type, isArray: true) 
    } 

    public static func optionalArray(_ variable: String, type: String) -> Property { 
        return Property(variable: variable, type: type, isOptional: true, isArray: true) 
    } 
} 

Step 3: Update the generateWithSwiftMustache()function Now update your generation function to use StructData and write the result to a file:

  //MARK: - Hummingbird Mustache 
    public func generateWithSwiftMustache() { 
        let structData = StructData.user() 

        // Generate Swift code using the Mustache template 
        let generatedCode = Templates.generateStruct(from: structData.toDictionary()) 

        // Write the generated code to a file 
        do { 
            try writeToFile(generatedCode, filename: "User.swift") 
        } catch { 
            print("Error writing file: \(error)") 
        } 
    } 

Final Hierarchy & Output After running the command:

swift run

You can see a new Generated directory with a User.swift file inside:

Other Use Cases for Swift Mustache

HTML Rendering

Swift Mustache can generate dynamic HTML for server-side Swift frameworks like Vapor.

For example, if you’re building a blog, you don’t want to write a new HTML page whenever you create a new post. Instead, you can use a template that automatically fills in the title, author, and content.

Vapor is a server-side Swift framework for building web applications and APIs. Unlike iOS apps on a user’s device, server-side Swift runs on a web server and responds with HTML pages or JSON data.

Is Swift Mustache Limited to Swift?

Yes, Swift Mustache is a Swift-specific implementation of the Mustache templating language. However, Mustache itself is not limited to Swift , it has implementations in multiple languages, including:

  • JavaScript
  • Python
  • Ruby
  • Java
  • PHP

Benefits of Swift Mustache

  • Customizable templates with a separation of code generation templates from the core code, along with examples for multiple cases.
  • Supports custom inheritance, loops, optionals, and encoding/decoding.

Challenges of using Swift Mustache

  • Mustache templates lack detailed debugging information, making it difficult to identify missing elements or required fixes.
  • No comprehensive documentation was found that showcases various template examples.
  • Mustache is a templating language that requires a learning curve for generating complex code, such as manual decoding and encoding, methods, statements, and enum with associated values.

For more details, check out the Mustache Syntax Documentation.

Conclusion (to Part 1!)

In this part, we laid the groundwork for code generation in Swift using Swift Mustache, which offers flexibility and simplicity for basic struct generation. But what if you need more structure, type safety, and integration with the Swift compiler?

In **Part Two, we’ll dive deeper into SwiftSyntax and Swift OpenAPI Generator, **exploring how these tools give you precise control over how your Swift code is constructed from schemas and specifications.


메타데이터
post_id
d985711e2c2c
slug
a-guide-to-generating-swift-code-with-swift-mustache-part-1-d985711e2c2c
url
https://medium.com/deloitte-uk-cloud-blog/a-guide-to-generating-swift-code-with-swift-mustache-part-1-d985711e2c2c
canonical_url
https://medium.com/deloitte-uk-cloud-blog/a-guide-to-generating-swift-code-with-swift-mustache-part-1-d985711e2c2c
author_url
https://medium.com/@esraa-eid
status
ok
fetched_at
2026-06-15 20:49:13