If you're a developer who wants to actually understand your finances — not just see a list of transactions in an app — this is the setup worth building.
SheetLink's CLI syncs your bank transactions to a Postgres database. Grafana connects to that database and turns it into a real-time dashboard: spending by category, monthly cash flow, top merchants, income trends. The kind of visibility you'd normally need an expensive finance tool to get.
This guide walks through the full setup — from first sync to a working dashboard.
What You're Building
By the end of this guide you'll have:
- All your bank transactions in a Postgres database, updated automatically via cron
- A Grafana dashboard with panels for monthly spending, income, category breakdown, and top merchants
- A setup that costs $0 in infrastructure (Grafana Cloud free tier + local or free-tier Postgres)
Prerequisites
- Node.js 18+
- A SheetLink account on the MAX plan
- Postgres (local, Supabase, Railway, Neon — anything with a connection string)
- Grafana (self-hosted or Grafana Cloud free tier)
- At least one bank connected in the SheetLink dashboard
Step 1: Install and Authenticate the SheetLink CLI
This opens a browser window for Google sign-in. After authenticating, credentials are stored locally and the CLI can run unattended.
Step 2: Run Your First Sync to Postgres
SheetLink creates two tables automatically:
sheetlink_transactions— every transaction from all connected accounts (35 columns)sheetlink_accounts— account metadata and current balances
Upsert key is transaction_id — running sync multiple times is always safe, no duplicates.
You should see output like:
Chase ................. 47 transactions
Bank of America ....... 83 transactions
Amex .................. 61 transactions
191 rows upserted → sheetlink_transactions
✓ sync complete
Verify the data landed:
SELECT COUNT(*), MIN(date), MAX(date) FROM sheetlink_transactions;
Step 3: Automate with Cron
Add a daily sync so Grafana always has fresh data:
# Runs every morning at 7am
0 7 * * * /usr/local/bin/sheetlink sync --output postgres://user:pass@host/finances >> /var/log/sheetlink.log 2>&1
💡 Tip
Store your connection string as an environment variable: sheetlink sync --output $DATABASE_URL. Keeps credentials out of your crontab.
Step 4: Connect Grafana to Postgres
- Open Grafana → Connections → Add new data source
- Select PostgreSQL
- Enter your connection details:
- Host: your Postgres host + port
- Database: your database name
- User/Password: your credentials
- SSL Mode:
requirefor hosted databases,disablefor local
- Click Save & Test — you should see "Database Connection OK"
Step 5: Build Your Dashboard
Create a new dashboard and add panels using the queries below. Each one is a standalone panel — add as many as you want.
Monthly Spending by Category
SELECT
DATE_TRUNC('month', date) AS time,
category_primary AS metric,
SUM(ABS(amount)) AS value
FROM sheetlink_transactions
WHERE amount < 0
AND date >= NOW() - INTERVAL '6 months'
GROUP BY 1, 2
ORDER BY 1
Panel type: Bar chart or Time series. Set visualization to stack bars for a clear breakdown.
Monthly Cash Flow (Income vs Expenses)
SELECT
DATE_TRUNC('month', date) AS time,
CASE WHEN amount > 0 THEN 'Income' ELSE 'Expenses' END AS metric,
SUM(ABS(amount)) AS value
FROM sheetlink_transactions
WHERE date >= NOW() - INTERVAL '12 months'
GROUP BY 1, 2
ORDER BY 1
Panel type: Bar chart with grouped bars. Green for income, red for expenses.
Net Cash Flow per Month
SELECT
DATE_TRUNC('month', date) AS time,
SUM(amount) * -1 AS net_cash_flow
FROM sheetlink_transactions
WHERE date >= NOW() - INTERVAL '12 months'
GROUP BY 1
ORDER BY 1
Panel type: Time series. Positive = saved money, negative = spent more than earned.
ℹ️ Info
Amounts follow Plaid's sign convention: negative = money out (expense), positive = money in (income/deposit). The * -1 in the net cash flow query flips it so positive = surplus.
Top Merchants (Last 90 Days)
SELECT
COALESCE(merchant_name, description_raw) AS merchant,
SUM(ABS(amount)) AS total_spent
FROM sheetlink_transactions
WHERE amount < 0
AND date >= NOW() - INTERVAL '90 days'
GROUP BY 1
ORDER BY total_spent DESC
LIMIT 15
Panel type: Bar gauge or Table.
Spending This Month vs Last Month
SELECT
DATE_TRUNC('month', date) AS month,
SUM(ABS(amount)) AS total_spent
FROM sheetlink_transactions
WHERE amount < 0
AND date >= DATE_TRUNC('month', NOW()) - INTERVAL '1 month'
GROUP BY 1
ORDER BY 1
Panel type: Stat panel with two values side by side.
Current Account Balances
SELECT
name AS account,
current_balance
FROM sheetlink_accounts
ORDER BY current_balance DESC
Panel type: Table or Bar gauge.
Recurring Subscriptions
SELECT
COALESCE(merchant_name, description_raw) AS merchant,
COUNT(*) AS months,
AVG(ABS(amount)) AS avg_amount,
SUM(ABS(amount)) AS total_paid
FROM sheetlink_transactions
WHERE amount < 0
AND payment_channel = 'online'
AND date >= NOW() - INTERVAL '6 months'
GROUP BY 1
HAVING COUNT(*) >= 3
ORDER BY total_paid DESC
Panel type: Table. This surfaces anything that's charged you 3+ times in 6 months — a quick way to audit subscriptions.
Step 6: Set Up Alerts (Optional)
Grafana can alert you when spending crosses a threshold. For example, alert when monthly food spending exceeds $800:
- Open your spending by category panel
- Click Alert → New alert rule
- Set condition:
value > 800wherecategory_primary = 'FOOD_AND_DRINK' - Connect a notification channel (email, Slack, PagerDuty — whatever you use)
The Full Stack
Bank accounts (Plaid)
↓
SheetLink CLI (daily cron)
↓
Postgres (sheetlink_transactions + sheetlink_accounts)
↓
Grafana (dashboards, alerts)
Total infrastructure cost at scale: SheetLink MAX at $10.99/month. Grafana Cloud free tier handles personal use. Postgres on Railway or Supabase starts free.
For the user who already has a home server or a small VPS, the marginal cost is zero beyond the SheetLink subscription.
What You End Up With
A dashboard that shows you exactly where your money is going, updated every morning, queryable with SQL, and extensible with anything else Grafana can connect to. Home Assistant, server metrics, uptime — your financial data sitting next to everything else you monitor.
It's the kind of setup that takes an afternoon to build and then runs itself.
SheetLink MAX
Add CLI, Postgres, and API access
Upgrade to MAX — $10.99/mo14-day money-back guarantee · Cancel anytime