@_exported import in Swift

Hi Switers :), Today, we are going to explore a handy little feature in Swift. Lets say you are packing for a vacation but instead of packing just for yourself, you decide to pack extra clothes and snacks in case your friend forgets theirs. Generous, right? Well in Swift there’s a feature that does something kind of like that for imports. Its called the @_exported import its a powerful tool to help make your code more modular and DRY.

The Problem: Repeating Yourself with Imports

Let’s say you’re building a Swift module or an internal framework. And inside this framework, you’re using a dependency like Alamofire or UIKit. Now imagine that you have multiple files importing your framework

Swift
import MyNetworkingLib
import Alamofire // still need this manually

Even though MyNetworkingLib uses Alamofire under the hood, your app code still needs to manually import Alamofire if it wants to use any of its symbols. Thats kind of annoying, right? It’s like bringing your own fork to a restaurant even though they clearly use forks inside 😀

So What Is @_exported import?

The @_exported import declaration tells Swift:

“Hey, not only am I using this module I want to re-export it too. So anything that imports me also gets this one, automatically.”

Think of it like:

  • Normal import: You’re keeping it to yourself.
  • @_exported import: You’re sharing it with everyone who uses you.

Basic Syntax

Swift
@_exported import Alamofire

Now, anywhere that imports your module will also implicitly get Alamofire. No need to import it separately. Lets take a look at real world example, let’s say you are building a Swift package called MyNetworkingLib. You are using Alamofire inside it.

Before: Without Exporting

Swift
// In MyNetworkingLib.swift
import Alamofire

public func makeRequest() {
    AF.request("https://thepenguin.tech")
}

Then, in your app:

Swift
import MyNetworkingLib
import Alamofire // required if you want to use `AF` directly

Even though you use AF inside your library, anyone using your library still has to import Alamofire directly. Kind of defeats the purpose of abstraction.

After: With @_exported import

Swift
// In MyNetworkingLib.swift
@_exported import Alamofire

public func makeRequest() {
    AF.request("https://thepenguin.tech")
}

Now, in your app:

Swift
import MyNetworkingLib

AF.request("https://another.com") // ✅ works!

No need to import Alamofire again because it’s exported through your library!

So Where Is This Actually Useful

  • Frameworks that wrap or depend heavily on other libraries
  • Modules that compose multiple smaller modules into one
  • Internal SDKs where you want to simplify your public API
  • Avoiding repeated imports across multiple files

But Wait, Why Is It Underscored?

You might’ve noticed: it’s @_exported import, not @exported import. That underscore means it’s a compiler attribute and technically not officially public API. It’s available and works well, but Apple might reserve the right to change or formalize it in the future. That said, it’s been around for years and is widely used in real projects (especially internal frameworks and packages). So it’s considered stable enough for practical use but don’t be surprised if it evolves into a cleaner exported import someday.

Be Careful With Overexposure

While this tool is powerful, don’t get too export happy. You don’t want to leak every dependency your library uses. Ask yourself this:

  • Do consumers need direct access to this module?
  • Or can they just use your public API without knowing what’s underneath?

Only export what you want others to rely on directly.


Posted

in

Tags: