megastep/codex-skills

axiom-networking-migration

Network framework migration guides. Use when migrating from BSD sockets to NWConnection, NWConnection to NetworkConnection (iOS 26+), or URLSession StreamTask to NetworkConnection.

First seen Mar 5, 2026

Installation

$ npx skills add megastep/codex-skills --skill axiom-networking-migration

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from megastep/codex-skills · top by installs.

npx skills add megastep/codex-skills

Browse all from megastep/codex-skills

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Not declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Repository health

Stars 5
License MIT
Default branch main
Open issues 0
Status Active

Skill metadata

Parsed from SKILL.md frontmatter.

LicenseMIT

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 8,346 B
  • docs SUMMARY.md 214 B

History

  1. First seen on skills.sh
  2. First recorded snapshot · 8 installs

SKILL.md

Network Framework Migration Guides

Do I Need to Migrate?

What networking API are you using?

├─ URLSession for HTTP/HTTPS REST APIs?
│   └─ Stay with URLSession — it's the RIGHT tool for HTTP
│      URLSession handles caching, cookies, auth challenges,
│      HTTP/2/3, and is heavily optimized for web APIs.
│      Network.framework is for custom protocols, NOT HTTP.
│
├─ BSD Sockets (socket, connect, send, recv)?
│   └─ Migrate to NWConnection (iOS 12+)
│      → See Migration 1 below
│
├─ NWConnection / NWListener?
│   ├─ Need async/await? → Migrate to NetworkConnection (iOS 26+)
│   │   → See Migration 2 below
│   └─ Callback-based code working fine? → Stay (not deprecated)
│
├─ URLSession StreamTask for TCP/TLS?
│   └─ Need UDP or custom protocols? → NetworkConnection
│      Need just TCP/TLS for HTTP? → Stay with URLSession
│      → See Migration 3 below
│
├─ SCNetworkReachability?
│   └─ DEPRECATED — Replace with NWPathMonitor (iOS 12+)
│      let monitor = NWPathMonitor()
│      monitor.pathUpdateHandler = { path in
│          print(path.status == .satisfied ? "Online" : "Offline")
│      }
│
└─ CFSocket / NSStream?
    └─ DEPRECATED — Replace with NWConnection (iOS 12+)
       → See Migration 1 below

Migration 1: From BSD Sockets to NWConnection

Migration mapping

BSD Sockets NWConnection Notes
socket() + connect() NWConnection(host:port:using:) + start() Non-blocking by default
send() / sendto() connection.send(content:completion:) Async, returns immediately
recv() / recvfrom() connection.receive(minimumIncompleteLength:maximumLength:completion:) Async, returns immediately
bind() + listen() NWListener(using:on:) Automatic port binding
accept() listener.newConnectionHandler Callback for each connection
getaddrinfo() Let NWConnection handle DNS Smart resolution with racing
SCNetworkReachability connection.stateUpdateHandler waiting state No race conditions
setsockopt() NWParameters configuration Type-safe options

Example migration

Before (BSD Sockets)

// BEFORE — Blocking, manual DNS, error-prone
var hints = addrinfo()
hints.ai_family = AF_INET
hints.ai_socktype = SOCK_STREAM

var results: UnsafeMutablePointer<addrinfo>?
getaddrinfo("example.com", "443", &hints, &results)

let sock = socket(results.pointee.ai_family, results.pointee.ai_socktype, 0)
connect(sock, results.pointee.ai_addr, results.pointee.ai_addrlen) // BLOCKS

let data = "Hello".data(using: .utf8)!
data.withUnsafeBytes { ptr in
    send(sock, ptr.baseAddress, data.count, 0)
}

After (NWConnection)

// AFTER — Non-blocking, automatic DNS, type-safe
let connection = NWConnection(
    host: NWEndpoint.Host("example.com"),
    port: NWEndpoint.Port(integerLiteral: 443),
    using: .tls
)

connection.stateUpdateHandler = { state in
    if case .ready = state {
        let data = Data("Hello".utf8)
        connection.send(content: data, completion: .contentProcessed { error in
            if let error = error {
                print("Send failed: \(error)")
            }
        })
    }
}

connection.start(queue: .main)

Benefits

  • 20 lines → 10 lines
  • No manual DNS, no blocking, no unsafe pointers
  • Automatic Happy Eyeballs, proxy support, WiFi Assist

Migration 2: From NWConnection to NetworkConnection (iOS 26+)

Why migrate

  • Async/await eliminates callback hell
  • TLV framing and Coder protocol built-in
  • No [weak self] needed (async/await handles cancellation)
  • State monitoring via async sequences

Migration mapping

NWConnection (iOS 12-25) NetworkConnection (iOS 26+) Notes
connection.stateUpdateHandler = { state in } for await state in connection.states { } Async sequence
connection.send(content:completion:) try await connection.send(content) Suspending function
connection.receive(minimumIncompleteLength:maximumLength:completion:) try await connection.receive(exactly:) Suspending function
Manual JSON encode/decode Coder(MyType.self, using: .json) Built-in Codable support
Custom framer TLV { TLS() } Built-in Type-Length-Value
[weak self] everywhere No [weak self] needed Task cancellation automatic

Example migration

Before (NWConnection)

// BEFORE — Completion handlers, manual memory management
let connection = NWConnection(host: "example.com", port: 443, using: .tls)

connection.stateUpdateHandler = { [weak self] state in
    switch state {
    case .ready:
        self?.sendData()
    case .waiting(let error):
        print("Waiting: \(error)")
    case .failed(let error):
        print("Failed: \(error)")
    default:
        break
    }
}

connection.start(queue: .main)

func sendData() {
    let data = Data("Hello".utf8)
    connection.send(content: data, completion: .contentProcessed { [weak self] error in
        if let error = error {
            print("Send error: \(error)")
            return
        }
        self?.receiveData()
    })
}

func receiveData() {
    connection.receive(minimumIncompleteLength: 10, maximumLength: 10) { [weak self] (data, context, isComplete, error) in
        if let error = error {
            print("Receive error: \(error)")
            return
        }
        if let data = data {
            print("Received: \(data)")
        }
    }
}

After (NetworkConnection)

// AFTER — Async/await, automatic memory management
let connection = NetworkConnection(
    to: .hostPort(host: "example.com", port: 443)
) {
    TLS()
}

// Monitor states in background task
Task {
    for await state in connection.states {
        switch state {
        case .preparing:
            print("Connecting...")
        case .ready:
            print("Ready")
        case .waiting(let error):
            print("Waiting: \(error)")
        case .failed(let error):
            print("Failed: \(error)")
        default:
            break
        }
    }
}

// Send and receive with async/await
func sendAndReceive() async throws {
    let data = Data("Hello".utf8)
    try await connection.send(data)

    let received = try await connection.receive(exactly: 10).content
    print("Received: \(received)")
}

Benefits

  • 30 lines → 15 lines
  • No callback nesting, no [weak self]
  • Errors propagate naturally with throws
  • Automatic cancellation on Task exit

Migration 3: From URLSession StreamTask to NetworkConnection

When to migrate

  • Need UDP (StreamTask only supports TCP)
  • Need custom protocols beyond TCP/TLS
  • Need low-level control (packet pacing, ECN, service class)

When to STAY with URLSession

  • Doing HTTP/HTTPS (URLSession optimized for this)
  • Need WebSocket support
  • Need built-in caching, cookie handling

Example migration

Before (URLSession StreamTask)

// BEFORE — URLSession for TCP/TLS stream
let task = URLSession.shared.streamTask(withHostName: "example.com", port: 443)

task.resume()

task.write(Data("Hello".utf8), timeout: 10) { error in
    if let error = error {
        print("Write error: \(error)")
    }
}

task.readData(ofMinLength: 10, maxLength: 10, timeout: 10) { data, atEOF, error in
    if let error = error {
        print("Read error: \(error)")
        return
    }
    if let data = data {
        print("Received: \(data)")
    }
}

After (NetworkConnection)

// AFTER — NetworkConnection for TCP/TLS
let connection = NetworkConnection(
    to: .hostPort(host: "example.com", port: 443)
) {
    TLS()
}

func sendAndReceive() async throws {
    try await connection.send(Data("Hello".utf8))
    let data = try await connection.receive(exactly: 10).content
    print("Received: \(data)")
}

Resources

Skills: axiom-ios-networking, axiom-networking-legacy