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:
- swift-algorithms
- swift-collections
- swift-argument-parser
- swift-nio
- swift-format
- swift-syntax
- swift-testing
- swift-log
- Package Structure
- Package.swift Conventions
- Naming Conventions
- Code Formatting Rules
- Documentation Patterns
- Testing Patterns
- CI/CD Setup
- GitHub Configuration
- Quick Reference
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
Sources/
└── Logging/
├── Docs.docc/
├── LogHandler.swift
├── Logging.swift
└── Locks.swift
Sources/
├── Collections/ # Umbrella module
│ └── Collections.swift # Re-exports other modules
├── DequeModule/
├── HeapModule/
├── OrderedCollections/
│ ├── OrderedDictionary/
│ └── OrderedSet/
└── InternalCollectionsUtilities/ # Underscore = internal
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)
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/
// 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
}| 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 |
platforms: [
.macOS(.v10_15),
.iOS(.v13),
.tvOS(.v13),
.watchOS(.v6),
.macCatalyst(.v13),
]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
}| 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 |
// Pattern: [Descriptor][Collection|Sequence]
struct ChunkedByCollection<Base>
struct CombinationsSequence<Base>
struct EvenlyChunkedCollection<Base>struct Chain2Sequence<Base1, Base2> {
struct Iterator: IteratorProtocol { ... }
struct Index: Comparable { ... }
}// Internal/private types use leading underscore
internal struct _Storage { ... }
internal struct _HeapNode { ... }
@usableFromInline internal struct _UnsafeBitSet { ... }| 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) |
| Mutating (Verb) | Non-Mutating (Noun/-ed/-ing) |
|---|---|
sort() |
sorted() |
reverse() |
reversed() |
append(_:) |
appending(_:) |
formUnion(_:) |
union(_:) |
func makeIterator() -> Iterator
func makeNoise() -> Sound| 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 |
| 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 |
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": {} }
}| 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> |
| 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 |
| 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 |
Standard .editorconfig:
root = true
[*]
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = trueFour-tier hierarchy (enforced by OrderedImports):
- Regular imports - Standard module imports
- Declaration imports - Imports with kind specifiers
- @_implementationOnly imports - Implementation-only
- @testable imports - Test imports
Groups separated by blank lines, sorted alphabetically within.
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
//
//===----------------------------------------------------------------------===///// 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- Single sentence, under 150 characters
- No links or code formatting
- End with period
- Use verb phrases for methods, noun phrases for properties
Parameters → Returns → Throws → Complexity
Sources/Module/
└── Documentation.docc/
├── Module.md # Landing page
├── Extensions/ # API extensions
├── Articles/ # Guides
│ └── GettingStarted.md
├── Tutorials/ # Step-by-step
├── Resources/ # Assets
└── Info.plist
Use LLVM-style dividers to separate logical sections:
//===----------------------------------------------------------------------===//
// MARK: - Iterator Implementation
//===----------------------------------------------------------------------===//
extension MyType: IteratorProtocol {
// ...
}// MARK: - Public API
// MARK: - Internal Helpers
// MARK: - Protocol Conformance
// MARK: - Sendable SupportTests/
├── [Module]Tests/
│ ├── [Feature]Tests.swift
│ ├── [Feature]Tests+Extension.swift
│ └── TestUtilities.swift
└── _[Module]TestSupport/ # Shared test utilities
[SourceFileName]Tests.swift
[Feature]Tests.swift
[Feature]Tests+[SubFeature].swift
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() { }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() { }
}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
}Private test support modules follow this pattern:
// _CollectionsTestSupport
struct MinimalSequence<Element>: Sequence { }
struct MinimalCollection<Element>: Collection { }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"All official packages use shared workflows from:
swiftlang/github-workflowsapple/swift-nio/.github/workflows/
| 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 |
arguments: >-
-Xswiftc -warnings-as-errors
--explicit-target-dependency-import-check error
-Xswiftc -require-explicit-sendableTesting across multiple Swift versions:
- Swift 5.9, 5.10
- Swift 6.0, 6.1, 6.2
- Nightly (main, 6.x branches)
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]## Description
[Brief description of changes]
### Checklist
- [ ] Added tests for new functionality
- [ ] Updated documentation
- [ ] Followed code style guidelines
- [ ] Read CONTRIBUTING.mdStored 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.spi.yml:
version: 1
builder:
configs:
- documentation_targets: [ModuleName]- Use
swift-tools-version:6.0or later - Package name:
lowercase-with-hyphens - Module names:
PascalCase - Add
.swift-formatconfiguration - Add
.editorconfig - Add
CONTRIBUTING.md - Add
LICENSE.txt(Apache 2.0 with Runtime Library Exception) - Add
README.md - Add
.spi.ymlfor 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
# Format all files
swift format format --parallel --in-place --recursive .
# Lint all files
swift format lint --strict --parallel --recursive .# 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@inlinable // Inline across modules
@usableFromInline // Expose to inlinable code
@frozen // ABI-stable struct layout
@inline(__always) // Force inlining
@inline(never) // Prevent inlining// At end of file
// MARK: - Sendable Conformance
extension MyType: Sendable {}
extension MyType.NestedType: @unchecked Sendable {}| 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 |
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//- Swift API Design Guidelines
- swift-format Repository
- swiftlang GitHub Workflows
- Swift Package Manager Documentation
- DocC Documentation
Generated from analysis of official Apple and Swift.org packages, December 2024.