SwiftUI Multi-Tenant Architecture (Accounts, Workspaces, Isolation)

# swiftui# architecture# multitenant# accounts
SwiftUI Multi-Tenant Architecture (Accounts, Workspaces, Isolation)Sebastien Lato

Single-user apps are simple. But real products eventually need: multiple accounts team...

Single-user apps are simple.

But real products eventually need:

  • multiple accounts
  • team workspaces
  • organization switching
  • sandbox vs production data
  • different permission scopes

Without proper architecture, this leads to:

  • mixed user data
  • cache corruption
  • wrong account actions
  • impossible bug reports
  • “why is this showing someone else’s data?”

This post shows how to design a multi-tenant architecture in SwiftUI that:

  • isolates user data
  • supports account switching
  • prevents cross-tenant bugs
  • scales to teams and organizations

🧠 The Core Principle

Every piece of data must belong to a tenant.

If you don’t know which account owns a piece of state, your architecture is already unsafe.


🧱 1. Define the Tenant Model

A tenant represents a data boundary.

struct Tenant {
    let id: UUID
    let name: String
    let role: Role
}

enum Role {
    case personal
    case member
    case admin
}
Enter fullscreen mode Exit fullscreen mode

This could represent:

  • a user account
  • a workspace
  • an organization
  • a project context

🧬 2. Tenant-Aware App State

Never store global user data.

Bad:

class AppState {
    var user: User
    var projects: [Project]
}
Enter fullscreen mode Exit fullscreen mode

Correct:

class AppState {
    var activeTenant: Tenant
    var tenantStores: [UUID: TenantStore]
}
Enter fullscreen mode Exit fullscreen mode

Each tenant has its own isolated state.


📦 3. Tenant Store

final class TenantStore: ObservableObject {
    @Published var user: User
    @Published var projects: [Project]
    @Published var settings: TenantSettings
}
Enter fullscreen mode Exit fullscreen mode

This ensures:

  • no cross-tenant leaks
  • clean switching
  • independent lifecycles

🔁 4. Account Switching Architecture

Switching tenants should:

  1. Save current state
  2. Tear down feature stores
  3. Activate new tenant store
  4. Rebuild navigation

Example:

func switchTenant(to tenant: Tenant) {
    activeTenant = tenant
    currentStore = tenantStores[tenant.id]
}
Enter fullscreen mode Exit fullscreen mode

Never reuse old state across tenants.


🧭 5. Tenant-Scoped Services

Services must be tenant-aware.

Bad:

apiClient.fetchProjects()
Enter fullscreen mode Exit fullscreen mode

Correct:

apiClient.fetchProjects(for: tenantID)
Enter fullscreen mode Exit fullscreen mode

Or inject a tenant-scoped client:

TenantAPIClient(tenantID: tenant.id)
Enter fullscreen mode Exit fullscreen mode

Every request must carry tenant context.


🧠 6. Storage Isolation

Persist data per tenant:

/Storage
  /tenant_1
    projects.db
  /tenant_2
    projects.db
Enter fullscreen mode Exit fullscreen mode

Or use namespaced keys:

"tenant_\(id)_settings"
Enter fullscreen mode Exit fullscreen mode

Never share storage across tenants.


🧪 7. Testing Multi-Tenant Flows

You must test:

  • switching accounts
  • logging out and back in
  • background sync per tenant
  • cross-tenant isolation
  • permission differences

Multi-tenant bugs are subtle and dangerous.


🔐 8. Permission & Role Awareness

Tenants may have different roles.

Example:

if tenant.role == .admin {
    showAdminPanel()
}
Enter fullscreen mode Exit fullscreen mode

Never assume capabilities across tenants.


⚠️ 9. Common Multi-Tenant Anti-Patterns

Avoid:

  • global singletons for user data
  • shared caches across tenants
  • not clearing state on switch
  • hardcoded user assumptions
  • mixing personal and workspace data

These cause the worst production bugs.


🧠 Mental Model

Think:

Tenant
 → Tenant Store
   → Tenant Services
     → Tenant Storage
       → Tenant UI
Enter fullscreen mode Exit fullscreen mode

Not:

“There’s just one user”


🚀 Final Thoughts

A proper multi-tenant architecture gives you:

  • safe account switching
  • clean workspace logic
  • better permission handling
  • fewer data leaks
  • scalable product design

If your app ever needs teams or organizations,
multi-tenant architecture is not optional.