NewThe Flutter Kit — Flutter boilerplate$149$69
Tutorial · SwiftUI + SwiftData · 7 Days to Ship

How to Build a Habit Tracker App with SwiftUI (2026)

Production-grade guide. SwiftData persistence, streak logic, calendar heatmap, push notification reminders, RevenueCat paywall.

Last updated: 2026-05-16 14 min read By Ahmed Gagan, iOS Engineer
Quick Answer

To build a habit tracker iOS app with SwiftUI in 2026: (1) model habits + completions as SwiftData @Models, (2) compute streaks from completion dates rather than storing them, (3) schedule UNCalendarNotificationTrigger reminders per habit, (4) gate unlimited habits + themes via RevenueCat paywall, (5) ship in 4–7 days with The Swift Kit. The full architecture, schema, and Swift code is below.

Time to ship
4–7 days with boilerplate
Stack
SwiftUI + SwiftData + RevenueCat + UNUserNotificationCenter
iOS target
iOS 17+
Pricing model
$4.99/mo or $29.99/yr freemium

Ship your habit tracker this week.

The Swift Kit ships everything except the habit logic — design system, paywall, push notifications, all pre-wired.

Get The Swift Kit — $99

The 7 Steps to Ship

Each step takes 4–8 hours with the Swift Kit. From scratch, double-to-triple that.

  1. 1

    Step 1 — Project setup

    Clone Swift Kit, run setup.sh, pick "Productivity" preset.

    git clone <swift-kit-repo> MyHabitApp
    cd MyHabitApp
    ./setup.sh
  2. 2

    Step 2 — Model habits + completions in SwiftData

    Habit owns a list of HabitCompletion records. Completion has a date (normalized to midnight). Use a @Model for native SwiftUI integration.

    import SwiftData
    
    @Model
    final class Habit {
      var name: String
      var emoji: String
      var colorHex: String
      var reminderTime: Date?
      @Relationship(deleteRule: .cascade) var completions: [HabitCompletion] = []
      var createdAt: Date
    
      init(name: String, emoji: String, colorHex: String) {
        self.name = name
        self.emoji = emoji
        self.colorHex = colorHex
        self.createdAt = .now
      }
    }
    
    @Model
    final class HabitCompletion {
      var date: Date  // midnight in user timezone
      var habit: Habit?
    }
  3. 3

    Step 3 — Compute streaks (don't store them)

    Walk backward from today, counting consecutive completed days. Computing on read is cheap and avoids stale-data bugs.

    extension Habit {
      var currentStreak: Int {
        let dates = Set(completions.map { Calendar.current.startOfDay(for: $0.date) })
        var streak = 0
        var day = Calendar.current.startOfDay(for: .now)
        while dates.contains(day) {
          streak += 1
          day = Calendar.current.date(byAdding: .day, value: -1, to: day)!
        }
        return streak
      }
    }
  4. 4

    Step 4 — Build the habit list + completion toggle

    List of habits with a tap-to-complete circle. Toggling adds or removes today's HabitCompletion. Haptic + animation on complete.

    List {
      ForEach(habits) { habit in
        HStack {
          Text(habit.emoji).font(.title)
          VStack(alignment: .leading) {
            Text(habit.name).font(.headline)
            Text("\(habit.currentStreak) day streak").font(.caption).foregroundStyle(.secondary)
          }
          Spacer()
          Button { toggle(habit) } label: {
            Image(systemName: isCompletedToday(habit) ? "checkmark.circle.fill" : "circle")
              .font(.title)
          }
        }
      }
    }
  5. 5

    Step 5 — Calendar heatmap view

    GitHub-style calendar heat map showing last 90 days. Use LazyVGrid with 7 columns. Color intensity scales with completion.

    LazyVGrid(columns: Array(repeating: .init(.fixed(20)), count: 7), spacing: 4) {
      ForEach(last90Days, id: \.self) { day in
        RoundedRectangle(cornerRadius: 4)
          .fill(color(for: day, habit: habit))
          .frame(height: 20)
      }
    }
  6. 6

    Step 6 — Schedule push notification reminders

    For each habit with a reminder time, schedule a daily UNCalendarNotificationTrigger. Cap at 64 (Apple's limit on pending notifications). Cancel today's when user marks complete.

    func scheduleReminder(for habit: Habit) async throws {
      guard let time = habit.reminderTime else { return }
      let center = UNUserNotificationCenter.current()
    
      let content = UNMutableNotificationContent()
      content.title = habit.emoji + " " + habit.name
      content.body = "Time to log your habit"
      content.sound = .default
    
      let trigger = UNCalendarNotificationTrigger(
        dateMatching: Calendar.current.dateComponents([.hour, .minute], from: time),
        repeats: true
      )
      let request = UNNotificationRequest(identifier: habit.id.uuidString, content: content, trigger: trigger)
      try await center.add(request)
    }
  7. 7

    Step 7 — Paywall gating + ship

    Free tier: 3 habits, basic theme. Premium: unlimited habits, all themes, widget customization, CSV export. RevenueCat handles the rest. Ship with included App Store assets.

    if !subscription.isPremium && habits.count >= 3 { showPaywall = true; return }

Frequently Asked Questions

How long does it take to build a habit tracker app with SwiftUI?
With a SwiftUI boilerplate: 4–7 days for a polished MVP. From scratch: 3–5 weeks. The visible features (streak calendar, completion ring, push notifications) are quick. The invisible glue (paywall, subscription state, push registration, analytics, App Store assets) is what eats time.
Should I use SwiftData or Core Data for habit tracker storage?
SwiftData if iOS 17+ is acceptable. The model is simpler and SwiftUI integration is native via @Query. Core Data is fine if you need iOS 16 support or CloudKit sync with mature migration tooling. For a new habit tracker in 2026, default to SwiftData.
How do I implement streaks in SwiftUI?
Store completion dates as a Set<Date> (normalized to midnight in user's timezone). Compute current streak by walking backward from today; longest streak by scanning the set. Don't store streak as a denormalized field — recompute on read; it's fast for any reasonable history.
How do I schedule habit reminder push notifications?
Use UNUserNotificationCenter with repeating UNCalendarNotificationTrigger. Schedule one notification per habit-time combo, capped at 64 pending notifications per app (Apple's limit). When user marks complete, cancel today's notification.
What pricing model works for habit tracker apps?
Freemium with 1-3 habits free and unlimited via subscription ($4.99/mo, $29.99/yr, or $49.99 lifetime). Streaks, themes, widget customization, and CSV export are common premium gates. Many top habit trackers add iCloud sync as a premium gate.
Does The Swift Kit help with habit tracker apps?
Yes. The Swift Kit ships everything except habit-specific UI: design system, paywall, auth, onboarding, push notification scaffolding, analytics, SwiftData primitives. You build the habit logic + calendar UI on top. Realistic MVP timeline: 5–7 days.

Keep exploring

Ship your iOS app 10× faster

The Swift Kit gives you a production-ready SwiftUI boilerplate — design system, paywall, auth, AI, all pre-wired. $99 one-time.

Get The Swift Kit — $99

One-time purchase · Lifetime updates · 14-day refund