---
title: Your lake
description: How synced data is organized, how rows change, and why deleted data never silently disappears.
species: concept
---

# Your lake

Everything Supernova syncs lands in one place: your organization's lake. It's a
single queryable surface over every connected source — Stripe next to HubSpot next
to your production Postgres — stored in an open columnar format, so a query that
joins across three SaaS tools is no different from a query over one table. This
page explains the small set of rules the lake lives by. They're worth ten minutes:
every other page assumes them.

## Tables and names

Each source syncs into its own schema, named after the source. The full name of
any table is `titan.<schema>.<table>`:

```sql fragment
select * from titan.stripe.charges
select * from titan.hubspot.deals
select * from titan.postgres.orders
```

Sources with fixed schemas (Stripe, Zendesk, Shopify) always produce the same
tables. Sources with discovered schemas (Postgres, Salesforce, Airtable) produce
whatever your account contains — Airtable, for instance, syncs each base into its
own schema named `airtable_<base>`. Column names are lowercase `snake_case`
everywhere, whatever the source API calls them.

## The system columns

Every synced table carries two columns maintained by Supernova:

| Column | Type | Meaning |
|---|---|---|
| `_synced_at` | timestamp | When this row last changed in the lake |
| `_deleted` | boolean | The row no longer exists at the source |

`_deleted` is the one to internalize. When a charge is deleted in Stripe or a deal
is merged away in HubSpot, the lake doesn't remove the row — it marks it. Your
history stays intact, and queries opt out explicitly:

```sql fragment
select count(*) from titan.hubspot.deals where not _deleted
```

Filter `not _deleted` in anything that counts, sums, or joins current state. Skip
the filter when you're deliberately looking at history — that's the point of
keeping it.

## How rows change

Syncs are incremental: each run fetches what changed since the last one and merges
it in by primary key, keeping the latest version of each row. Two consequences:

- **A sync interrupted halfway is harmless.** The next run picks up from the last
  checkpoint. You never get duplicate rows, because the merge is by key.
- **Delete detection varies by source.** Some APIs report deletions incrementally;
  others only reveal them in a complete pull, so those connectors periodically
  re-read everything to find what vanished. Each connector page states which
  strategy its source forces.

## Snapshots

Every sync commits atomically. A query always reads one consistent snapshot of a
table — never a half-written sync, even if the sync is running while your query
is. New data becomes visible all at once, when its sync commits.

The lake retains recent snapshots (30 days by default) rather than only the
present, which is what makes the atomicity cheap and interrupted work safe to
abandon.

## What this buys you

- **Joins across sources** with no pipelines to build: revenue by deal stage is
  one join between `titan.stripe.charges` and `titan.hubspot.deals`.
- **Schema changes surface, they don't break.** When a source grows a column, it
  appears in the lake; the **Schema changes** feed shows you what changed and when.
- **An open format.** Your data is stored as standard columnar files with standard
  table metadata — not a proprietary blob keyed to us.

Next: [writing models](/v2/docs/models/authoring) turns queries over these tables
into tables of your own.
