Start a journal

by hand

(power users)

The simplest possible journal is just an empty file:
echo >2017.journal

The name doesn't matter much and can be changed later. One file per year is common, and so is a .journal or .hledger extension.

Record a transaction, using journal format:

$ cat >>2017.journal
  expenses:food     $10

Account names can be anything and you can change them later by search and replace. If you don't know what to choose, start with these five:
expenses, income, assets, liabilities, and equity,
perhaps with one extra subcategory as above.

by text editor

Write transactions in a text editor and save the file.

by add

Use the add command:
hledger add -f 2017.journal
enter one or more transactions


To avoid typing -f FILE every time, set the LEDGER_FILE environment variable. Eg:
echo "export LEDGER_FILE=~/finance/2017.journal" >> ~/.bash_profile && source ~/.bash_profile

Most examples here assume you have done this.

by hledger-iadd

ensure $LEDGER_FILE exists
hledger iadd
enter one or more transactions

by hledger-web

ensure $LEDGER_FILE exists
hledger web
wait for web browser to open
click "add transaction" or press "a"
enter a transaction, click ok or press enter

Track changes with version control

You don't need to do this, but it's a nice way to keep track of changes to your data.


Start tracking changes:
git init && git add 2017.journal && git commit 2017.journal -m "first commit"

View uncommitted changes: git status, git diff

Commit changes: git commit 2017.journal -m "updates"

View past commits: git log


darcs init && darcs add 2017.journal && darcs record 2017.journal -m "first commit"

darcs whatsnew, darcs diff

darcs record 2017.journal -m "updates"

darcs log


Example journal entries

Example hledger journal entries for various kinds of transaction.

A purchase:

2017/1/26 market
  expenses:food    $10

Convert CSV files

Here's a quick example of reading CSV data with hledger.

Say we have downloaded checking.csv from a bank for the first time:

"2012/3/23","TRANSFER TO SAVINGS","-10.00"

We tell hledger how to intepret this with a file named checking.csv.rules, using the CSV rules syntax. Eg:

# skip the first CSV line (headings)
skip 1

# use the first three fields in each CSV record as transaction date, description and amount respectively
fields   date, description, amount

# prepend $ to CSV amounts
currency $

# always set the first account to assets:bank:checking
account1 assets:bank:checking

# if the CSV record contains ‘SAVINGS’, set the second account to assets:bank:savings
# (if not set, it will be expenses:unknown or income:unknown)
  account2 assets:bank:savings

Now hledger can read this CSV file as journal data:

$ hledger -f checking.csv print
using conversion rules file checking.csv.rules
2012/03/22 DEPOSIT
    income:unknown             $-50.00
    assets:bank:checking        $50.00

    assets:bank:savings         $10.00
    assets:bank:checking       $-10.00

We might save this output as checking.journal, and/or merge it (manually) into the main journal file. We could also run other commands:

$ hledger -f checking.csv balance
using conversion rules file checking.csv.rules
              $50.00  assets:bank
              $40.00    checking
              $10.00    savings
             $-50.00  income:unknown

Here are more CSV rules examples.

Rewrite account names

Here's an example of using account aliases.

Say a sole proprietor has a personal.journal:

    expenses:food  $1

and a business.journal:

    expenses:office supplies  $1
    assets:business checking

So each entity (the business owner, and the business) has their own file with its own simple chart of accounts. However, at tax reporting time we need to view these as a single entity (at least in the US). In unified.journal, we include both files, and rewrite the personal account names to fit into the business chart of accounts,

alias expenses    = equity:draw:personal
alias assets:cash = assets:personal cash
include personal.journal
end aliases

include business.journal

Now we can see the data from both files at once, and the personal account names have changed:

$ hledger -f unified.journal print
2014/01/01                                    # from business.journal - no aliases applied
    expenses:office supplies            $1
    assets:business checking           $-1

2014/01/02                                    # from personal.journal
    equity:draw:personal:food            $1   # <- was expenses:food
    assets:personal cash                $-1   # <- was assets:cash

You can also specify aliases on the command line. This could be useful to quickly rewrite account names when sharing a report with someone else, such as your accountant:

$ hledger --alias 'my earning=income:business' ...

See also How to use another account separator character.

Use another account separator character

Timedot format makes me want to use dots (.) for separating account components, instead of colon (:). For example, instead of fos:hledger:timedot I'd like to write fos.hledger.timedot. We can use the powerful account aliases feature to rewrite account names before hledger's account name parser sees them.

In journal files, we can use an alias directive. Note the backslash which tells the regular expression engine it's a literal . not a wildcard:

alias /\./=:

2008/01/01 income  $1

Check that subaccounts are recognised:

$ hledger -f t.journal bal --no-elide
                  $1  assets
                  $1    bank
                  $1      checking
                 $-1  income
                 $-1    salary

Alias directives aren't supported in the timedot format,

fos.hledger.timedot  2
fos.ledger           1

so we would use the --alias command line option instead. The second backslash tells the shell that's a literal backslash, not a shell escape sequence:

$ hledger --alias /\\./=: -f t.timedot bal --no-elide
                3.00  fos
                2.00    hledger
                2.00      timedot
                1.00    ledger

Track investments

You can use hledger to track stock investments. In fact, the double-entry accounting is flexible enough to support most constellations you will come across. However, you may find that some transactions could be better supported. Caveats are: - hledger does not validate the cost basis during a sale. - historical mark-to-market performance is not supported (but the market value at one instant, like today, can be calculated)


Buying a stock

Let's go over a simple example using prices:

2017/1/1 opening balance
  (assets:depot)  $3000

2017/1/2 buy shares at $200
  ; let's assume no fees
  assets:shares   10 TSLA @ $200  ; transaction/purchase price

Some reports. We start with $3000. After the 1/2 purchase, we have $1000 remaining and 10 TSLA shares:

$ hledger -f t.j bal --flat -HD
Ending balances (historical) in 2017/01/01-2017/01/02:

               ||  2017/01/01     2017/01/02
 assets:depot  ||       $3000          $1000
 assets:shares ||           0        10 TSLA
               ||       $3000 $1000, 10 TSLA

Show the shares' value at cost, with -B/--cost:

$ hledger -f t.j bal --flat -HD -B
Ending balances (historical) in 2017/01/01-2017/01/02:

               ||  2017/01/01  2017/01/02
 assets:depot  ||       $3000       $1000
 assets:shares ||           0       $2000
               ||       $3000       $3000

Value reporting

Add the following to the journal file.

; market price, has jumped since yesterday's purchase!
P 2017/1/3 TSLA $250

Show the shares's value using the latest applicable market price, with -V/--value. A $500 capital gain is apparent in the totals:

$ hledger -f t.j bal --flat -HD -V
Ending balances (historical) in 2017/01/01-2017/01/02:

               ||  2017/01/01  2017/01/02
 assets:depot  ||       $3000       $1000
 assets:shares ||           0       $2500
               ||       $3000       $3500

There are still limitations in the value reporting that hledger can currently do. More information can be found in Github issue #131 and Github issue #329.

You may want to investigate the output after adding more prices to the journal file.

P 2017/1/1 TSLA $210
P 2017/1/4 TSLA $250
P 2017/1/8 TSLA $270

Selling a stock and tracking capital gains

At some point you will probably sell shares. It may seem intuitive to model such a sale as follows.

2017/1/4 sell shares at $250      ; NOTE: You probably want to model capital gains too; see below
  assets:shares   -10 TSLA @ $250  ; sell price

This leads to the following evolution

hledger -f t.j balance --flat -HD
Ending balances (historical) in 2017/01/01-2017/01/04:

               ||  2017/01/01     2017/01/02     2017/01/03  2017/01/04
 assets:depot  ||       $3000          $1000          $1000       $3500
 assets:shares ||           0        10 TSLA        10 TSLA           0
               ||       $3000 $1000, 10 TSLA $1000, 10 TSLA       $3500

You end up with the correct amount in your depot. At some point, however, you will have to report the capital gain that you realized with your sale. This gain is currently invisible. In fact, we have violated the double-entry principle and created money out of nowhere.

Let's report our sale in a different way.

2017/1/4 sell shares at $250
  assets:shares         -10 TSLA @ $200  ; cost basis (must be tracked by user!)
  assets:depot          $2500            ; cash proceeds
  revenue:capital_gains                  ; deduce profit

Now, the new $500 are correctly balanced with the capital gains account.

hledger -f t.j balance --flat -HD
Ending balances (historical) in 2017/01/01-2017/01/04:

                       ||  2017/01/01     2017/01/02     2017/01/03  2017/01/04
 assets:depot          ||       $3000          $1000          $1000       $3500
 assets:shares         ||           0        10 TSLA        10 TSLA           0
 revenue:capital_gains ||           0              0              0       $-500
                       ||       $3000 $1000, 10 TSLA $1000, 10 TSLA       $3000

Further reading

Save frequently used options

You can save frequently used options and arguments in an argument file, one per line, then reuse them via a @FILE argument on the command line. (hledger 1.4+)

Here's an example. I keep frequently-used options for quick daily reports in a file called simple.args. The name can be anything; I use a .args suffix so I can find these easily. Here's the content of simple.args:


The format is one command-line flag or command-line argument per line. Now if I write @simple.args in a hledger command line, it will be replaced by all of the above options/flags.

The options above are just an example, but in case you're wondering:

Ie they remove some detail, giving simplified reports which are easier for me to read at a glance.


Generate a balance report showing the simplified accounts:

$ hledger bal @simple.args

Start a live-updating hledger-ui showing the simplified asset accounts only:

$ hledger-ui --watch @simple.args assets

Options in the arguments file can be overridden by similar options later on the command line, in the usual way. Eg, to show just a little more account detail:

$ hledger bal @simple.args -3


Special characters in the arguments file may need to be quoted, depending on your shell (bash, fish etc.) They'll need one less level of quoting than on the command line. I think

$ hledger bal @simple.args

is equivalent to writing:

$ hledger bal "--alias=/:(business|personal):/=:" "--alias=/:(bank|cash|online):/=:" "--alias=/:bofi:/=:b" "--alias=/:unify:/=:u" "--alias=/:wf:/=:w" "-2" "cur:."

So in this example, using the bash shell, the | pipe character did not need to be quoted in the arguments file (and should not be).

Suppressing this feature

If you actually need to write an argument beginning with @, eg let's say you have an account pattern beginning with that character, you'll want a way to disable this feature. On unix systems at least, you can do that by inserting a -- (double hyphen) argument first. Eg:

$ hledger bal       # looks for additional arguments in the ./ file
$ hledger bal --    # matches account names containing ""

On windows, this double hyphen trick might require a hledger built with GHC 8.2+. (Let us know.)