Skip to content

Include Directive

Overview

The include directive imports the contents of another file into the current ledger. This enables organizing large ledgers across multiple files.

Syntax

include = "include" WHITESPACE path

path = string

Components

Path

A string containing the file path to include: - Relative paths resolve from the including file's directory - Absolute paths are used as-is

Examples

Basic Include

; main.beancount
include "accounts.beancount"
include "2024/january.beancount"
include "2024/february.beancount"

Directory Structure

ledger/
├── main.beancount
├── accounts.beancount
├── commodities.beancount
├── 2024/
│   ├── q1.beancount
│   ├── q2.beancount
│   ├── q3.beancount
│   └── q4.beancount
└── config/
    └── options.beancount
; main.beancount
include "config/options.beancount"
include "accounts.beancount"
include "commodities.beancount"
include "2024/q1.beancount"
include "2024/q2.beancount"
include "2024/q3.beancount"
include "2024/q4.beancount"

Nested Includes

; main.beancount
include "2024/all.beancount"

; 2024/all.beancount
include "q1.beancount"
include "q2.beancount"
include "q3.beancount"
include "q4.beancount"

Path Resolution

Relative Paths

Relative paths resolve from the including file's directory:

/home/user/finances/
├── main.beancount           ; include "yearly/2024.beancount"
└── yearly/
    └── 2024.beancount       ; include "q1.beancount"
    └── q1.beancount

In main.beancount:

include "yearly/2024.beancount"  ; → /home/user/finances/yearly/2024.beancount

In yearly/2024.beancount:

include "q1.beancount"  ; → /home/user/finances/yearly/q1.beancount

Absolute Paths

include "/shared/ledgers/common/accounts.beancount"

Path Normalization

Paths are normalized before resolution: - ./file.beancountfile.beancount - dir/../file.beancountfile.beancount

Include Behavior

Merging

Included files are merged into the main file:

  1. All directives are combined
  2. Directives are sorted chronologically
  3. Options from the main file take precedence

Processing Order

  1. Parse main file
  2. For each include, recursively parse included file
  3. Merge all directives
  4. Sort by date
  5. Apply plugins

Validation

The following conditions produce errors:

Condition Error Type
Include file not found LoadError ("File glob ... does not match any files")
Circular include detected LoadError

File Not Found

LoadError: File glob "missing.beancount" does not match any files

Circular Include

error: Circular include detected
  --> b.beancount:3:1
   |
 3 | include "a.beancount"
   | ^^^^^^^^^^^^^^^^^^^^^ creates cycle
   |
   = cycle: a.beancount → b.beancount → a.beancount

Option Scoping

Options are scoped to the top-level file:

; main.beancount
option "title" "Main Ledger"
include "other.beancount"
; Title is "Main Ledger"

; other.beancount
option "title" "Other Ledger"  ; Ignored for final ledger

Only options from the main file apply to the final result.

Security

Path Traversal Prevention

Include paths MUST NOT escape the allowed directory:

; REJECTED: Escapes ledger directory
include "../../../etc/passwd"
include "/etc/passwd"

See security/includes/path-traversal.md.

The behavior regarding symlinks is implementation-dependent. The Python beancount reference implementation follows symlinks by default.

Best Practices

File Organization

ledger/
├── main.beancount          ; Entry point, includes everything
├── accounts.beancount      ; Account definitions (open/close)
├── commodities.beancount   ; Commodity declarations
├── prices.beancount        ; Historical prices
├── config/
│   └── options.beancount   ; Options and plugins
└── transactions/
    ├── 2024/
    │   ├── 01-january.beancount
    │   ├── 02-february.beancount
    │   └── ...
    └── 2023/
        └── ...

Main File Structure

; main.beancount
;
; Personal Finance Ledger
; =======================

; Configuration
include "config/options.beancount"

; Account structure
include "accounts.beancount"
include "commodities.beancount"

; Historical prices
include "prices.beancount"

; Transactions by year
include "transactions/2023/all.beancount"
include "transactions/2024/all.beancount"

Year File

; transactions/2024/all.beancount
include "01-january.beancount"
include "02-february.beancount"
include "03-march.beancount"
include "04-april.beancount"
include "05-may.beancount"
include "06-june.beancount"
include "07-july.beancount"
include "08-august.beancount"
include "09-september.beancount"
include "10-october.beancount"
include "11-november.beancount"
include "12-december.beancount"

Glob Patterns

Standard Beancount does NOT support glob patterns:

; NOT SUPPORTED in standard Beancount
include "2024/*.beancount"

Some implementations may support globs as an extension.

Conditional Includes

Not directly supported. Use plugins or external tools for conditional logic:

; Standard approach: include different files for different environments
; Use separate main files that include the appropriate environment-specific files:

; main-production.beancount:
include "common.beancount"
include "production.beancount"

; main-development.beancount:
include "common.beancount"
include "development.beancount"

Note: There is no environment option in beancount. Use separate entry-point files or conditional includes via custom plugins.

Implementation Notes

  1. Resolve paths relative to including file
  2. Track include chain for cycle detection
  3. Normalize paths before checking cycles
  4. Apply security checks (path traversal, symlinks)
  5. Merge directives after all includes processed
  6. Report errors with full include chain context