A minimal iOS 26 starter project demonstrating Supabase integration with SwiftUI — no authentication required. Build a fully functional news app with image uploads in minutes.
Perfect for beginners who want to learn how to connect a SwiftUI app to a real backend using Supabase for CRUD operations and file storage.
This is a simple two-tab iOS app:
News Tab — A list of articles fetched from Supabase. Each article has a title, an image, and a creation date. You can add new articles with photos from your library, pull to refresh, and swipe to delete.
Profile Tab — A profile editor where you can set your first name, last name, and upload an avatar photo. Everything is saved to Supabase.
All images (article photos and avatar) are uploaded to Supabase Storage and stored as public URLs in the database.
There is no authentication. This is intentional — the project is designed as a learning tool and starting point, not a production app.
- SwiftUI — iOS 26+ with modern APIs (async/await, PhotosPicker, AsyncImage, ContentUnavailableView)
- Supabase — Backend-as-a-Service (PostgreSQL database + object storage)
- Supabase Swift SDK — Official Swift client for Supabase
The only external dependency is the official Supabase Swift SDK:
https://github.com/supabase/supabase-swift
Select the Supabase library when adding the package.
supabase-swiftui-starter/
├── SupabaseStarterApp.swift → App entry point (@main)
├── SupabaseManager.swift → Supabase client singleton (add your credentials here)
├── Models.swift → Codable data models (Article, Profile)
├── ContentView.swift → Main TabView (News + Profile)
├── ArticleListView.swift → Fetches, displays, and deletes articles
├── ArticleRowView.swift → Single article row (image + title + date)
├── AddArticleView.swift → Form to create a new article with image upload
├── ProfileView.swift → Profile editor with avatar upload
├── setup.sql → SQL queries to set up your Supabase database
└── README.md
If you've never used Supabase before, follow every step below. If you already have an account, skip to Step 2.
- Go to supabase.com
- Click Start your project and sign up with GitHub or email
- Once logged in, you'll land on the Supabase Dashboard
- Click New Project
- Choose your organization (or create one)
- Set a project name (e.g.
swiftui-starter) - Set a database password (save it somewhere — you won't need it in the app but you'll need it for direct DB access)
- Choose a region close to you
- Click Create new project and wait for it to finish provisioning (about 1-2 minutes)
- In the left sidebar, go to Settings (gear icon at the bottom)
- Click API under Configuration
- Copy these two values — you'll need them later:
- Project URL — looks like
https://abcdefg.supabase.co - anon public key — a long string starting with
eyJ...
- Project URL — looks like
- In the left sidebar, click SQL Editor
- Click New query
- Paste the following SQL and click Run:
-- ============================================
-- supabase-swiftui-starter — Database Setup
-- ============================================
-- Articles table
CREATE TABLE articles (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
title TEXT NOT NULL,
image_url TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Profile table (single row, no authentication)
CREATE TABLE profile (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
first_name TEXT NOT NULL DEFAULT '',
last_name TEXT NOT NULL DEFAULT '',
avatar_url TEXT
);
-- Insert a default empty profile
INSERT INTO profile (first_name, last_name) VALUES ('', '');- You should see Success. No rows returned — that's correct
- Now run a second query to set up the security policies:
-- ============================================
-- Row Level Security — Allow All (No Auth)
-- ============================================
ALTER TABLE articles ENABLE ROW LEVEL SECURITY;
ALTER TABLE profile ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Allow all on articles" ON articles
FOR ALL USING (true) WITH CHECK (true);
CREATE POLICY "Allow all on profile" ON profile
FOR ALL USING (true) WITH CHECK (true);This enables Row Level Security but allows all operations without requiring authentication. This is fine for learning, but in production you should use proper auth-based policies.
- In the left sidebar, click Storage
- Click New bucket
- Create the first bucket:
- Name:
article-images - Toggle Public bucket to ON
- Click Create bucket
- Name:
- Create the second bucket:
- Name:
avatars - Toggle Public bucket to ON
- Click Create bucket
- Name:
For each bucket, you need to allow uploads and downloads without authentication.
For the article-images bucket:
- Click on
article-imagesin the Storage sidebar - Click the Policies tab (or go to Configuration → Policies)
- Click New policy
- Select For full customization
- Set:
- Policy name:
Allow all - Allowed operations: check SELECT, INSERT, DELETE
- Target roles: leave default
- USING expression:
true - WITH CHECK expression:
true
- Policy name:
- Click Review then Save policy
Repeat the exact same steps for the avatars bucket.
Your Supabase backend is now ready.
-
Clone this repo:
git clone https://github.com/user/supabase-swiftui-starter.git
-
Open the project in Xcode 26+
-
Add the Supabase Swift SDK:
- Go to File → Add Package Dependencies
- Enter:
https://github.com/supabase/supabase-swift - Click Add Package
- Select the Supabase library and click Add Package
-
Open
SupabaseManager.swiftand replace the placeholders:private static let projectURL = URL(string: "https://YOUR_PROJECT_ID.supabase.co")! private static let anonKey = "YOUR_ANON_KEY_HERE"
-
Build and run on a simulator or device (iOS 26+)
- Database — The app reads and writes to PostgreSQL tables (
articles,profile) using the Supabase Swift SDK's query builder with async/await. - Storage — Images are compressed to JPEG, uploaded to Supabase Storage buckets, and their public URLs are saved in the database. The app uses
AsyncImageto load them. - No Auth — RLS is enabled with permissive policies. All operations are allowed without a logged-in user. This keeps the code simple and focused on learning Supabase basics.
When you're ready to add authentication:
- Enable an auth provider in Supabase Dashboard (Email, Google, Apple, etc.)
- Use
SupabaseManager.client.auth.signIn()and.signUp()in your app - Replace the RLS policies to use
auth.uid()instead oftrue - Add a login/signup screen and gate the main content behind auth state
MIT License — see LICENSE for details.
Made by Withnico — iOS Developer and Content Creator.
Feel free to star the repo if you find it useful.
Un progetto starter minimale per iOS 26 che dimostra l'integrazione di Supabase con SwiftUI — senza autenticazione.
Perfetto per chi vuole imparare a connettere un'app SwiftUI a un backend reale usando Supabase per operazioni CRUD e upload di immagini.
L'app ha due sezioni:
Tab News — Una lista di articoli scaricati da Supabase. Ogni articolo ha un titolo, un'immagine e una data di creazione. Puoi aggiungere nuovi articoli con foto dalla libreria, aggiornare con pull-to-refresh e cancellare con swipe.
Tab Profilo — Un editor dove puoi impostare nome, cognome e caricare una foto profilo. Tutto viene salvato su Supabase.
Tutte le immagini vengono caricate su Supabase Storage e salvate come URL pubblici nel database.
Non c'è autenticazione. Questa è una scelta intenzionale — il progetto è pensato come strumento di apprendimento, non come app di produzione.
- SwiftUI — iOS 26+ con API moderne (async/await, PhotosPicker, AsyncImage, ContentUnavailableView)
- Supabase — Backend-as-a-Service (database PostgreSQL + storage oggetti)
- Supabase Swift SDK — Client Swift ufficiale per Supabase
L'unica dipendenza esterna è il Supabase Swift SDK ufficiale:
https://github.com/supabase/supabase-swift
Seleziona la libreria Supabase quando aggiungi il pacchetto.
supabase-swiftui-starter/
├── SupabaseStarterApp.swift → Entry point dell'app (@main)
├── SupabaseManager.swift → Singleton Supabase (inserisci qui le tue credenziali)
├── Models.swift → Modelli Codable (Article, Profile)
├── ContentView.swift → TabView principale (News + Profilo)
├── ArticleListView.swift → Fetch, visualizzazione e cancellazione articoli
├── ArticleRowView.swift → Riga singola (immagine + titolo + data)
├── AddArticleView.swift → Form per creare un articolo con upload immagine
├── ProfileView.swift → Editor profilo con upload avatar
├── setup.sql → Query SQL per configurare il database Supabase
└── README.md
Se non hai mai usato Supabase, segui ogni passaggio. Se hai già un account, vai al Passo 2.
- Vai su supabase.com
- Clicca Start your project e registrati con GitHub o email
- Una volta dentro, ti troverai nella Dashboard di Supabase
- Clicca New Project
- Scegli la tua organizzazione (o creane una)
- Imposta un nome progetto (es.
swiftui-starter) - Imposta una password per il database (salvala da qualche parte — non ti servirà nell'app ma per l'accesso diretto al DB)
- Scegli una regione vicina a te
- Clicca Create new project e aspetta 1-2 minuti
- Nella barra laterale, vai su Settings (icona ingranaggio in basso)
- Clicca API sotto Configuration
- Copia questi due valori:
- Project URL — tipo
https://abcdefg.supabase.co - anon public key — una stringa lunga che inizia con
eyJ...
- Project URL — tipo
- Nella barra laterale, clicca SQL Editor
- Clicca New query
- Incolla il seguente SQL e clicca Run:
-- ============================================
-- supabase-swiftui-starter — Setup Database
-- ============================================
-- Tabella articoli
CREATE TABLE articles (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
title TEXT NOT NULL,
image_url TEXT,
created_at TIMESTAMPTZ DEFAULT now()
);
-- Tabella profilo (riga singola, senza autenticazione)
CREATE TABLE profile (
id UUID DEFAULT gen_random_uuid() PRIMARY KEY,
first_name TEXT NOT NULL DEFAULT '',
last_name TEXT NOT NULL DEFAULT '',
avatar_url TEXT
);
-- Inserisci un profilo vuoto di default
INSERT INTO profile (first_name, last_name) VALUES ('', '');- Dovresti vedere Success. No rows returned — è corretto
- Ora esegui una seconda query per le policy di sicurezza:
-- ============================================
-- Row Level Security — Permetti Tutto (No Auth)
-- ============================================
ALTER TABLE articles ENABLE ROW LEVEL SECURITY;
ALTER TABLE profile ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Allow all on articles" ON articles
FOR ALL USING (true) WITH CHECK (true);
CREATE POLICY "Allow all on profile" ON profile
FOR ALL USING (true) WITH CHECK (true);Questo abilita la Row Level Security ma permette tutte le operazioni senza autenticazione. Va bene per imparare, ma in produzione dovresti usare policy basate sull'autenticazione.
- Nella barra laterale, clicca Storage
- Clicca New bucket
- Crea il primo bucket:
- Nome:
article-images - Attiva Public bucket
- Clicca Create bucket
- Nome:
- Crea il secondo bucket:
- Nome:
avatars - Attiva Public bucket
- Clicca Create bucket
- Nome:
Per ogni bucket devi permettere upload e download senza autenticazione.
Per il bucket article-images:
- Clicca su
article-imagesnella barra laterale dello Storage - Clicca la tab Policies (o vai su Configuration → Policies)
- Clicca New policy
- Seleziona For full customization
- Imposta:
- Policy name:
Allow all - Allowed operations: seleziona SELECT, INSERT, DELETE
- Target roles: lascia il default
- USING expression:
true - WITH CHECK expression:
true
- Policy name:
- Clicca Review poi Save policy
Ripeti gli stessi identici passaggi per il bucket avatars.
Il tuo backend Supabase è pronto.
-
Clona questo repo:
git clone https://github.com/user/supabase-swiftui-starter.git
-
Apri il progetto in Xcode 26+
-
Aggiungi il Supabase Swift SDK:
- Vai su File → Add Package Dependencies
- Inserisci:
https://github.com/supabase/supabase-swift - Clicca Add Package
- Seleziona la libreria Supabase e clicca Add Package
-
Apri
SupabaseManager.swifte sostituisci i placeholder:private static let projectURL = URL(string: "https://YOUR_PROJECT_ID.supabase.co")! private static let anonKey = "YOUR_ANON_KEY_HERE"
-
Builda e avvia su simulatore o dispositivo (iOS 26+)
- Database — L'app legge e scrive su tabelle PostgreSQL (
articles,profile) usando il query builder del Supabase Swift SDK con async/await. - Storage — Le immagini vengono compresse in JPEG, caricate sui bucket di Supabase Storage, e i loro URL pubblici vengono salvati nel database. L'app usa
AsyncImageper caricarle. - Nessuna Auth — La RLS è abilitata con policy permissive. Tutte le operazioni sono consentite senza un utente loggato. Questo mantiene il codice semplice e focalizzato sull'apprendimento delle basi di Supabase.
Quando sei pronto per aggiungere l'autenticazione:
- Abilita un provider di auth nella Dashboard Supabase (Email, Google, Apple, ecc.)
- Usa
SupabaseManager.client.auth.signIn()e.signUp()nella tua app - Sostituisci le policy RLS usando
auth.uid()al posto ditrue - Aggiungi una schermata login/registrazione e mostra il contenuto principale solo dopo l'autenticazione
MIT License — vedi LICENSE per i dettagli.
Creato da Withnico — iOS Developer e Content Creator.
Se il progetto ti è utile, lascia una stella al repo.