Skip to main content
v2.0 is the Swift 6 and iOS 26 Liquid Glass release. It changes the toolchain floor, ships a new Liquid Glass primitive, and splits oversized files into ≤ 400-line extension siblings. Most downstream apps upgrade in under an hour.
Canonical release notes: RELEASE_NOTES.md in the boilerplate repo. This guide is the step-by-step version.

1. Toolchain

v2.0 uses iOS 26 SDK symbols (Glass, glassEffect, GlassEffectContainer) that older toolchains cannot compile, regardless of #available checks. Required:
  • macOS 15+
  • Xcode 26.2+ (Swift 6.0)
  • iOS 17+ runtime (unchanged)
The repo pins 26.3 via .xcode-version. If you use xcodes or asdf-xcode, run xcodes install (or asdf install xcode) inside the repo to match.
Stuck on older Xcode? Pin your build to v1.9.0 until you can upgrade. There is no forward-compatible fallback; the iOS 26 SDK is required to compile.

2. Apply the Supabase migration

v2.0 ships a new SQL migration that fixes a permissions gap on the conversation-stats trigger.
# From the repo root
supabase migration up
Or run the file directly:
psql "$SUPABASE_DB_URL" \
  -f supabase/migrations/20260408000000_fix_conversation_stats_auth.sql

3. Redeploy the ai edge function

The Edge Function was updated alongside the migration. Redeploy it so the new version picks up the fix:
supabase functions deploy ai

4. Install the secrets pre-commit hook

v2.0 ships a pre-commit hook that blocks accidental secret commits (the hook lives in .githooks/). Enable it once per clone:
git config core.hooksPath .githooks
This is a one-time, per-clone setting. It is not picked up automatically.

5. Reapply downstream customisations

A lot of oversized files were split into extension siblings to stay under the new ≤ 400-line rule. Public entry points are unchanged, but if you customised any of these files, your edits may now belong in a subview or sibling file.
Touched in v1.9Where the content lives now
ProfileView.swiftViews/Profile/*.swift (composition root + section files)
SettingsView.swiftViews/Settings/*.swift (≤ 125-line root + one file per section)
EmailSignUpView.swiftViews/Auth/EmailSignUp*.swift
SessionManager.swift+SignIn, +Refresh, +Persistence extensions
L10n.swiftL10n+<Namespace>.swift per nested enum
ChatViewModel.swiftChatViewModel+Memory.swift for history/memory
Strategy: git log the file, find the function you edited, grep for it in the new tree, port the change.

6. Fighting-glass cleanup

This is the biggest source of visual regressions when upgrading. On iOS 26, SwiftUI handles sheet and container materials for you. If your downstream code piles manual backgrounds on top, you block the Material SwiftUI already provides and you fight Liquid Glass on iOS 26. Remove these patterns from your own views:
  • .background(DSColors.background) on SwiftUI containers (NavigationStack, Form, List, sheets, TabView).
  • DSColors.background.ignoresSafeArea() stacked under sheets or full-screen covers.
  • .background(.black) or .background(Color.clear) under .presentationBackground on sheets.
  • .scrollContentBackground(.hidden) on forms that already use .formStyle(.grouped). .grouped already does the right thing on iOS 26.
  • Explicit .safeAreaInset(edge: .bottom) gutters under a TabView. The tab bar’s own inset is already respected.
Use instead:
  • .saiGlass(.regular) when you need glass on a custom view.
  • SAIGlassContainer { ... } when multiple glass surfaces sit near each other.
  • .saiScrollEdgeGlass(_:) for scroll-edge treatment under nav and input chrome.
  • .saiTabBarMinimize(.onScrollDown) if you want iOS 26 tab bar minimisation (it is a no-op on iOS 17–25).

7. Paywall CTA theming

Paywall CTAs in v2.0 use the standard system styles:
Button("Upgrade") { ... }
    .buttonStyle(.borderedProminent)

Button("Maybe later") { ... }
    .buttonStyle(.bordered)
If you were theming these buttons via .background(), switch to .tint():
// Before (v1.9)
Button("Upgrade") { ... }
    .background(BrandConfig.accentColor)

// After (v2.0)
Button("Upgrade") { ... }
    .buttonStyle(.borderedProminent)
    .tint(BrandConfig.accentColor)
.tint() lets the standard button style render the glass-aware surface correctly on iOS 26, and still picks up the correct Material on iOS 17–25.

Quick verification checklist

After the upgrade, run through this list before shipping:
  • App builds under Xcode 26.2+ with zero Swift 6 warnings.
  • Supabase migration ran cleanly (supabase migration list shows 20260408000000_fix_conversation_stats_auth).
  • The ai Edge Function returns a streaming response end-to-end.
  • git config core.hooksPath returns .githooks.
  • Sheets, paywall, settings, and chat all look right on iOS 26 (Liquid Glass) and iOS 17–18 (Material fallback).
  • No remaining .onReceive(...) on ToastCenter or DeepLinkBus in downstream code; migrate to .onChange(of:).
  • No remaining .background(DSColors.background.ignoresSafeArea()) under containers.

Changelog

Full v2.0.0 release entry

Liquid Glass API

SAIGlass, modifiers, container

Architecture

Swift 6 concurrency model + ≤ 400-line rule

Troubleshooting

Common upgrade errors and fixes