Skip to main content

Connecting a Database

This guide explains how to store, retrieve, and manage data in your Natively app using the built-in Specular backend.

When You Need a Database

You need a database when:
  • Data should persist across app restarts
  • Data should sync across devices
  • Users need their own personal data
  • You’re building any CRUD application

Basic Data Storage

Creating a Simple Feature

Let’s build a notes app to demonstrate database concepts:
Create a notes app where users can:
- View a list of their notes
- Tap a note to see full content
- Create new notes with title and content
- Edit existing notes
- Delete notes

Store notes in the database so they persist.
Each user should only see their own notes.
When you request data persistence, Specular automatically creates the necessary database tables and API endpoints.

Understanding the Data Model

How the AI Creates Tables

The AI analyzes your request and creates an appropriate schema:
-- Example generated table for notes
CREATE TABLE notes (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  user_id TEXT NOT NULL,
  title TEXT NOT NULL,
  content TEXT,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

Being Explicit About Schema

For complex data, be specific:
Create a recipes feature with this data structure:

Recipes table:
- id (unique identifier)
- title (required, text)
- description (optional, text)
- prep_time (number, in minutes)
- cook_time (number, in minutes)
- servings (number)
- image_url (optional, text)
- created_at (timestamp)
- user_id (link to user)

Ingredients table (linked to recipes):
- id (unique)
- recipe_id (link to recipe)
- name (required, text)
- quantity (text, like "2 cups")
- order (number, for sorting)

Each user can only see their own recipes.

CRUD Operations

Create (Adding Data)

When the user submits the new recipe form:
1. Validate all required fields are filled
2. Save the recipe to the database
3. Navigate back to the recipe list
4. Show a success toast: "Recipe saved!"

Read (Fetching Data)

On the recipes list screen:
1. Fetch all recipes for the current user
2. Order by created_at, newest first
3. Show a loading spinner while fetching
4. Show "No recipes yet" if empty

Update (Editing Data)

Add an edit button on the recipe detail screen:
1. Tapping it shows the recipe form with existing data
2. User can modify any field
3. On save, update the recipe in the database
4. Show success toast and return to detail view

Delete (Removing Data)

Add delete functionality:
1. Long press on a recipe shows delete option
2. Show confirmation dialog: "Delete this recipe?"
3. On confirm, delete from database
4. Remove from list with animation

Relationships Between Data

One-to-Many Relationships

Each recipe has many ingredients.
When viewing a recipe, show its ingredients.
When deleting a recipe, also delete its ingredients.
On the recipe detail screen:
- Fetch the recipe by ID
- Also fetch all ingredients for this recipe
- Display ingredients in order

Querying and Filtering

Add a search bar to the recipes list:
- Filter recipes as the user types
- Search both title and description
- Show "No results" if nothing matches

Sorting

Add a sort option to recipes:
- Sort by newest first (default)
- Sort by prep time (shortest first)
- Sort alphabetically by title

Filtering

Add category filtering:
- Each recipe has a category (breakfast, lunch, dinner, dessert)
- Add filter chips at the top of the list
- Tapping a chip shows only that category

Optimistic Updates

For better UX, update the UI before the server responds:
When marking a task complete:
1. Immediately show it as complete (optimistic update)
2. Send the update to the server in background
3. If the server request fails, revert the change
4. Show an error toast if it fails

Error Handling

Handle database errors gracefully:
- If save fails, show error message and keep form data
- If fetch fails, show retry button
- If delete fails, show error and keep item in list
- Always show user-friendly error messages

Viewing Your Data

Use the Database Viewer to inspect your data:
  1. Click the Database icon in the preview header
  2. Select a table from the sidebar
  3. Browse records and their values
This is useful for:
  • Debugging data issues
  • Verifying saves work correctly
  • Understanding the data structure

Best Practices

Validate Before Saving

Check data is valid before sending to server

Show Loading States

Indicate when data is being fetched or saved

Handle Errors

Always handle and display errors gracefully

Use Optimistic Updates

Update UI immediately for better responsiveness

Next Steps