Skip to content

Instantly share code, notes, and snippets.

@g-cqd
Created December 30, 2025 11:59
Show Gist options
  • Select an option

  • Save g-cqd/cb89a5b1f81f745e496265cf2697e30c to your computer and use it in GitHub Desktop.

Select an option

Save g-cqd/cb89a5b1f81f745e496265cf2697e30c to your computer and use it in GitHub Desktop.
Swift Package Ecosystem: Official Conventions & Best Practices - A comprehensive study of Apple/Swift.org package structure, naming, formatting, and tooling patterns

Swift Package Ecosystem: Official Conventions & Best Practices

A comprehensive study of how Apple and Swift.org official packages are structured, including file organization, naming conventions, code quality rules, formatting rules, and tooling patterns.

Packages Analyzed:


Table of Contents

  1. Package Structure
  2. Package.swift Conventions
  3. Naming Conventions
  4. Code Formatting Rules
  5. Documentation Patterns
  6. Testing Patterns
  7. CI/CD Setup
  8. GitHub Configuration
  9. Quick Reference

1. Package Structure

1.1 Standard Directory Layout

All official Swift packages follow this consistent structure:

package-name/
├── .github/
│   ├── ISSUE_TEMPLATE/
│   │   ├── BUG_REPORT.md
│   │   └── FEATURE_REQUEST.md
│   ├── workflows/
│   │   ├── pull_request.yml
│   │   └── main.yml
│   └── PULL_REQUEST_TEMPLATE.md
├── Benchmarks/              # Separate package for benchmarks
│   └── Package.swift
├── Documentation/           # Additional markdown docs
├── Examples/                # Example applications (if applicable)
├── Scripts/                 # Build/format scripts
├── Snippets/                # DocC code snippets
├── Sources/
│   ├── [ModuleName]/
│   │   ├── Documentation.docc/    # DocC catalog
│   │   └── [SourceFiles].swift
│   └── [SecondaryModule]/
├── Tests/
│   ├── [ModuleName]Tests/
│   └── [SecondaryModule]Tests/
├── .editorconfig
├── .gitignore
├── .licenseignore
├── .spi.yml                 # Swift Package Index config
├── .swift-format
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE.txt
├── Package.swift
├── README.md
└── SECURITY.md

1.2 Source Organization Patterns

Single Module Package (swift-log style)

Sources/
└── Logging/
    ├── Docs.docc/
    ├── LogHandler.swift
    ├── Logging.swift
    └── Locks.swift

Multi-Module Package (swift-collections style)

Sources/
├── Collections/              # Umbrella module
│   └── Collections.swift     # Re-exports other modules
├── DequeModule/
├── HeapModule/
├── OrderedCollections/
│   ├── OrderedDictionary/
│   └── OrderedSet/
└── InternalCollectionsUtilities/  # Underscore = internal

Large Package (swift-nio style)

Sources/
├── NIOCore/                  # Core abstractions
├── NIOPosix/                 # Platform implementation
├── NIO/                      # Umbrella module
├── NIOHTTP1/                 # Protocol layer
├── CNIODarwin/               # C interop (Darwin)
├── CNIOLinux/                # C interop (Linux)
└── _NIOBase64/               # Private module (underscore)

1.3 File Organization Within Modules

Pattern 1: One Feature Per File

Sources/Algorithms/
├── Chain.swift
├── Chunked.swift
├── Combinations.swift
└── Indexed.swift

Pattern 2: Extensions by Conformance

Sources/HeapModule/
├── Heap.swift
├── Heap+Descriptions.swift
├── Heap+ExpressibleByArrayLiteral.swift
├── Heap+Invariants.swift
├── Heap+UnsafeHandle.swift
└── _HeapNode.swift           # Internal (underscore prefix)

Pattern 3: Logical Grouping (with Spaces)

Sources/ArgumentParser/
├── Completions/
├── Documentation.docc/
├── Parsable Properties/      # Spaces allowed in folder names
├── Parsable Types/
├── Parsing/
├── Usage/
└── Utilities/

2. Package.swift Conventions

2.1 Standard Package.swift Template

// swift-tools-version:6.0

import PackageDescription

let package = Package(
    name: "swift-example",
    products: [
        .library(
            name: "Example",
            targets: ["Example"]
        ),
    ],
    dependencies: [
        // External dependencies (if any)
    ],
    targets: [
        .target(
            name: "Example",
            dependencies: []
        ),
        .testTarget(
            name: "ExampleTests",
            dependencies: ["Example"]
        ),
    ]
)

// MARK: - Standard Cross-Repo Settings

for target in package.targets {
    var settings = target.swiftSettings ?? []
    settings.append(.enableUpcomingFeature("MemberImportVisibility"))
    settings.append(.enableExperimentalFeature("StrictConcurrency=complete"))
    target.swiftSettings = settings
}

2.2 Naming Conventions

Element Convention Example
Package name lowercase-with-hyphens swift-algorithms
Library product PascalCase Algorithms
Target name PascalCase Algorithms
Test target [Target]Tests AlgorithmsTests
Internal module _[Name] prefix _SwiftSyntaxTestSupport

2.3 Platform Requirements

platforms: [
    .macOS(.v10_15),
    .iOS(.v13),
    .tvOS(.v13),
    .watchOS(.v6),
    .macCatalyst(.v13),
]

2.4 Swift Settings Block

All official packages include this standard settings block:

for target in package.targets {
    var settings = target.swiftSettings ?? []

    // Enable upcoming features
    settings.append(.enableUpcomingFeature("MemberImportVisibility"))

    // Enable strict concurrency
    settings.append(.enableExperimentalFeature("StrictConcurrency=complete"))

    target.swiftSettings = settings
}

3. Naming Conventions

3.1 Case Conventions Summary

Element Case Example
Types (struct, class, enum, protocol) UpperCamelCase ChunkedByCollection
Variables, properties, functions lowerCamelCase makeIterator()
Nested types Same as parent context Heap.Iterator
Global constants lowerCamelCase defaultTimeout
Enum cases lowerCamelCase case pending
Package names lowercase-with-hyphens swift-algorithms
Module/Target names PascalCase SwiftAlgorithms

3.2 Type Naming Patterns

Collection/Sequence Wrappers

// Pattern: [Descriptor][Collection|Sequence]
struct ChunkedByCollection<Base>
struct CombinationsSequence<Base>
struct EvenlyChunkedCollection<Base>

Nested Iterator and Index Types

struct Chain2Sequence<Base1, Base2> {
    struct Iterator: IteratorProtocol { ... }
    struct Index: Comparable { ... }
}

Internal Types (Underscore Prefix)

// Internal/private types use leading underscore
internal struct _Storage { ... }
internal struct _HeapNode { ... }
@usableFromInline internal struct _UnsafeBitSet { ... }

3.3 Protocol Naming

Pattern When to Use Examples
Noun Describes what something IS Collection, Sequence, Iterator
-able/-ible Something is done TO it Equatable, Hashable, Codable
-ing It IS DOING something ProgressReporting, Loading
Protocol suffix Class name collision FooProtocol (when Foo class exists)

3.4 Method Naming

Mutating vs Non-Mutating

Mutating (Verb) Non-Mutating (Noun/-ed/-ing)
sort() sorted()
reverse() reversed()
append(_:) appending(_:)
formUnion(_:) union(_:)

Factory Methods

func makeIterator() -> Iterator
func makeNoise() -> Sound

3.5 File Naming

Pattern Example
Main type definition Heap.swift
Extension by conformance Heap+ExpressibleByArrayLiteral.swift
Extension by feature Heap+Descriptions.swift
Internal implementation _HeapNode.swift
Test file HeapTests.swift
Test extension HelpGenerationTests+AtOption.swift

3.6 Internal Symbol Prefixes

Prefix Usage Example
_ Internal/private Swift symbols _storage, _find()
__ Public but internal symbols __check()
swt_ C/C++ internal symbols swt_function
SWT C/C++ types SWTContext

4. Code Formatting Rules

4.1 The Official .swift-format Configuration

This is the canonical configuration used across Apple's Swift packages:

{
    "version": 1,
    "lineLength": 120,
    "indentation": { "spaces": 2 },
    "tabWidth": 8,
    "maximumBlankLines": 1,
    "spacesBeforeEndOfLineComments": 2,
    "respectsExistingLineBreaks": true,
    "fileScopedDeclarationPrivacy": { "accessLevel": "private" },
    "indentConditionalCompilationBlocks": false,
    "indentSwitchCaseLabels": false,
    "lineBreakBeforeControlFlowKeywords": false,
    "lineBreakBeforeEachArgument": true,
    "lineBreakBeforeEachGenericRequirement": false,
    "lineBreakBetweenDeclarationAttributes": false,
    "lineBreakAroundMultilineExpressionChainComponents": false,
    "prioritizeKeepingFunctionOutputTogether": true,
    "spacesAroundRangeFormationOperators": false,
    "multiElementCollectionTrailingCommas": true,
    "noAssignmentInExpressions": { "allowedFunctions": ["XCTAssertNoThrow"] },
    "reflowMultilineStringLiterals": { "never": {} }
}

4.2 Enabled Rules by Default

Rule Description
AlwaysUseLowerCamelCase Identifiers use lowerCamelCase
DoNotUseSemicolons No semicolons
FileScopedDeclarationPrivacy Use private over fileprivate
NoBlockComments Use // not /* */
NoParensAroundConditions if x not if (x)
OrderedImports Alphabetize imports
UseTripleSlashForDocumentationComments Use /// for docs
OneCasePerLine Separate enum cases
OneVariableDeclarationPerLine One let/var per line
ReturnVoidInsteadOfEmptyTuple -> Void not -> ()
UseShorthandTypeNames [T] not Array<T>

4.3 Opt-In Rules (Disabled by Default)

Rule When to Enable
AllPublicDeclarationsHaveDocumentation Public APIs must have docs
NeverForceUnwrap Prohibit !
NeverUseForceTry Prohibit try!
NeverUseImplicitlyUnwrappedOptionals Prohibit Type!
UseEarlyExits Convert if...else to guard
NoLeadingUnderscores Disallow _ prefix

4.4 Key Formatting Values

Setting Official Value Notes
Indentation 2 spaces Most common; swift-nio uses 4
Line length 120 characters Some use 80 or 100
Trailing commas Required In multi-element collections
Blank lines Max 1 Between declarations
End-of-line comments 2 spaces before code // comment

4.5 EditorConfig

Standard .editorconfig:

root = true

[*]
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true

4.6 Import Ordering

Four-tier hierarchy (enforced by OrderedImports):

  1. Regular imports - Standard module imports
  2. Declaration imports - Imports with kind specifiers
  3. @_implementationOnly imports - Implementation-only
  4. @testable imports - Test imports

Groups separated by blank lines, sorted alphabetically within.


5. Documentation Patterns

5.1 File Header

All source files include this header:

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift [Project] open source project
//
// Copyright (c) [Year] Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

5.2 Documentation Comments

Basic Format

/// Returns the sum of two integers.
///
/// Use this method when you need to add two integers together.
///
/// - Parameters:
///   - a: The first integer.
///   - b: The second integer.
/// - Returns: The sum of `a` and `b`.
/// - Throws: `OverflowError` if the result overflows.
/// - Complexity: O(1)
func add(_ a: Int, _ b: Int) throws -> Int

Summary Rules

  • Single sentence, under 150 characters
  • No links or code formatting
  • End with period
  • Use verb phrases for methods, noun phrases for properties

Order of Tags

ParametersReturnsThrowsComplexity

5.3 DocC Structure

Sources/Module/
└── Documentation.docc/
    ├── Module.md              # Landing page
    ├── Extensions/            # API extensions
    ├── Articles/              # Guides
    │   └── GettingStarted.md
    ├── Tutorials/             # Step-by-step
    ├── Resources/             # Assets
    └── Info.plist

5.4 Section Dividers

Use LLVM-style dividers to separate logical sections:

//===----------------------------------------------------------------------===//
// MARK: - Iterator Implementation
//===----------------------------------------------------------------------===//

extension MyType: IteratorProtocol {
    // ...
}

5.5 MARK Comments

// MARK: - Public API
// MARK: - Internal Helpers
// MARK: - Protocol Conformance
// MARK: - Sendable Support

6. Testing Patterns

6.1 Test Directory Structure

Tests/
├── [Module]Tests/
│   ├── [Feature]Tests.swift
│   ├── [Feature]Tests+Extension.swift
│   └── TestUtilities.swift
└── _[Module]TestSupport/      # Shared test utilities

6.2 Test Naming Conventions

Test Files

[SourceFileName]Tests.swift
[Feature]Tests.swift
[Feature]Tests+[SubFeature].swift

Test Methods

XCTest Style:

func testParsing_SingleOption() { }
func testParsing_SingleOption_Fails() { }
func testHelp() { }
func test_init_empty() { }

Swift Testing Style:

@Test func autoclosure() throws { }
@Test func multiplexLogHandler() { }

6.3 Test Class Structure

import XCTest
@testable import Module

final class FeatureTests: XCTestCase {
    // MARK: - Setup

    override func setUp() { }
    override func tearDown() { }

    // MARK: - Basic Tests

    func testBasicBehavior() { }

    // MARK: - Edge Cases

    func testEmptyInput() { }
    func testNilHandling() { }
}

6.4 Common Test Utilities

Custom Assertions:

func expectEqual<T: Equatable>(_ actual: T, _ expected: T)
func expectEqualSequences<S1, S2>(_ s1: S1, _ s2: S2)
func AssertParse<T>(_ type: T.Type, _ arguments: [String])

Parameterized Testing:

withEvery("count", in: 0..<20) { count in
    // Test with each count value
}

Lifecycle Tracking:

withLifetimeTracking { tracker in
    // Verify object lifecycle
}

6.5 Test Support Modules

Private test support modules follow this pattern:

// _CollectionsTestSupport
struct MinimalSequence<Element>: Sequence { }
struct MinimalCollection<Element>: Collection { }

7. CI/CD Setup

7.1 Standard GitHub Actions Workflow

name: Pull Request

on:
  pull_request:
    types: [opened, reopened, synchronize]

permissions:
  contents: read

jobs:
  tests:
    name: Tests
    uses: swiftlang/github-workflows/.github/workflows/swift_package_test.yml@main
    with:
      enable_macos_checks: true
      enable_wasm_sdk_build: true

  soundness:
    name: Soundness
    uses: swiftlang/github-workflows/.github/workflows/soundness.yml@main
    with:
      license_header_check_project_name: "Swift Example"

7.2 Reusable Workflows

All official packages use shared workflows from:

  • swiftlang/github-workflows
  • apple/swift-nio/.github/workflows/

7.3 Standard CI Jobs

Job Purpose
tests Multi-platform unit tests
soundness License headers, formatting, API breakage
benchmarks Performance regression testing
cxx-interop C++ interoperability
static-linux Static Linux SDK builds
android Android SDK builds
wasm WebAssembly SDK builds

7.4 CI Compiler Flags

arguments: >-
  -Xswiftc -warnings-as-errors
  --explicit-target-dependency-import-check error
  -Xswiftc -require-explicit-sendable

7.5 Swift Version Matrix

Testing across multiple Swift versions:

  • Swift 5.9, 5.10
  • Swift 6.0, 6.1, 6.2
  • Nightly (main, 6.x branches)

8. GitHub Configuration

8.1 Issue Templates

Bug Report Template:

## Description
[Brief description of the bug]

## Steps to Reproduce
1. ...
2. ...

## Expected Behavior
[What should happen]

## Actual Behavior
[What actually happens]

## Environment
- Swift version:
- OS:
- Package version:

Feature Request Template:

## Motivation
[Why is this feature needed?]

## Proposed Solution
[Description of the feature]

## Alternatives Considered
[Other approaches you've thought about]

8.2 Pull Request Template

## Description
[Brief description of changes]

### Checklist
- [ ] Added tests for new functionality
- [ ] Updated documentation
- [ ] Followed code style guidelines
- [ ] Read CONTRIBUTING.md

8.3 Git Commit Template

Stored in dev/git.commit.template:

One line description of your change

Motivation:
Explain the context and why you're making this change.

Modifications:
Describe the modifications you've made.

Result:
What will change after this commit.

Configure with:

git config commit.template dev/git.commit.template

8.4 Swift Package Index Configuration

.spi.yml:

version: 1
builder:
  configs:
    - documentation_targets: [ModuleName]

9. Quick Reference

9.1 Checklist for New Packages

  • Use swift-tools-version:6.0 or later
  • Package name: lowercase-with-hyphens
  • Module names: PascalCase
  • Add .swift-format configuration
  • Add .editorconfig
  • Add CONTRIBUTING.md
  • Add LICENSE.txt (Apache 2.0 with Runtime Library Exception)
  • Add README.md
  • Add .spi.yml for Swift Package Index
  • Set up GitHub Actions using shared workflows
  • Add issue and PR templates
  • Enable strict concurrency in Package.swift
  • Add DocC documentation catalog

9.2 Formatting Commands

# Format all files
swift format format --parallel --in-place --recursive .

# Lint all files
swift format lint --strict --parallel --recursive .

9.3 Testing Commands

# Run all tests
swift test

# Run with strict flags
swift test -Xswiftc -warnings-as-errors \
           --explicit-target-dependency-import-check error

# Skip long tests
SKIP_LONG_TESTS=1 swift test

9.4 Common Performance Annotations

@inlinable        // Inline across modules
@usableFromInline // Expose to inlinable code
@frozen           // ABI-stable struct layout
@inline(__always) // Force inlining
@inline(never)    // Prevent inlining

9.5 Sendable Conformance Pattern

// At end of file
// MARK: - Sendable Conformance

extension MyType: Sendable {}
extension MyType.NestedType: @unchecked Sendable {}

Appendix A: Package Comparison Matrix

Package Indentation Line Length Swift Format SwiftLint
swift-algorithms 2 spaces 80 Yes No
swift-collections 2 spaces 120 No No
swift-argument-parser 2 spaces 80 Yes No
swift-nio 4 spaces 120 Yes No
swift-format 2 spaces 120 Yes No
swift-syntax 2 spaces 120 Yes No
swift-testing 2 spaces 80 Yes No
swift-log 4 spaces 120 Yes No

Appendix B: License Header Template

//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift [PROJECT_NAME] open source project
//
// Copyright (c) [YEAR] Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
//
//===----------------------------------------------------------------------===//

Appendix C: Resources


Generated from analysis of official Apple and Swift.org packages, December 2024.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment