← Back to all posts

My Open Source Journey: Building SwiftSky from Zero to 500+ Stars

Open Source Swift Community Career

Why I Started SwiftSky

In 2019, I was building Mizzle and found myself writing the same weather API integration code over and over. Every new feature meant more boilerplate: JSON parsing, error handling, unit conversions, caching.

I thought: “Someone must have already solved this.” I searched GitHub for Swift weather libraries and found:

  • Abandoned projects from 2015
  • Libraries using outdated Swift patterns
  • Poorly documented code
  • No support for modern async/await

So I did what any developer would do: I built my own solution and open-sourced it.

Today, SwiftSky has over 500 GitHub stars, powers 100+ apps, and taught me more about software engineering than any course ever could.

The First Commit

Here’s the embarrassing truth: my first commit was terrible.

// My actual first commit (simplified)
class WeatherAPI {
    func getWeather(lat: Double, lon: Double, completion: @escaping (Data?, Error?) -> Void) {
        let url = "https://api.darksky.net/forecast/\(apiKey)/\(lat),\(lon)"
        // Force unwrapping everywhere
        URLSession.shared.dataTask(with: URL(string: url)!) { data, response, error in
            completion(data, error) // No error handling!
        }.resume()
    }
}

Problems:

  • Force unwrapping (crashes waiting to happen)
  • No error handling
  • API key hardcoded (security issue)
  • No input validation
  • Non-idiomatic Swift

But I shipped it anyway. Version 0.1.0.

The First User

Three weeks after publishing to GitHub, I got my first issue:

“Love the idea! But it crashes when the network is offline. Can you add error handling?”

This was my introduction to being a maintainer. Someone was actually using my code! And they had expectations!

I spent that weekend refactoring the entire error handling system:

enum WeatherError: Error {
    case invalidURL
    case networkError(Error)
    case invalidResponse
    case decodingError(Error)
}

func getWeather(lat: Double, lon: Double) async throws -> Weather {
    guard let url = URL(string: buildURL(lat: lat, lon: lon)) else {
        throw WeatherError.invalidURL
    }

    do {
        let (data, response) = try await URLSession.shared.data(from: url)

        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            throw WeatherError.invalidResponse
        }

        return try JSONDecoder().decode(Weather.self, from: data)
    } catch let error as DecodingError {
        throw WeatherError.decodingError(error)
    } catch {
        throw WeatherError.networkError(error)
    }
}

That first user became a contributor. They added tests, improved documentation, and helped shape the API design.

Lesson learned: Your first users are gold. Listen to them.

The Documentation Wake-Up Call

After six months, SwiftSky had about 50 stars. Then I got this issue:

“This looks useful but I can’t figure out how to use it. Can you add examples?”

I looked at my README. It was four lines:

# SwiftSky
A Swift weather library.

## Installation
Add to Package.swift

## Usage
See the code.

Ouch.

I spent the next week writing comprehensive documentation:

  • Quick start guide
  • Detailed API reference
  • Multiple usage examples
  • Migration guides
  • Common pitfalls
  • FAQ section

Within a month, stars tripled. Lesson learned: Documentation is as important as code. Maybe more important.

The Breaking Change Debacle

In version 2.0, I made a decision I regret: I changed the entire API without a deprecation period.

// v1.x
let weather = try await api.getWeather(lat: 52.0, lon: 4.0)

// v2.0 - completely different!
let weather = try await api.forecast(latitude: 52.0, longitude: 4.0)

The GitHub issues exploded:

  • “Why did you break my app?”
  • “This should have been v3.0, not v2.0!”
  • “No migration guide??”
  • “I’m switching to [competitor]”

I learned about semantic versioning the hard way:

  • Major version (1.0 → 2.0): Breaking changes allowed
  • Minor version (1.0 → 1.1): New features, backwards compatible
  • Patch version (1.0.0 → 1.0.1): Bug fixes only

But just because breaking changes are “allowed” doesn’t mean you should make them without:

  1. Deprecation warnings - Give users time to migrate
  2. Migration guides - Show exactly what to change
  3. Reasoning - Explain why the change was necessary
  4. Parallel support - Support both APIs for one version

I spent two weeks:

  • Writing a comprehensive migration guide
  • Adding deprecated wrappers for old API
  • Reaching out to major users personally
  • Answering every single GitHub issue

Lesson learned: Breaking changes break trust. Handle them with care.

The Dark Sky API Shutdown

In 2020, Apple acquired Dark Sky and announced they’d shut down the API.

SwiftSky was built entirely around the Dark Sky API. Hundreds of apps depended on SwiftSky. And the API was disappearing.

This was my first major crisis as a maintainer.

The Solution: Provider Abstraction

I refactored SwiftSky to support multiple weather providers:

// Protocol-based provider system
protocol WeatherProvider {
    func fetchWeather(latitude: Double, longitude: Double) async throws -> Weather
}

// Users can now choose their provider
let sky = SwiftSky(provider: .openWeather, apiKey: "key")
// or
let sky = SwiftSky(provider: .weatherKit)
// or implement their own

This took three months of work:

  • Designing the abstraction layer
  • Building adapters for OpenWeather, WeatherKit, etc.
  • Creating a data normalization system (every API returns different formats)
  • Writing tests for each provider
  • Updating all documentation

But it future-proofed SwiftSky. When the next API shuts down, users can just switch providers.

Lesson learned: Don’t build on a single dependency. Always have a plan B.

The Contributor Who Became a Friend

A developer named Alex opened a PR to add Combine support. The PR was 500+ lines and beautifully written.

We went back and forth on the design:

  • Me: “Let’s keep Combine as a separate package”
  • Alex: “Users want reactive bindings in the main package”
  • Me: “What about package size?”
  • Alex: “Make it optional with conditional imports”

Alex was right. We merged the PR. Then Alex contributed:

  • Vapor integration for server-side Swift
  • SwiftUI property wrappers
  • Example projects
  • Documentation improvements

Today, Alex is a co-maintainer. We chat regularly about API design, Swift news, and life.

Lesson learned: Open source creates unexpected friendships.

The Stats (As of Today)

  • 500+ GitHub stars
  • 100+ apps using SwiftSky in production
  • 50+ contributors (code, docs, issues)
  • 10,000+ downloads via Swift Package Manager
  • 300+ closed issues
  • 5 years of active maintenance

What Open Source Gave Me

Technical Skills

  • API design and ergonomics
  • Backwards compatibility strategies
  • Testing and CI/CD
  • Performance optimization
  • Technical writing
  • Swift language deep dives

Soft Skills

  • Community management
  • Handling feedback (positive and negative)
  • Saying no politely
  • Asynchronous communication
  • Public speaking (gave talks about SwiftSky)

Career Impact

  • Featured prominently on my resume
  • Topic of discussion in every interview
  • Led to freelance opportunities
  • Built network in iOS community
  • Improved code review skills

Personal Fulfillment

  • Helping hundreds of developers
  • Learning in public
  • Being part of something bigger
  • Giving back to open source

Advice for First-Time Maintainers

Do This

  1. Write great documentation - It’s how people decide to use your library
  2. Be responsive - Acknowledge issues within 24 hours (even if you can’t fix them immediately)
  3. Welcome contributors - Make them feel appreciated
  4. Release often - Small, frequent releases > big, rare ones
  5. Celebrate milestones - 100 stars, 1000 downloads, etc.

Don’t Do This

  1. Don’t ignore issues - They’ll pile up and overwhelm you
  2. Don’t make breaking changes lightly - They break trust
  3. Don’t merge PRs without review - Quality > speed
  4. Don’t let it burn you out - It’s okay to say “I need a break”
  5. Don’t feel bad saying no - You can’t implement every feature request

Challenges I Still Face

Time Commitment

Maintaining open source takes time:

  • Reviewing PRs: 2-5 hours/week
  • Answering issues: 1-3 hours/week
  • Bug fixes: 3-10 hours/month
  • Major features: 20-40 hours/quarter

This is on top of full-time work. Setting boundaries is important.

Scope Creep

Everyone wants different things:

  • “Add GraphQL support!”
  • “Support weather data from 10 years ago!”
  • “Can you make it work with Objective-C?”

Learning to say no politely is crucial:

“That’s a great idea, but it’s outside the scope of SwiftSky’s core mission. Consider building it as a separate extension!”

The Weight of Responsibility

When 100+ apps depend on your code, breaking things has real consequences. This creates pressure to:

  • Never introduce bugs (impossible)
  • Respond to issues immediately (unsustainable)
  • Maintain perfect backwards compatibility (limiting)

I’ve learned to be kind to myself. Bugs happen. It’s how you handle them that matters.

What’s Next

SwiftSky will continue as long as people find it useful. Upcoming features:

  • GraphQL support
  • More weather providers
  • SwiftUI widgets
  • Vapor integration improvements

But more importantly, I want to mentor new contributors. Help others experience the joy of open source.

Should You Open Source Your Project?

Ask yourself:

  1. Will others find it useful? - Solving your problem probably means others have it too
  2. Can you commit to maintaining it? - At least responding to issues
  3. Are you okay with criticism? - People will judge your code publicly
  4. Do you want to learn in public? - It’s vulnerable but rewarding

If yes, do it. Start small. Ship it. Iterate based on feedback.

The open source community needs more contributors, not perfect code.

Conclusion

Building SwiftSky taught me:

  • Software engineering at scale
  • Community management
  • API design
  • The importance of documentation
  • How to handle criticism
  • The joy of helping others

It opened doors I didn’t know existed and created friendships I treasure.

If you’re thinking about open sourcing a project, do it. Your code doesn’t have to be perfect. Your documentation doesn’t have to be complete. You just have to start.

The best time to open source was when you first had the idea. The second best time is now.


SwiftSky is available on GitHub under the MIT License. Contributions welcome!