SPM: qué es, Swift Package Manager y Package.swift

Autor: IT Sectr Publicado: 2026-02-13 Tiempo de lectura: 11 min

SPM (Swift Package Manager) es un gestor de paquetes integrado en el ecosistema Swift, desarrollado por Apple para automatizar la conexión, compilación y actualización de bibliotecas de terceros. SPM forma parte del compilador Swift desde la versión 3.0 (2016) y no requiere instalación adicional. A diferencia de CocoaPods y Carthage, SPM se integra directamente con el compilador y Xcode, convirtiéndolo en la herramienta estándar de gestión de dependencias en proyectos Swift modernos. En este artículo analizaremos la estructura de Package.swift, los comandos de SPM, la creación de paquetes propios y la migración desde gestores alternativos.

Puntos clave

  • SPM (Swift Package Manager) es un gestor de paquetes integrado en el compilador Swift que no requiere instalación adicional; funciona en iOS, macOS, Linux y plataformas servidor.
  • Package.swift es un archivo manifiesto que describe el nombre del paquete, plataformas, dependencias y módulos objetivo (targets) en formato declarativo.
  • SPM resuelve dependencias mediante versionado semántico (SemVer), guarda en caché el código fuente y compila los paquetes en paralelo para mayor velocidad.
  • Comandos: swift package init (crear paquete), swift package update (actualizar dependencias), swift build (compilar), swift test (ejecutar pruebas).
  • La migración de CocoaPods/Carthage a SPM se realiza mediante Xcode: File → Add Package Dependency, tras lo cual se eliminan el podfile y el Cartfile.

¿Qué es SPM?

SPM (Swift Package Manager) es el gestor de paquetes oficial para el lenguaje Swift, integrado en el compilador swiftc y en el entorno de desarrollo Xcode. Permite a los desarrolladores añadir bibliotecas de terceros, gestionar sus versiones y publicar sus propios paquetes. SPM apareció por primera vez en Swift 3.0 (septiembre de 2016) como herramienta de línea de comandos, y a partir de Xcode 11 (2019) recibió integración completa con la interfaz gráfica — las dependencias se añaden ahora a través del menú File → Add Packages.

SPM descarga automáticamente el código fuente de las dependencias desde repositorios Git, las compila en paralelo con el proyecto principal y guarda en caché los resultados para que las compilaciones posteriores sean más rápidas. A diferencia de CocoaPods, SPM no genera un workspace separado (xcworkspace) — las dependencias pasan a formar parte del proyecto principal de Xcode. Según la encuesta Swift.org Developer Survey (2024), el 67% de los desarrolladores iOS utiliza SPM, lo que lo convierte en la herramienta de gestión de dependencias más popular del ecosistema Swift.

SPM admite tres plataformas: Apple (iOS, macOS, tvOS, watchOS, visionOS), Linux (Ubuntu, CentOS, Amazon Linux) y Swift del lado del servidor (Vapor, Kitura). En Linux, SPM funciona completamente a través de la línea de comandos sin Xcode.

Cómo funciona Swift Package Manager

SPM se basa en tres conceptos clave: paquetes (packages), productos (products) y objetivos (targets). Un paquete es un repositorio Git con un manifiesto Package.swift. Un producto es el resultado de la compilación (una biblioteca o un ejecutable). Un objetivo es un módulo dentro del paquete que se compila como una unidad de compilación.

Cuando un desarrollador añade una dependencia en Package.swift, SPM realiza los siguientes pasos:

  1. Clonación — SPM descarga el repositorio Git de la dependencia desde la URL especificada.
  2. Resolución de versiones — analiza las etiquetas SemVer (por ejemplo, 2.1.3) y selecciona la versión adecuada dentro del rango especificado.
  3. Resolución transitiva — comprueba las dependencias de las dependencias y construye un grafo de versiones sin conflictos.
  4. Caché — guarda el código fuente descargado en ~Library/Caches/org.swift.swiftpm/.
  5. Compilación — compila todos los objetivos del paquete con las banderas del proyecto principal.

El archivo Package.resolved fija las versiones exactas de todas las dependencias para que el equipo de desarrollo trabaje con un conjunto idéntico de bibliotecas. Este archivo debe añadirse al control de versiones (git).

Una ventaja clave de SPM frente a alternativas es la ausencia de un registro centralizado. Los paquetes pueden residir en cualquier repositorio Git público: GitHub, GitLab, Bitbucket, así como en servidores Git privados de la empresa. Desde Swift 5.2, SPM admite dependencias binarias (binary targets) — bibliotecas cerradas distribuidas como XCFramework sin proporcionar código fuente.

Package.swift — manifiesto del proyecto

Package.swift es un archivo Swift que describe la estructura del paquete y sus dependencias. El archivo está escrito en el propio Swift (no en JSON ni YAML), lo que permite usar lógica condicional, constantes calculadas y funciones dentro del manifiesto.

Estructura básica de Package.swift:

swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "MyLibrary",
    platforms: [
        .iOS(.v16),
        .macOS(.v13)
    ],
    products: [
        .library(
            name: "MyLibrary",
            targets: ["MyLibrary"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire.git",
                 from: "5.9.0"),
        .package(url: "https://github.com/onevcat/Kingfisher.git",
                 from: "7.12.0"),
    ],
    targets: [
        .target(
            name: "MyLibrary",
            dependencies: [
                "Alamofire",
                "Kingfisher"
            ]
        ),
        .testTarget(
            name: "MyLibraryTests",
            dependencies: ["MyLibrary"]
        ),
    ]
)

Analicemos los elementos clave:

  • // swift-tools-version: 5.9 — directiva que especifica la versión de SPM; de ella depende la sintaxis disponible del manifiesto.
  • name — nombre del paquete, que se muestra en Xcode y se utiliza en los enlaces de dependencias.
  • platforms — versiones mínimas de las plataformas; SPM no permitirá compilar el paquete en una versión de SO más antigua.
  • products — lo que "exporta" el paquete: una biblioteca (.library) o un ejecutable (.executable).
  • dependencies — lista de paquetes externos con URL y versión; admite from:, exact:, branch:, revision:.
  • targets — objetivos de compilación; cada objetivo contiene una lista de dependencias, recursos y archivos swift del directorio correspondiente (Sources/TargetName/).

Ejemplo de especificación de versión exacta, rama y commit:

swift
dependencies: [
    .package(url: "https://github.com/pointfreeco/swift-snapshot-testing.git",
             exact: "1.17.3"),
    .package(url: "https://github.com/pointfreeco/swift-composable-architecture.git",
             branch: "main"),
    .package(url: "https://github.com/apple/swift-log.git",
             revision: "e5c6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4"),
]

Desde Swift 5.9, Package.swift ha añadido soporte para static framework y linkerSettings, lo que permite una configuración más precisa del enlazador para bibliotecas estáticas y dinámicas.

Comandos básicos de SPM

Swift Package Manager proporciona un conjunto de comandos para trabajar desde la terminal. Los comandos se ejecutan desde el directorio raíz del paquete (donde se encuentra Package.swift).

bash
# Crear un nuevo paquete con una biblioteca
swift package init --type library

# Crear un paquete ejecutable (aplicación de consola)
swift package init --type executable

# Compilar el proyecto
swift build

# Compilar en configuración de lanzamiento
swift build -c release

# Ejecutar pruebas
swift test

# Ejecutar una prueba específica
swift test --filter "MyLibraryTests/testExample"

# Descargar y resolver dependencias
swift package resolve

# Actualizar dependencias a las últimas versiones disponibles
swift package update

# Mostrar el grafo de dependencias
swift package show-dependencies

# Limpiar la caché de compilación
swift package clean

# Generar proyecto de Xcode (antes de Xcode 11)
swift package generate-xcodeproj

Al trabajar dentro de Xcode, la mayoría de estos comandos se ejecutan automáticamente: las dependencias se resuelven al abrir el proyecto, la compilación se inicia con ⌘B, las pruebas con ⌘U. Sin embargo, conocer los comandos de terminal es necesario para los pipelines de CI/CD (GitHub Actions, GitLab CI, Jenkins) donde Xcode no está disponible.

El comando swift package resolve crea o actualiza el archivo Package.resolved. Este archivo fija las versiones exactas de todas las dependencias, incluidas las transitivas, y debe añadirse a git. Se recomienda ejecutar swift package update antes de cada nueva rama de funcionalidad para trabajar con versiones actualizadas de las bibliotecas.

Creación de tu propio paquete

Crear tu propio paquete SPM es útil para encapsular lógica de negocio en proyectos multimódulo y para publicar bibliotecas de código abierto. Veamos el proceso paso a paso.

Paso 1: Inicialización

bash
mkdir MyNetworkKit
cd MyNetworkKit
swift package init --type library

Paso 2: Estructura de directorios

El comando swift package init crea la siguiente estructura:

text
MyNetworkKit/
├── Package.swift
├── README.md
├── Sources/
│   └── MyNetworkKit/
│       └── MyNetworkKit.swift
└── Tests/
    └── MyNetworkKitTests/
        └── MyNetworkKitTests.swift

SPM escanea automáticamente los directorios Sources/ y Tests/: cada subdirectorio dentro de Sources corresponde a un objetivo (target).

Paso 3: Editar Package.swift

Añadamos dependencias y configuremos las plataformas objetivo:

swift
// swift-tools-version: 5.9
import PackageDescription

let package = Package(
    name: "MyNetworkKit",
    platforms: [
        .iOS(.v15),
        .macOS(.v12)
    ],
    products: [
        .library(
            name: "MyNetworkKit",
            targets: ["MyNetworkKit"]
        ),
    ],
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire.git",
                 from: "5.9.0"),
    ],
    targets: [
        .target(
            name: "MyNetworkKit",
            dependencies: ["Alamofire"]
        ),
        .testTarget(
            name: "MyNetworkKitTests",
            dependencies: ["MyNetworkKit"]
        ),
    ]
)

Paso 4: Escribir código

swift
// Sources/MyNetworkKit/MyNetworkKit.swift
import Foundation
import Alamofire

public struct NetworkClient {
    private let session: Session

    public init() {
        let configuration = URLSessionConfiguration.default
        configuration.timeoutIntervalForRequest = 30
        self.session = Session(configuration: configuration)
    }

    public func fetchData(from url: String) async throws -> Data {
        let response = try await session.request(url).serializingData().value
        return response
    }
}

Paso 5: Publicación

Sube el paquete a un repositorio Git y crea una etiqueta SemVer:

bash
git init
git add .
git commit -m "Initial commit: MyNetworkKit"
git remote add origin https://github.com/username/MyNetworkKit.git
git push -u origin main
git tag 1.0.0
git push --tags

Después de esto, cualquier desarrollador podrá añadir tu paquete mediante .package(url: "https://github.com/username/MyNetworkKit.git", from: "1.0.0").

Ejemplos de uso de SPM

Ejemplo 1: Añadir Alamofire para peticiones de red

Alamofire es el cliente HTTP más popular para Swift. Añadámoslo mediante SPM y realicemos una petición GET.

swift
import Alamofire

func fetchUsers() {
    AF.request("https://jsonplaceholder.typicode.com/users")
        .validate()
        .responseDecodable(of: [User].self) { response in
            switch response.result {
            case .success(let users):
                print("Recibidos (users.count) usuarios")
            case .failure(let error):
                print("Error: (error.localizedDescription)")
            }
        }
}

Ejemplo 2: Swinject — inyección de dependencias

La biblioteca Swinject proporciona un contenedor DI para Swift. Se añade mediante .package(url: "https://github.com/Swinject/Swinject.git", from: "2.8.0").

swift
import Swinject

let container = Container()
container.register(NetworkServiceProtocol.self) { _ in NetworkService() }
container.register(DataRepositoryProtocol.self) { r in
    DataRepository(networkService: r.resolve(NetworkServiceProtocol.self)!)
}

let repository = container.resolve(DataRepositoryProtocol.self)
repository?.loadData()

Ejemplo 3: Swift-log para registro estructurado

El paquete swift-log de Apple proporciona una API de registro unificada que admite múltiples backend (OSLog, consola, archivos).

swift
import Logging

var logger = Logger(label: "com.myapp.network")
logger.logLevel = .debug

logger.info("Petición de red iniciada", metadata: [
    "url": "(requestURL)",
    "method": "GET"
])

logger.warning("El tiempo de respuesta superó los 2 segundos")
logger.error("Error de conexión: sin internet")

Estos tres ejemplos cubren escenarios típicos de uso de SPM: clientes HTTP, contenedores DI e infraestructura de sistema. La selección de bibliotecas no es casual — Alamofire, Swinject y swift-log están entre los 20 paquetes Swift con más estrellas en GitHub.

Migración desde CocoaPods y Carthage

Si tu proyecto utiliza CocoaPods o Carthage, la migración a SPM se realiza en unos pocos pasos. El proceso es seguro: las dependencias de SPM pueden coexistir con CocoaPods y Carthage en el mismo proyecto, lo que permite una migración gradual.

CocoaPods → SPM

  1. En Xcode: File → Add Package Dependency, introduce la URL del paquete.
  2. Selecciona la versión y añade el paquete a los targets necesarios.
  3. Tras añadir todas las dependencias mediante SPM, elimina las líneas del Podfile.
  4. Elimina el .xcworkspace, abre el .xcodeproj y realiza Clean Build Folder.

Carthage → SPM

  1. Añade los paquetes mediante Xcode File → Add Package Dependency.
  2. Elimina las dependencias del Cartfile.
  3. Elimina los scripts de compilación de Carthage de Build Phases.
  4. Limpia la caché: rm -rf Carthage/ en la terminal.

A fecha de 2025, SPM admite la gran mayoría de las bibliotecas Swift populares. Las excepciones son algunos frameworks ObjC sin mapas de módulos. Si una biblioteca aún no es compatible con SPM, consulta la sección Installation en su README; la mayoría de los autores ya han añadido soporte para SPM en las últimas versiones.

Preguntas frecuentes

¿En qué se diferencia SPM de CocoaPods y Carthage?

SPM está integrado en el compilador Swift y Xcode, no requiere instalación mediante gem ni Homebrew. CocoaPods utiliza un registro centralizado Specs y genera un workspace separado. Carthage funciona mediante frameworks sin integrarse con el proyecto. SPM es el único gestor integrado a nivel de compilador: las dependencias se resuelven, almacenan en caché y compilan en paralelo con el código principal.

¿Se puede usar SPM para proyectos Objective-C?

Sí, SPM admite proyectos mixtos Swift + Objective-C. Los archivos ObjC dentro de un paquete SPM se incluyen automáticamente en un Umbrella Header si existe un modulemap correcto. Sin embargo, SPM no admite bibliotecas estáticas de ObjC que carezcan de un mapa de módulos. Se recomienda conectar bibliotecas ObjC mediante SPM solo si proporcionan un modulemap o están escritas en C puro.

¿Cómo resuelve SPM los conflictos de versiones?

SPM utiliza versionado semántico (SemVer). Si el paquete A requiere Alamofire 5.8+ y el paquete B requiere Alamofire 5.9+, SPM seleccionará la versión 5.9.x que satisface ambos. Si el conflicto no se puede resolver (un paquete requiere 5.x, otro requiere 6.x), SPM informará de un error. En ese caso, debes actualizar uno de los paquetes o cambiar la dependencia a una versión compatible con ambos requisitos.

¿Dónde se almacenan los paquetes SPM descargados?

En macOS: ~Library/Caches/org.swift.swiftpm/ y ~/Library/Developer/Xcode/DerivedData/. En Linux: ~cache/swiftpm/. Durante las compilaciones, SPM guarda en caché el código fuente y los archivos objeto compilados. Para limpiar completamente la caché, ejecuta swift package reset — este comando elimina la caché de dependencias y DerivedData del proyecto actual.

¿Admite SPM bibliotecas cerradas (propietarias)?

Sí, desde Swift 5.2 SPM admite objetivos binarios (binary targets). Una biblioteca cerrada se distribuye como XCFramework y la ruta al .xcframework se especifica en Package.swift. El código fuente no se expone. Un target binario se especifica mediante .binaryTarget(name: "PrivateSDK", path: "Sources/PrivateSDK.xcframework"). Esto permite conectar SDK comerciales sin violar acuerdos de licencia.

Resumen

  • SPM (Swift Package Manager) es un gestor de paquetes integrado en Swift que no requiere instalación adicional y está integrado con Xcode y el compilador.
  • Package.swift es un manifiesto declarativo escrito en Swift que describe el nombre del paquete, plataformas, dependencias, productos y objetivos de compilación.
  • SPM utiliza repositorios Git como fuente de paquetes y resuelve versiones mediante SemVer, almacenando en caché el código fuente para compilaciones posteriores más rápidas.
  • Comandos principales: swift package init (crear paquete), swift build (compilar), swift test (probar), swift package update (actualizar dependencias).
  • Un paquete personalizado se crea mediante swift package init, se publica en Git y está disponible para otros proyectos mediante URL con etiqueta SemVer.
  • La migración de CocoaPods/Carthage a SPM es segura: las dependencias pueden coexistir, la migración se realiza mediante File → Add Package Dependency en Xcode.
  • SPM es la herramienta estándar de gestión de dependencias en el ecosistema Swift, utilizada por el 67% de los desarrolladores iOS (Swift.org Developer Survey, 2024).

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también