Supabase
Supabase offers the best of both worlds — storage buckets for raw payloads and Postgres tables for structured metadata, all within the same platform.
Setup
Terra integrates with Supabase via OAuth. Everything is provisioned automatically:
In the Terra Dashboard > Connections page, click "Add New" and select Supabase.
You'll be redirected to Supabase to authorize Terra.
Select an existing project or create a new one.
Terra automatically provisions the following in your project:
A
terra-payloadsstorage bucket for raw data filesAccess via your project's service role key for secure write operations
Three database tables (see Data Structure below)
No manual setup is required.
Data Structure
Database tables
Terra creates three tables in your Supabase project's Postgres database:
CREATE TABLE terra_users (
user_id TEXT PRIMARY KEY,
reference_id TEXT,
created_at TIMESTAMPTZ,
granted_scopes TEXT,
provider TEXT,
state TEXT
);
CREATE TABLE terra_data_payloads (
payload_id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
data_type TEXT,
created_at TIMESTAMPTZ,
start_time TIMESTAMPTZ,
end_time TIMESTAMPTZ,
FOREIGN KEY (user_id) REFERENCES terra_users(user_id)
ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE terra_misc_payloads (
payload_id TEXT PRIMARY KEY,
user_id TEXT NOT NULL,
data_type TEXT,
payload_type TEXT,
created_at TIMESTAMPTZ,
FOREIGN KEY (user_id) REFERENCES terra_users(user_id)
ON DELETE CASCADE ON UPDATE CASCADE
);terra_users— Created/updated on authentication events. Thestatecolumn tracks the user's lifecycle (active,deauth,user_reauth, etc.).terra_data_payloads— One row per data event (activity, sleep, body, etc.). Same-day data for the same user and data type is deduplicated (last write wins).terra_misc_payloads— Non-data events (deauth, access revoked, etc.).
Foreign keys use ON DELETE CASCADE and ON UPDATE CASCADE, so deleting or updating a user automatically propagates to their payloads.
Storage bucket
Raw JSON payloads are uploaded to the terra-payloads bucket with the path:
For example: activity/3a4b5c6d7e8f9012.json
Row Level Security (RLS)
RLS is disabled on the Terra tables by default. This is intentional:
Terra writes data using a service role key, which bypasses RLS regardless.
Enabling RLS without policies would block your client-side reads (Supabase defaults to deny-all when RLS is on with no policies).
You're free to enable RLS and add your own policies to control how your frontend or users access the data. Terra's writes will continue to work regardless.
User lifecycle handling
Terra automatically manages user state transitions in your Supabase tables:
Re-authentication — When a user re-authenticates, Terra migrates their existing payloads to the new user ID and updates all foreign key references.
Deauthentication — When a user disconnects, Terra deletes their record from
terra_users(cascading to all payload rows) and removes their files from the storage bucket.
Last updated
Was this helpful?