Skip to content

Swift

Swift support in bufrnix enables generation of Swift Protocol Buffer code for iOS, macOS, and server-side Swift applications using SwiftProtobuf.

{
languages = {
swift = {
enable = true;
};
};
}
  • Type: bool
  • Default: false
  • Description: Enable Swift code generation
  • Type: string
  • Default: "proto/gen/swift"
  • Description: Output directory for generated Swift files
  • Type: string
  • Default: ""
  • Description: Name of the Swift package to create
  • Type: list of strings
  • Default: []
  • Description: Additional options to pass to protoc-gen-swift
{
description = "iOS app with protobuf support";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
bufrnix.url = "github:your-org/bufrnix";
};
outputs = { self, nixpkgs, bufrnix }:
let
system = "aarch64-darwin";
pkgs = import nixpkgs { inherit system; };
protoGen = bufrnix.lib.mkBufrnixPackage {
inherit pkgs;
inherit (pkgs) lib;
config = {
languages = {
swift = {
enable = true;
outputPath = "Generated/Proto";
options = [
"Visibility=Public"
"FileNaming=FullPath"
];
};
};
};
};
in {
packages.${system} = {
default = protoGen;
proto = protoGen;
};
devShells.${system}.default = pkgs.mkShell {
packages = with pkgs; [
protoGen
swift
protoc-gen-swift
];
};
};
}
{
languages = {
swift = {
enable = true;
outputPath = "Sources/ProtoModels";
packageName = "APIModels";
options = [
"Visibility=Public"
"FileNaming=PathToUnderscores"
];
};
};
}
import Foundation
import SwiftProtobuf
// Shared data models across iOS, macOS, and server
extension User_V1_User {
var displayName: String {
return name.isEmpty ? "Unknown User" : name
}
var isValidEmail: Bool {
return email.contains("@") && email.contains(".")
}
static func create(name: String, email: String) -> User_V1_User {
var user = User_V1_User()
user.id = UUID().uuidString
user.name = name
user.email = email
user.createdAt = Google_Protobuf_Timestamp(date: Date())
return user
}
}
// API client using protobuf
class APIClient {
private let baseURL: URL
init(baseURL: URL) {
self.baseURL = baseURL
}
func createUser(name: String, email: String) async throws -> User_V1_User {
var request = User_V1_CreateUserRequest()
request.name = name
request.email = email
let data = try request.serializedData()
var urlRequest = URLRequest(url: baseURL.appendingPathComponent("users"))
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/x-protobuf", forHTTPHeaderField: "Content-Type")
urlRequest.httpBody = data
let (responseData, _) = try await URLSession.shared.data(for: urlRequest)
return try User_V1_User(serializedData: responseData)
}
func getUser(id: String) async throws -> User_V1_User {
let url = baseURL.appendingPathComponent("users/\(id)")
let (data, _) = try await URLSession.shared.data(from: url)
return try User_V1_User(serializedData: data)
}
}

The Swift plugin supports several options that can be passed via the options configuration:

  • Visibility=Public - Generate public classes (default: internal)
  • Visibility=Package - Generate package-level visibility
  • FileNaming=FullPath - Use full proto path in generated file names
  • FileNaming=PathToUnderscores - Convert path separators to underscores
  • FileNaming=DropPath - Drop path from file names
  • ProtoPathModuleMappings=path/to/mapping.txt - Custom module mappings
  • SwiftProtobufModuleName=CustomProtobuf - Custom SwiftProtobuf module name
MySwiftProject/
├── Package.swift
├── Sources/
│ ├── MyApp/
│ │ ├── main.swift
│ │ └── Services/
│ └── ProtoModels/ # Generated protobuf code
│ ├── user/
│ │ └── v1/
│ │ └── user.pb.swift
│ └── common/
├── Tests/
├── proto/ # Source proto files
│ ├── user/
│ │ └── v1/
│ │ └── user.proto
│ └── buf.yaml
└── flake.nix
  • Use Any types sparingly for better performance
  • Prefer binary serialization over JSON when possible
  • Consider using UnknownStorage preservation for forward compatibility
  • Use MessageSet for extensible message types
  • SwiftProtobuf integrates well with Core Data
  • Works with Combine for reactive programming
  • Supports Codable for JSON APIs
  • Excellent performance with Vapor and Hummingbird
  • Works well with async/await
  • Good integration with database ORMs
  • Protobuf messages are value types (structs)
  • Automatic memory management
  • Efficient copying with copy-on-write semantics
  • No retain cycles to worry about
extension User_V1_User {
func toCoreDataUser(context: NSManagedObjectContext) -> CoreDataUser {
let user = CoreDataUser(context: context)
user.id = self.id
user.name = self.name
user.email = self.email
user.createdAt = self.createdAt.date
return user
}
static func fromCoreDataUser(_ user: CoreDataUser) -> User_V1_User {
var protoUser = User_V1_User()
protoUser.id = user.id ?? ""
protoUser.name = user.name ?? ""
protoUser.email = user.email ?? ""
if let createdAt = user.createdAt {
protoUser.createdAt = Google_Protobuf_Timestamp(date: createdAt)
}
return protoUser
}
}
import Combine
class UserRepository: ObservableObject {
@Published var users: [User_V1_User] = []
private let apiClient: APIClient
init(apiClient: APIClient) {
self.apiClient = apiClient
}
func fetchUsers() -> AnyPublisher<[User_V1_User], Error> {
return apiClient.getUsers()
.receive(on: DispatchQueue.main)
.handleEvents(receiveOutput: { [weak self] users in
self?.users = users
})
.eraseToAnyPublisher()
}
}
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
bufrnix = {
url = "github:conneroisu/bufrnix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
outputs = {
nixpkgs,
bufrnix,
flake-utils,
...
}:
flake-utils.lib.eachDefaultSystem (system: let
pkgs = import nixpkgs {inherit system;};
# Create our bufrnix package with Swift language support
bufrnixPkg = bufrnix.lib.mkBufrnixPackage {
inherit pkgs;
config = {
languages = {
swift = {
enable = true;
outputPath = "proto/gen/swift";
};
};
};
};
in {
packages.default = bufrnixPkg;
devShells.default = pkgs.mkShell {
packages = with pkgs; [
bufrnixPkg
swift
protoc-gen-swift
];
shellHook = ''
echo "Swift protobuf example development environment"
echo "Available commands:"
echo " bufrnix_init - Initialize proto structure"
echo " bufrnix - Generate Swift code from proto files"
echo " bufrnix_lint - Lint proto files"
'';
};
});
}