.NET MAUI
Local Storage & Data
7 question(s)
What is Preferences and when should you use it?
Beginner
Preferences stores small key-value primitives (strings, numbers, booleans, dates) in platform-native settings storage. Use it for lightweight, non-sensitive app state like the last-selected tab, a theme choice, or a first-run flag. It is not for large or structured data.
Preferences.Default.Set("theme", "dark");
string theme = Preferences.Default.Get("theme", "light");
Real-world example
An app remembers the user's chosen theme across launches with a single Preferences key.
Common follow-ups: How is Preferences different from SecureStorage? | What types can it store?
Preferences
Device Features
Local Storage & Data
What is SecureStorage and what is it for?
Beginner
SecureStorage saves key-value string data encrypted using platform keystores (Android Keystore, iOS Keychain). Use it for sensitive values—auth tokens, refresh tokens, API keys tied to a user. It's asynchronous and should not hold large blobs.
await SecureStorage.Default.SetAsync("auth_token", token);
string? token = await SecureStorage.Default.GetAsync("auth_token");
Real-world example
After login, the JWT is kept in SecureStorage so it survives restarts without exposing it in plain preferences.
Common follow-ups: Why not store tokens in Preferences? | Is SecureStorage synchronous?
SecureStorage
Security
Local Storage & Data
How do you use SQLite for local relational data in MAUI?
Intermediate
Add the sqlite-net-pcl (or Microsoft.Data.Sqlite) package, create a database file path under FileSystem.AppDataDirectory, define models with attributes, and use an SQLiteAsyncConnection to create tables and run async CRUD. It's the standard choice for structured offline data.
var db = new SQLiteAsyncConnection(
Path.Combine(FileSystem.AppDataDirectory, "app.db3"));
await db.CreateTableAsync<Note>();
await db.InsertAsync(new Note { Text = "Hello" });
var notes = await db.Table<Note>().ToListAsync();
Real-world example
A note-taking app stores entries in SQLite so they're available fully offline and queryable.
Common follow-ups: Where should the db file live? | sqlite-net vs Microsoft.Data.Sqlite?
SQLite
Offline
Local Storage & Data
How do you read and write files in MAUI cross-platform?
Intermediate
Use System.IO with paths from FileSystem.AppDataDirectory (private, persistent) or CacheDirectory (disposable). For files bundled with the app, use FileSystem.OpenAppPackageFileAsync since packaged assets aren't regular filesystem paths on all platforms.
string path = Path.Combine(FileSystem.AppDataDirectory, "data.json");
await File.WriteAllTextAsync(path, json);
using var stream = await FileSystem.OpenAppPackageFileAsync("seed.json");
Real-world example
An app writes user data to AppDataDirectory and reads a bundled seed file via OpenAppPackageFileAsync on first run.
Common follow-ups: AppDataDirectory vs CacheDirectory? | How do you read a packaged file?
File System
Local Storage & Data
Platform Integration
How do you use EF Core with SQLite in a MAUI app?
Intermediate
Add Microsoft.EntityFrameworkCore.Sqlite, define a DbContext pointing at a file in AppDataDirectory, and call Database.EnsureCreated or run migrations at startup. EF Core gives LINQ queries and change tracking; be mindful of startup cost and consider registering the context appropriately for a client app.
public class AppDbContext : DbContext
{
public DbSet<Note> Notes => Set<Note>();
protected override void OnConfiguring(DbContextOptionsBuilder o) =>
o.UseSqlite($"Filename={Path.Combine(
FileSystem.AppDataDirectory, \"app.db\")}");
}
Real-world example
A team reuses their server EF models on the client, querying local notes with LINQ instead of raw SQL.
Common follow-ups: EF Core vs sqlite-net trade-offs? | How do you apply migrations on device?
SQLite
EF Core
Local Storage & Data
How do you design an offline-first sync strategy in MAUI?
Advanced
Persist data locally (SQLite) as the source of truth for the UI, queue local changes with a pending/dirty flag, and reconcile with the server when Connectivity reports access. Use timestamps or version columns for conflict detection and a defined resolution policy (last-write-wins or merge). Sync in a background-safe service.
if (Connectivity.Current.NetworkAccess == NetworkAccess.Internet)
await _syncService.PushPendingAsync(); // then pull server changes
Real-world example
A field-service app lets technicians work fully offline; edits queue locally and sync automatically when signal returns.
Common follow-ups: How do you detect conflicts? | Where do you run sync safely?
Offline
SQLite
Networking & APIs
How do you protect data at rest in a MAUI app?
Advanced
Keep secrets in SecureStorage (keystore-backed). For databases, use SQLCipher (via sqlite-net's encryption support) to encrypt the file, storing the key in SecureStorage. Avoid logging sensitive data, and prefer platform biometric gating for access. Never hardcode keys in the app package.
// Encrypted SQLite connection string (SQLCipher)
var options = new SQLiteConnectionString(dbPath, true,
key: await SecureStorage.Default.GetAsync("db_key"));
var db = new SQLiteAsyncConnection(options);
Real-world example
A healthcare app encrypts its local SQLite database with a key held in the OS keychain to meet compliance requirements.
Common follow-ups: Where do you store the encryption key? | Why avoid hardcoding keys?
Security
SQLite
SecureStorage