A Swift protoc plugin for projects that exchange Protocol Buffers over JSON.
It runs Apple's protoc-gen-swift, preserves the generated Swift type declarations,
removes the binary wire-format extensions, and adds Foundation Decodable
conformances.
- Swift 6.0 or later
protoc- Apple's
protoc-gen-swift
Install the required tools with Homebrew:
brew install protobuf swift-protobufBuild the executable and copy it to a directory on your PATH:
swift build -c release --product protoc-gen-swift-json
cp .build/release/protoc-gen-swift-json /path/on/your/PATH/The plugin looks for protoc-gen-swift next to its own executable, on PATH,
or at the path specified by the PROTOC_GEN_SWIFT environment variable.
protoc \
--proto_path=./proto \
--swift-json_out=./Sources/Generated \
./proto/example/v1/*.protoThe generated filename is <basename>.pb.swift, matching Apple's plugin output.
Every imported .proto must be reachable through --proto_path. The repository
provides optional scripts for common Google APIs and legacy
validate/validate.proto imports:
scripts/install-common-protos.sh
protoc \
--proto_path=./proto \
$(scripts/proto-paths.sh) \
--swift-json_out=./Sources/Generated \
./proto/example/v1/*.protoThe legacy PGV schema is installed only so protoc can resolve imports. This
plugin does not generate or run validation code. If you use
Buf, let Buf resolve the dependency graph instead.
Pass options with --swift-json_opt:
protoc \
--swift-json_out=./Sources/Generated \
--swift-json_opt='Visibility=Public,entry_points=Example_User' \
./proto/example.proto| Option | Default | Description |
|---|---|---|
entry_points=<name>;<name>;... |
all types | Emits types reachable from the given top-level Swift type names |
coding_key_style=camel_case|snake_case |
camel_case |
Uses proto3 JSON lower-camel-case keys or original proto field names |
timestamp_decoder=<TypeName> |
none | Delegates google.protobuf.Timestamp JSON strings to a custom decoder |
additional_imports=<Module>;<Module>;... |
none | Adds imports needed by custom decoder types |
struct_decoder=true |
false |
Decodes google.protobuf.Struct, Value, and ListValue recursively |
Other options are forwarded to Apple's protoc-gen-swift, including
Visibility=Public.
When entry_points excludes an imported type, the plugin emits a minimal
Decodable stub so the generated code still compiles. Use timestamp_decoder
or struct_decoder when the JSON payload of those well-known types must be
preserved.
The timestamp delegate must expose this function:
public enum ExampleTimestampDecoder {
public static func decode(_ value: String) throws -> Date { ... }
}Then pass it to the plugin:
--swift-json_opt='entry_points=Example_User,timestamp_decoder=ExampleTimestampDecoder,additional_imports=ExampleDateSupport'struct_decoder=true requires no delegate:
--swift-json_opt='entry_points=Example_User,struct_decoder=true'- Missing or
nullproto3 fields use their zero value. - A field with an incompatible JSON value falls back to its proto3 default without failing the entire message.
- Enums accept their proto name, a stringified number, or a JSON number.
- Unknown values use Apple's
UNRECOGNIZED(Int)case for open enums and the default case for closed enums. - Oneofs try members in declaration order and keep the first value that decodes.
- Generated code supports JSON decoding only.
Encodableis not generated. - Binary protobuf serialization and parsing are not generated.
- Reflection, gRPC, Connect, and other transport layers are out of scope.
- Generated types still depend on the
SwiftProtobufruntime. - This plugin requires Apple's
protoc-gen-swift; it is not a standalone replacement for it.
Apache 2.0. See LICENSE and NOTICE.
- apple/swift-protobuf provides the plugin SDK, generated type declarations, and runtime used by emitted code.
- bufbuild/protobuf-es inspired the JSON-only positioning.