Skip to content

Database Schema

Treeline stores all your financial data in a local DuckDB database. This page documents the schema so you can write custom queries, build plugins, or integrate with external tools.

Treeline uses a two-layer schema design:

  • System tables (sys_*) - The raw data with all technical details
  • User views - Simplified views that join related data for convenience

When querying, prefer the views (transactions, accounts, balance_snapshots) unless you need low-level access.

These are the recommended tables for querying. They join related data and hide internal complexity.

The primary view for transaction data. Joins transaction records with their account information.

ColumnTypeDescription
transaction_idVARCHARUnique identifier (UUID)
account_idVARCHARForeign key to accounts
amountDECIMAL(15,2)Transaction amount (negative = expense)
descriptionVARCHARTransaction description from bank
transaction_dateDATEWhen the transaction occurred
posted_dateDATEWhen the transaction posted
tagsVARCHAR[]Array of user-applied tags
tags_auto_appliedBOOLEANWhether tags came from auto-tag rules
parent_transaction_idVARCHARFor split transactions, references parent
sourceVARCHARWhere this transaction came from
account_nameVARCHARJoined from accounts table
account_typeVARCHARAccount type (checking, credit, etc.)
currencyVARCHARCurrency code (USD, EUR, etc.)
institution_nameVARCHARBank or institution name

Source values:

  • simplefin - Synced via SimpleFIN
  • lunchflow - Synced via Lunch Flow
  • csv_import - Imported from CSV file
  • split - Created by splitting another transaction
  • manual - Manually entered
  • unknown - Legacy data without tracking

All financial accounts (checking, savings, credit cards, investments, etc.). This view exposes all columns from sys_accounts.

ColumnTypeDescription
account_idVARCHARUnique identifier
nameVARCHARAccount name from institution
nicknameVARCHARUser-defined display name
account_typeVARCHARType (depository, credit, loan, investment)
classificationVARCHARAsset or liability
currencyVARCHARCurrency code
balanceDECIMAL(15,2)Current balance
institution_nameVARCHARBank or institution name
institution_urlVARCHARInstitution website
institution_domainVARCHARInstitution domain
is_manualBOOLEANWhether manually created
created_atTIMESTAMPWhen account was added
updated_atTIMESTAMPLast modification time

Provider-specific columns (prefixed with sf_ for SimpleFIN, lf_ for Lunch Flow) contain raw data from each provider for deduplication and debugging.

Historical balance records captured during each sync.

ColumnTypeDescription
snapshot_idVARCHARUnique identifier
account_idVARCHARForeign key to accounts
balanceDECIMAL(15,2)Balance at snapshot time
snapshot_timeTIMESTAMPWhen the balance was recorded
sourceVARCHARHow the snapshot was created
created_atTIMESTAMPWhen the record was created
updated_atTIMESTAMPLast modification time
account_nameVARCHARJoined from accounts table
institution_nameVARCHARJoined from accounts table

Source values:

  • sync - Captured during bank sync
  • manual - Manually recorded
  • backfill - Generated to fill gaps

These tables store raw data. Query them when you need access to technical details not exposed in views.

Tracks which schema migrations have been applied.

ColumnTypeDescription
migration_nameVARCHARPrimary key, name of the migration file
applied_atTIMESTAMPWhen the migration was applied

Raw account data including external IDs from connected providers.

ColumnTypeDescription
account_idVARCHARPrimary key
nameVARCHARAccount name from institution
nicknameVARCHARUser-defined display name
account_typeVARCHARType (depository, credit, loan, investment)
classificationVARCHARAsset or liability
currencyVARCHARCurrency code (default: USD)
balanceDECIMAL(15,2)Current balance
external_idsJSONLegacy provider IDs (deprecated)
institution_nameVARCHARBank or institution name
institution_urlVARCHARInstitution website
institution_domainVARCHARInstitution domain
is_manualBOOLEANWhether manually created
created_atTIMESTAMPWhen account was added
updated_atTIMESTAMPLast modification time
sf_idVARCHARSimpleFIN account ID
sf_nameVARCHARSimpleFIN account name
sf_currencyVARCHARSimpleFIN currency
sf_balanceVARCHARSimpleFIN balance (string)
sf_available_balanceVARCHARSimpleFIN available balance
sf_balance_dateBIGINTSimpleFIN balance timestamp
sf_org_nameVARCHARSimpleFIN organization name
sf_org_urlVARCHARSimpleFIN organization URL
sf_org_domainVARCHARSimpleFIN organization domain
sf_extraJSONSimpleFIN extra fields
lf_idVARCHARLunch Flow account ID
lf_nameVARCHARLunch Flow account name
lf_institution_nameVARCHARLunch Flow institution name
lf_institution_logoVARCHARLunch Flow institution logo URL
lf_providerVARCHARLunch Flow provider
lf_currencyVARCHARLunch Flow currency
lf_statusVARCHARLunch Flow account status

The underlying transaction storage. Includes soft-delete support (deleted_at) and provider-specific columns for deduplication.

ColumnTypeDescription
transaction_idVARCHARPrimary key
account_idVARCHARForeign key to sys_accounts
amountDECIMAL(15,2)Transaction amount
descriptionVARCHARTransaction description
transaction_dateDATEWhen the transaction occurred
posted_dateDATEWhen the transaction posted
tagsVARCHAR[]Array of tags
tags_auto_appliedBOOLEANWhether tags came from auto-tag rules
external_idsJSONLegacy provider IDs (deprecated)
parent_transaction_idVARCHARFor split transactions, references parent
deleted_atTIMESTAMPSoft delete timestamp (NULL if active)
is_manualBOOLEANWhether manually entered
created_atTIMESTAMPWhen transaction was created
updated_atTIMESTAMPLast modification time
csv_fingerprintVARCHARCSV import dedup fingerprint
csv_batch_idVARCHARCSV import batch ID
sf_idVARCHARSimpleFIN transaction ID
sf_postedBIGINTSimpleFIN posted timestamp
sf_amountVARCHARSimpleFIN amount (string)
sf_descriptionVARCHARSimpleFIN description
sf_transacted_atBIGINTSimpleFIN transaction timestamp
sf_pendingBOOLEANSimpleFIN pending flag
sf_extraJSONSimpleFIN extra fields
lf_idVARCHARLunch Flow transaction ID
lf_account_idVARCHARLunch Flow account ID
lf_amountDECIMAL(15,2)Lunch Flow amount
lf_currencyVARCHARLunch Flow currency
lf_dateDATELunch Flow date
lf_merchantVARCHARLunch Flow merchant
lf_descriptionVARCHARLunch Flow description
lf_is_pendingBOOLEANLunch Flow pending flag

Raw balance snapshot records.

ColumnTypeDescription
snapshot_idVARCHARPrimary key
account_idVARCHARForeign key to sys_accounts
balanceDECIMAL(15,2)Balance at snapshot time
snapshot_timeTIMESTAMPWhen the balance was recorded
sourceVARCHARHow the snapshot was created
created_atTIMESTAMPWhen the record was created
updated_atTIMESTAMPLast modification time

Configuration for connected bank integrations (SimpleFIN, Lunch Flow).

ColumnTypeDescription
integration_nameVARCHARPrimary key (e.g., “simplefin”, “lunchflow”)
integration_settingsJSONIntegration configuration (tokens, API keys, account mappings)
created_atTIMESTAMPWhen the integration was added
updated_atTIMESTAMPLast modification time

Auto-tag rules that automatically apply tags to matching transactions.

ColumnTypeDescription
rule_idTEXTPrimary key
nameTEXTDisplay name for the rule
sql_conditionTEXTSQL WHERE clause for matching
display_conditionsTEXTJSON for UI rendering (optional)
tagsTEXT[]Tags to apply when matched
enabledBOOLEANWhether rule is active
sort_orderINTEGERProcessing order
created_atTIMESTAMPWhen the rule was created
updated_atTIMESTAMPLast modification time

Plugins store their data in dedicated DuckDB schemas, isolated from core tables. Each plugin creates its own schema (e.g., plugin_budget, plugin_goals, plugin_subscriptions).

Community plugins define their own schemas and are documented in their respective repositories.

Use tl query from the CLI or the Query plugin in the desktop app to run SQL against your data.

Terminal window
tl query "SELECT posted_date, amount, description FROM transactions LIMIT 10"

Spending by tag this month:

SELECT
UNNEST(tags) as tag,
SUM(-amount) as total
FROM transactions
WHERE amount < 0
AND posted_date >= DATE_TRUNC('month', CURRENT_DATE)
GROUP BY tag
ORDER BY total DESC

Net worth over time:

SELECT
DATE_TRUNC('month', snapshot_time) as month,
SUM(CASE
WHEN a.classification = 'asset' THEN balance
ELSE -balance
END) as net_worth
FROM balance_snapshots b
JOIN accounts a USING (account_id)
GROUP BY month
ORDER BY month

Untagged transactions:

SELECT posted_date, description, amount
FROM transactions
WHERE tags IS NULL OR ARRAY_LENGTH(tags) = 0
ORDER BY posted_date DESC

Account balances by type:

SELECT
account_type,
classification,
SUM(balance) as total_balance
FROM accounts
GROUP BY account_type, classification
ORDER BY classification, total_balance DESC

Explore the schema:

-- List all tables and views
SELECT table_name, table_type
FROM information_schema.tables
WHERE table_schema = 'main'
-- Describe a table's columns
DESCRIBE transactions
  1. Query views, not system tables unless you need raw provider data
  2. Use the Query view in the desktop app for interactive exploration
  3. Back up before experiments with tl backup create