Skip to content

Deploying Fava

Introduction

Fava is a modern, feature-rich web interface for Beancount, a powerful double-entry accounting system implemented in Python. Unlike traditional accounting software that hides data in proprietary databases, Fava embraces plain text accounting—your entire financial history lives in simple, version-controllable text files that you can edit with any text editor.

Fava transforms Beancount’s plain text ledgers into interactive dashboards with beautiful charts, real-time balance calculations, and powerful query capabilities. It’s perfect for personal finance tracking, small business accounting, investment portfolio management, or anyone who values transparency and control over their financial data.

Key Features

  • Plain Text Accounting - Your financial data stored in human-readable text files
  • Double-Entry Bookkeeping - Professional-grade accounting principles built-in
  • Interactive Dashboards - Real-time balance sheets, income statements, and cash flow reports
  • Multi-Currency Support - Track accounts in different currencies with automatic conversion
  • Investment Tracking - Monitor stock portfolios, calculate returns, and track cost basis
  • Budget Planning - Set budgets and compare actual vs. planned spending
  • Tag-Based Organization - Flexible categorization with tags, payees, and custom metadata
  • Query Interface - SQL-like queries for custom financial reports
  • Import Tools - Import transactions from CSV files and bank statements
  • Document Attachments - Link receipts and invoices to transactions
  • Version Control Friendly - Track financial history with Git
  • Mobile Responsive - Manage finances from any device
  • Extensible - Python-based plugins and custom scripts
  • Privacy First - No data leaves your server, no subscriptions, no vendor lock-in

Why Deploy Fava on Klutch.sh?

Deploying Fava on Klutch.sh provides significant advantages for managing your financial data:

  • Complete Privacy - Your financial records stay on your infrastructure, never shared with third parties
  • Always Accessible - Access your accounts from anywhere with HTTPS security
  • Fast Deployment - Automatic Dockerfile detection gets you running in minutes
  • Persistent Storage - Reliable storage for years of transaction history and documents
  • No Recurring Costs - Predictable infrastructure pricing without per-user or per-account fees
  • Version Control Integration - Easy Git integration for tracking financial history
  • Automatic Backups - Built-in volume backup capabilities for peace of mind
  • Custom Domains - Professional access at your own domain
  • Scalable - Handles decades of transaction data without slowdown

Prerequisites

Before deploying Fava on Klutch.sh, ensure you have:

  • A Klutch.sh account
  • Basic familiarity with Docker and environment variables
  • Understanding of double-entry accounting principles (helpful but not required)
  • Beancount ledger files or willingness to create them
  • Optional: Git repository for version-controlling your ledgers

Understanding Fava and Beancount

Fava is built on top of Beancount, which uses a simple text format for recording transactions:

; Example Beancount ledger
; Account declarations
2024-01-01 open Assets:Bank:Checking
2024-01-01 open Assets:Bank:Savings
2024-01-01 open Income:Salary
2024-01-01 open Expenses:Groceries
2024-01-01 open Expenses:Rent
; Transactions
2024-01-15 * "Paycheck"
Assets:Bank:Checking 3500.00 USD
Income:Salary -3500.00 USD
2024-01-16 * "Grocery Store" "Weekly shopping"
Expenses:Groceries 156.32 USD
Assets:Bank:Checking -156.32 USD
2024-01-01 * "Landlord" "January rent"
Expenses:Rent 1200.00 USD
Assets:Bank:Checking -1200.00 USD

Fava reads these files and presents them in a user-friendly web interface with charts, reports, and editing capabilities.

Preparing Your Repository

Create a new repository for your Fava deployment with the following structure:

fava-deployment/
├── Dockerfile
├── ledger/
│ ├── main.beancount
│ └── documents/
└── .gitignore

Dockerfile

Create a Dockerfile in your repository root:

# Multi-stage build for Fava
FROM python:3.11-slim AS builder
# Set working directory
WORKDIR /app
# Install build dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
gcc \
g++ \
&& rm -rf /var/lib/apt/lists/*
# Install Fava and Beancount
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir \
fava \
beancount \
smart_importer
# Production stage
FROM python:3.11-slim
# Install runtime dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
# Create non-root user
RUN useradd -m -u 1000 -s /bin/bash fava
# Copy Python packages from builder
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin/fava /usr/local/bin/fava
COPY --from=builder /usr/local/bin/bean-* /usr/local/bin/
# Create necessary directories
RUN mkdir -p /data/ledger /data/documents && \
chown -R fava:fava /data
# Switch to non-root user
USER fava
WORKDIR /data
# Environment variables with defaults
ENV FAVA_HOST=0.0.0.0 \
FAVA_PORT=5000 \
BEANCOUNT_FILE=/data/ledger/main.beancount
# Expose port
EXPOSE 5000
# Health check
HEALTHCHECK --interval=30s --timeout=3s --start-period=10s --retries=3 \
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:5000').read()" || exit 1
# Start Fava
CMD ["sh", "-c", "fava --host ${FAVA_HOST} --port ${FAVA_PORT} ${BEANCOUNT_FILE}"]

Sample Beancount Ledger

Create ledger/main.beancount as your starting ledger file:

; Fava Configuration Options
option "title" "My Personal Finances"
option "operating_currency" "USD"
; Account Declarations
2024-01-01 open Assets:Bank:Checking USD
2024-01-01 open Assets:Bank:Savings USD
2024-01-01 open Assets:Cash USD
2024-01-01 open Liabilities:CreditCard USD
2024-01-01 open Equity:Opening-Balances USD
2024-01-01 open Income:Salary USD
2024-01-01 open Income:Interest USD
2024-01-01 open Expenses:Groceries USD
2024-01-01 open Expenses:Rent USD
2024-01-01 open Expenses:Utilities USD
2024-01-01 open Expenses:Transportation USD
2024-01-01 open Expenses:Entertainment USD
; Opening Balances
2024-01-01 * "Opening Balance"
Assets:Bank:Checking 5000.00 USD
Assets:Bank:Savings 10000.00 USD
Equity:Opening-Balances -15000.00 USD
; Sample Transactions
2024-01-15 * "Employer Inc" "January Paycheck"
Assets:Bank:Checking 3500.00 USD
Income:Salary -3500.00 USD
2024-01-16 * "Supermarket" "Weekly groceries"
Expenses:Groceries 156.32 USD
Assets:Bank:Checking -156.32 USD
2024-01-01 * "Property Management" "January rent"
Expenses:Rent 1200.00 USD
Assets:Bank:Checking -1200.00 USD
2024-01-05 * "Electric Company" "December electricity"
Expenses:Utilities 85.50 USD
Assets:Bank:Checking -85.50 USD
2024-01-10 * "Gas Station" "Fuel"
Expenses:Transportation 45.00 USD
Liabilities:CreditCard -45.00 USD
; Budget for 2024
2024-01-01 custom "budget" Expenses:Groceries "monthly" 600.00 USD
2024-01-01 custom "budget" Expenses:Rent "monthly" 1200.00 USD
2024-01-01 custom "budget" Expenses:Utilities "monthly" 150.00 USD
2024-01-01 custom "budget" Expenses:Transportation "monthly" 200.00 USD
2024-01-01 custom "budget" Expenses:Entertainment "monthly" 100.00 USD

.gitignore

Create a .gitignore file to exclude sensitive or generated files:

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
# Environment
.env
.venv
venv/
# Fava cache
.fava-cache/
# Documents (if containing sensitive receipts)
# Uncomment if you don't want to commit documents
# ledger/documents/
# IDE
.vscode/
.idea/
*.swp
*.swo

Docker Compose for Local Development

For local testing before deploying to Klutch.sh, create a docker-compose.yml:

version: '3.8'
services:
fava:
build: .
ports:
- "5000:5000"
volumes:
- ./ledger:/data/ledger
- ./ledger/documents:/data/documents
environment:
- BEANCOUNT_FILE=/data/ledger/main.beancount
restart: unless-stopped

Test locally:

Terminal window
# Build and start Fava
docker-compose up -d
# View logs
docker-compose logs -f fava
# Stop
docker-compose down

Access Fava at http://localhost:5000

Environment Variables Reference

Fava supports the following environment variables:

Server Configuration:

  • FAVA_HOST - Host to bind to (default: 0.0.0.0)
  • FAVA_PORT - Port to listen on (default: 5000)
  • BEANCOUNT_FILE - Path to main Beancount ledger file (required)

Optional Configuration:

  • FAVA_OPTIONS - Additional Fava command-line options (e.g., --read-only)

Deploying on Klutch.sh

Now that your repository is ready, let’s deploy Fava to Klutch.sh.

Step 1: Create a New App

  1. Log in to your Klutch.sh dashboard
  2. Navigate to your project or create a new one
  3. Click "New App" and select "Deploy from GitHub"
  4. Authorize Klutch.sh to access your GitHub repositories
  5. Select the repository containing your Fava Dockerfile and ledger files
  6. Klutch.sh will automatically detect the Dockerfile in your repository

Step 2: Configure Environment Variables

  1. In the app configuration, navigate to the "Environment Variables" section
  2. Add the following environment variables:
    • FAVA_HOST = 0.0.0.0
    • FAVA_PORT = 5000
    • BEANCOUNT_FILE = /data/ledger/main.beancount
  3. Optional: Add FAVA_OPTIONS = --read-only if you want to disable editing through the web interface

Step 3: Configure Traffic and Networking

  1. In the "Traffic" section, select HTTP
  2. Set the internal port to 5000 (matches FAVA_PORT)
  3. Klutch.sh will automatically provide HTTPS access via your app's URL

Step 4: Attach Persistent Volumes

Fava needs persistent storage for your ledger files and document attachments.

  1. Navigate to the "Volumes" section in your app configuration
  2. Click "Add Volume" and configure:
    • Mount Path: /data/ledger
    • Size: 5 GB (adjust based on your needs)
  3. Add a second volume for documents and receipts:
    • Mount Path: /data/documents
    • Size: 10 GB (adjust based on the number of attachments)

Volume sizing recommendations:

  • Ledger volume: 1-5 GB (text files are small; even decades of transactions fit in megabytes)
  • Documents volume: 5-20 GB depending on the number of receipts, invoices, and attachments

Step 5: Deploy the App

  1. Review your configuration to ensure all settings are correct
  2. Click "Deploy" to start the deployment
  3. Klutch.sh will build your Docker image and deploy Fava
  4. Monitor the deployment logs for any errors
  5. Once deployed, access your Fava instance at https://your-app-name.klutch.sh

Step 6: Upload Your Ledger Files

After deployment, you need to populate your ledger files:

Option A: Using Git (Recommended)

If your ledger files are in your Git repository, they’ll be copied during the Docker build. However, for updates, you’ll need to rebuild the container. A better approach is to use persistent volumes:

  1. Use kubectl or a file manager to copy your ledger files to the persistent volume
  2. Alternatively, create an initialization script in your Dockerfile that clones a Git repository

Option B: Manual Upload via Shell

  1. Access your container's shell through the Klutch.sh dashboard
  2. Create your ledger file:
    cat > /data/ledger/main.beancount << 'EOF'
    ; Your Beancount transactions here
    option "title" "My Finances"
    option "operating_currency" "USD"
    

    2024-01-01 open Assets:Bank:Checking 2024-01-01 open Income:Salary EOF

  3. Restart the Fava container to load the new ledger

Option C: Using a Git Repository in Dockerfile

Modify your Dockerfile to clone your ledger repository:

# Add this before the CMD instruction
RUN apt-get update && apt-get install -y git && \
rm -rf /var/lib/apt/lists/*
# Clone your private ledger repository (use environment variables for credentials)
ARG GIT_REPO_URL
RUN if [ -n "$GIT_REPO_URL" ]; then \
git clone $GIT_REPO_URL /data/ledger; \
fi

Then add GIT_REPO_URL as an environment variable in Klutch.sh.

Initial Setup and Configuration

After deployment, configure Fava for your needs:

First Access

  1. Navigate to https://your-app-name.klutch.sh
  2. Fava will load your main.beancount file
  3. You'll see the main dashboard with your accounts and balances

Dashboard Overview

Fava’s interface includes several key sections:

  • Income Statement - Shows income, expenses, and net profit/loss
  • Balance Sheet - Assets, liabilities, and net worth
  • Trial Balance - Lists all accounts with their balances
  • Journal - Chronological list of all transactions
  • Query - SQL-like interface for custom reports
  • Statistics - Charts and visualizations of your financial data
  • Documents - File attachments linked to transactions
  • Import - Tools for importing transactions from CSV files
  • Editor - Text editor for modifying your Beancount files directly

Adding Your First Transaction

  1. Click on the "Editor" tab in Fava
  2. Scroll to the bottom of your ledger file
  3. Add a new transaction:
    2024-12-20 * "Coffee Shop" "Morning coffee"
      Expenses:Food:Coffee       5.50 USD
      Assets:Bank:Checking      -5.50 USD
  4. Click "Save"
  5. Fava will automatically reload and show the new transaction

Understanding Beancount Syntax

Account Types:

  • Assets - Things you own (bank accounts, cash, investments)
  • Liabilities - Things you owe (credit cards, loans)
  • Income - Money coming in (salary, interest, gifts)
  • Expenses - Money going out (rent, groceries, utilities)
  • Equity - Opening balances and retained earnings

Transaction Format:

YYYY-MM-DD [flag] "Payee" "Narration"
Account1 Amount1 Currency
Account2 Amount2 Currency

Flags:

  • * - Cleared/completed transaction
  • ! - Pending transaction

Tags and Links:

2024-12-20 * "Restaurant" "Team dinner" ^invoice-123 #work #meals
Expenses:Meals 125.00 USD
Assets:Bank:Checking -125.00 USD

Usage Examples

Recording Daily Transactions

Salary Deposit:

2024-12-15 * "Acme Corp" "December salary"
Assets:Bank:Checking 4500.00 USD
Income:Salary:Gross -5000.00 USD
Income:Salary:Tax 500.00 USD

Credit Card Purchase:

2024-12-16 * "Amazon" "Office supplies"
Expenses:Office:Supplies 87.65 USD
Liabilities:CreditCard -87.65 USD

Paying Off Credit Card:

2024-12-20 * "Credit Card Payment"
Liabilities:CreditCard 500.00 USD
Assets:Bank:Checking -500.00 USD

Multi-Currency Transactions

; Define exchange rates
2024-12-20 price EUR 1.09 USD
2024-12-20 * "Hotel in Paris" "Business trip accommodation"
Expenses:Travel:Lodging 150.00 EUR @ 1.09 USD
Liabilities:CreditCard -163.50 USD

Investment Tracking

; Open investment accounts
2024-01-01 open Assets:Investments:Brokerage:Cash USD
2024-01-01 open Assets:Investments:Brokerage:AAPL AAPL
2024-01-01 open Income:Investments:Capital-Gains USD
; Buy stock
2024-12-01 * "Brokerage" "Buy Apple stock"
Assets:Investments:Brokerage:AAPL 10 AAPL {150.00 USD}
Assets:Investments:Brokerage:Cash -1500.00 USD
; Record current price
2024-12-20 price AAPL 155.00 USD
; Sell stock
2024-12-20 * "Brokerage" "Sell Apple stock"
Assets:Investments:Brokerage:AAPL -10 AAPL {150.00 USD} @ 155.00 USD
Assets:Investments:Brokerage:Cash 1550.00 USD
Income:Investments:Capital-Gains -50.00 USD

Budget Tracking

; Set monthly budgets
2024-01-01 custom "budget" Expenses:Groceries "monthly" 600.00 USD
2024-01-01 custom "budget" Expenses:Entertainment "monthly" 100.00 USD
2024-01-01 custom "budget" Expenses:Transportation "monthly" 200.00 USD

View budget vs. actual in Fava’s Statistics tab.

Attaching Documents

Link receipts and invoices to transactions:

2024-12-20 * "Office Depot" "Printer"
Expenses:Office:Equipment 299.99 USD
Assets:Bank:Checking -299.99 USD
document: "/data/documents/2024-12-20-printer-receipt.pdf"

Upload the PDF to /data/documents/ and Fava will link it to the transaction.

Python API for Automation

Automate financial tracking with Python scripts:

from beancount import loader
from beancount.core import data
from beancount.core.amount import Amount
from decimal import Decimal
from datetime import date
# Load ledger
entries, errors, options = loader.load_file('/data/ledger/main.beancount')
# Create a new transaction
new_txn = data.Transaction(
meta={'lineno': 0, 'filename': '/data/ledger/main.beancount'},
date=date(2024, 12, 20),
flag='*',
payee='Coffee Shop',
narration='Morning coffee',
tags=set(),
links=set(),
postings=[
data.Posting(
account='Expenses:Food:Coffee',
units=Amount(Decimal('5.50'), 'USD'),
cost=None,
price=None,
flag=None,
meta={}
),
data.Posting(
account='Assets:Bank:Checking',
units=Amount(Decimal('-5.50'), 'USD'),
cost=None,
price=None,
flag=None,
meta={}
),
]
)
# Append to ledger file
with open('/data/ledger/main.beancount', 'a') as f:
f.write(f"\n{new_txn.date} {new_txn.flag} \"{new_txn.payee}\" \"{new_txn.narration}\"\n")
for posting in new_txn.postings:
f.write(f" {posting.account:40} {posting.units.number:>10} {posting.units.currency}\n")

CSV Import Script

Automate importing transactions from bank CSV exports:

import csv
from datetime import datetime
from decimal import Decimal
def import_csv(csv_path, output_path):
transactions = []
with open(csv_path, 'r') as f:
reader = csv.DictReader(f)
for row in reader:
date = datetime.strptime(row['Date'], '%m/%d/%Y').strftime('%Y-%m-%d')
description = row['Description']
amount = Decimal(row['Amount'])
# Categorize based on description (customize as needed)
if 'grocery' in description.lower():
expense_account = 'Expenses:Groceries'
elif 'gas' in description.lower():
expense_account = 'Expenses:Transportation'
elif 'amazon' in description.lower():
expense_account = 'Expenses:Shopping'
else:
expense_account = 'Expenses:Other'
# Generate transaction
txn = f'{date} * "{description}"\n'
txn += f' {expense_account:40} {abs(amount):>10.2f} USD\n'
txn += f' Assets:Bank:Checking{"":<40} {-abs(amount):>10.2f} USD\n'
transactions.append(txn)
# Append to ledger
with open(output_path, 'a') as f:
f.write('\n; Imported transactions\n')
for txn in transactions:
f.write(txn + '\n')
print(f"Imported {len(transactions)} transactions")
# Usage
import_csv('/data/documents/bank-export.csv', '/data/ledger/main.beancount')

Query Interface Examples

Fava includes a powerful query interface (BQL - Beancount Query Language):

Monthly Expenses:

SELECT
date,
payee,
account,
sum(position) AS amount
WHERE
account ~ 'Expenses:'
AND date >= 2024-01-01
AND date < 2024-02-01
GROUP BY date, payee, account
ORDER BY date DESC

Net Worth Over Time:

SELECT
date,
sum(convert(position, 'USD')) AS net_worth
WHERE
account ~ 'Assets:' OR account ~ 'Liabilities:'
GROUP BY date
ORDER BY date

Top Expense Categories:

SELECT
account,
sum(position) AS total
WHERE
account ~ 'Expenses:'
AND year = 2024
GROUP BY account
ORDER BY total DESC
LIMIT 10

Tax-Deductible Expenses:

SELECT
date,
payee,
narration,
account,
position
WHERE
account ~ 'Expenses:'
AND '#tax-deductible' IN tags
ORDER BY date

Production Best Practices

Security Hardening

1. Authentication (Optional but Recommended)

Fava doesn’t include built-in authentication. Add authentication via a reverse proxy:

Nginx with Basic Auth (Dockerfile addition):

# Install nginx
RUN apt-get update && apt-get install -y nginx apache2-utils
# Create htpasswd file (do this in deployment, not in Dockerfile)
# htpasswd -c /etc/nginx/.htpasswd yourusername
# Configure nginx as reverse proxy
COPY nginx.conf /etc/nginx/nginx.conf

nginx.conf:

events {
worker_connections 1024;
}
http {
upstream fava {
server localhost:5000;
}
server {
listen 8080;
location / {
auth_basic "Fava Login";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://fava;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
}

2. Read-Only Mode

For viewing without editing, enable read-only mode:

Terminal window
FAVA_OPTIONS="--read-only"

3. File Permissions

Ensure proper file ownership:

Terminal window
# In container
chown -R fava:fava /data/ledger
chmod 600 /data/ledger/*.beancount

4. Version Control

Track changes with Git for audit trails:

Terminal window
cd /data/ledger
git init
git add .
git commit -m "Initial ledger"
# Create post-save hook to auto-commit
cat > .git/hooks/post-commit << 'EOF'
#!/bin/sh
git add -A
git commit -m "Auto-commit: $(date)"
EOF
chmod +x .git/hooks/post-commit

Performance Optimization

1. Large Ledger Optimization

For ledgers with thousands of transactions:

; Use include to split ledgers by year
include "2022.beancount"
include "2023.beancount"
include "2024.beancount"

2. Caching

Fava caches parsed ledgers. Increase cache efficiency:

Terminal window
# Pre-load ledger on container start
bean-check /data/ledger/main.beancount

3. Resource Limits

For large ledgers, allocate sufficient memory:

# In Dockerfile, no specific Python memory limits needed
# Beancount is efficient even with decades of data

4. Index Optimization

Beancount automatically indexes accounts. No manual optimization needed, but keep transactions chronologically sorted for faster parsing.

Backup Strategy

1. Automated Git Backups

Create a backup script:

backup.sh
#!/bin/bash
cd /data/ledger
# Commit any changes
if [[ -n $(git status -s) ]]; then
git add -A
git commit -m "Auto-backup: $(date '+%Y-%m-%d %H:%M:%S')"
fi
# Push to remote (configure git remote first)
git push origin main
echo "Backup completed: $(date)"

Run via cron or manually:

Terminal window
chmod +x backup.sh
./backup.sh

2. Volume Snapshots

Use Klutch.sh’s volume backup features:

  1. Navigate to the "Volumes" section in your app
  2. Select your ledger volume
  3. Click "Create Snapshot"
  4. Schedule regular snapshots (daily recommended)

3. Export to Multiple Formats

Regularly export your data:

Terminal window
# Export to CSV
bean-query /data/ledger/main.beancount "SELECT * FROM transactions" > backup.csv
# Export to SQL
bean-query /data/ledger/main.beancount "SELECT * FROM transactions" -o json > backup.json

4. Document Backups

Backup attached receipts and documents:

Terminal window
# Sync documents to external storage
tar -czf documents-backup-$(date +%Y%m%d).tar.gz /data/documents

Monitoring and Alerts

1. Health Checks

Monitor Fava availability:

health-check.sh
#!/bin/bash
FAVA_URL="https://your-app-name.klutch.sh"
if curl -f -s "$FAVA_URL" > /dev/null; then
echo "Fava is healthy"
else
echo "Fava health check failed"
# Send alert (email, Slack, etc.)
fi

2. Ledger Validation

Regularly validate your ledger for errors:

Terminal window
# Check ledger integrity
bean-check /data/ledger/main.beancount
# Check for balance assertions
bean-doctor /data/ledger/main.beancount

3. Transaction Monitoring

Alert on unusual transactions:

from beancount import loader
from decimal import Decimal
def check_large_transactions(ledger_path, threshold=1000.00):
entries, errors, options = loader.load_file(ledger_path)
large_txns = []
for entry in entries:
if hasattr(entry, 'postings'):
for posting in entry.postings:
if posting.units and abs(posting.units.number) > Decimal(threshold):
large_txns.append({
'date': entry.date,
'payee': entry.payee,
'amount': posting.units
})
if large_txns:
print(f"Found {len(large_txns)} transactions over ${threshold}")
for txn in large_txns:
print(f" {txn['date']} - {txn['payee']}: {txn['amount']}")
return large_txns
# Run daily
check_large_transactions('/data/ledger/main.beancount', threshold=1000.00)

4. Balance Reconciliation

Add balance assertions to catch errors:

; Check balance on specific dates
2024-12-20 balance Assets:Bank:Checking 2345.67 USD
2024-12-31 balance Assets:Bank:Savings 10000.00 USD

Beancount will error if balances don’t match, alerting you to missing transactions or errors.

Troubleshooting

Common Issues and Solutions

1. Ledger File Not Found

Symptom: Fava fails to start with “Error: file not found”

Solutions:

  • Verify BEANCOUNT_FILE path is correct: /data/ledger/main.beancount

  • Check that persistent volume is mounted at /data/ledger

  • Ensure ledger file exists and has correct permissions

  • Test with shell access:

    Terminal window
    ls -la /data/ledger/
    cat /data/ledger/main.beancount

2. Syntax Errors in Ledger

Symptom: Fava shows “Parse Error” or fails to load

Solutions:

  • Validate ledger file:

    Terminal window
    bean-check /data/ledger/main.beancount
  • Check for common errors:

    • Missing account declarations
    • Unbalanced transactions (debits ≠ credits)
    • Invalid date formats (must be YYYY-MM-DD)
    • Missing currency codes
  • Use Fava’s editor with syntax highlighting to fix errors

3. Container Out of Memory

Symptom: Container crashes or becomes unresponsive with large ledgers

Solutions:

  • Split ledger into multiple files by year:

    include "2022.beancount"
    include "2023.beancount"
    include "2024.beancount"
  • Increase container memory allocation in Klutch.sh dashboard

  • Optimize queries (avoid SELECT * on huge datasets)

4. Permission Denied Errors

Symptom: Cannot save changes or write files

Solutions:

  • Verify volume permissions:

    Terminal window
    chown -R fava:fava /data/ledger
    chmod -R u+rw /data/ledger
  • Check that Fava is running as correct user (UID 1000)

  • Ensure volumes are mounted with read-write permissions

5. Import Failures

Symptom: CSV import doesn’t work or creates malformed transactions

Solutions:

  • Verify CSV format matches expected structure

  • Check date format in CSV (MM/DD/YYYY vs YYYY-MM-DD)

  • Use smart_importer for better automatic categorization:

    Terminal window
    pip install smart_importer
  • Review imported transactions before committing

6. Currency Conversion Issues

Symptom: Multi-currency transactions show errors or wrong values

Solutions:

  • Define exchange rates explicitly:

    2024-12-20 price EUR 1.09 USD
    2024-12-20 price GBP 1.27 USD
  • Use @ for transaction-time rates:

    Expenses:Travel 100.00 EUR @ 1.09 USD
  • Update exchange rates regularly (daily for volatile currencies)

7. Slow Performance

Symptom: Fava takes a long time to load or query

Solutions:

  • Split large ledger files by year

  • Close old periods (prevent edits to old data):

    2024-01-01 close Assets:Bank:OldAccount
  • Use specific date ranges in queries instead of full history

  • Cache frequently used queries as separate files

8. Documents Not Loading

Symptom: Attached documents show 404 or broken links

Solutions:

  • Verify document path in transactions:

    document: "/data/documents/receipt.pdf"
  • Check that documents volume is mounted at /data/documents

  • Ensure files have correct permissions:

    Terminal window
    chmod 644 /data/documents/*.pdf
  • Use relative paths from the documents directory

Debug Mode

Enable verbose logging for troubleshooting:

Terminal window
# Start Fava with debug logging
FAVA_OPTIONS="--debug" fava /data/ledger/main.beancount
# Check Beancount version
python -m beancount.scripts.doctor
# Validate entire ledger
bean-check -v /data/ledger/main.beancount

Getting Help

If you encounter issues not covered here:

Additional Resources


Take Control of Your Finances - With Fava on Klutch.sh, you have complete ownership of your financial data in a transparent, version-controlled format. No subscriptions, no vendor lock-in, just pure double-entry accounting perfection. Start tracking your finances the right way today.