blog

Product update: export transactions from an account as CSV easily plus beanhub-import input rules improvement

March 10, 2025
beanhub-import
csv
export
new-feature

Yay! It’s tax season once again. Well, says nobody. While we all are not fans of it, unfortunately, there’s no way around it. But at least, with the right tools, we can make life much easier. Today, we are glad to announce the new CSV file exporting buttons feature.

Screenshot of account CSV transactions export button

With that, you can easily export transactions from your accounts for further processing.

Improvement of beanhub-import, no more repetitive input rules with loop

In addition to the exporting button, we have also improved our open-source beanhub-import tool and released a new 1.1.1 version. There are two major improvements: the first solves the repetitive input rules problems. Over time, by importing transactions from various accounts, you will end up with more and more input rules in the .beanhub/imports.yaml file. Like this:

inputs:
  - match: "import-data/connect/Wells Fargo/CHECKING ...1234/*.csv"
    config:
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: Assets:Bank:US:WellsFargo:Checking
          amount:
            number: "{{ -amount }}"
            currency: "{{ currency | default('USD', true) }}"
  - match: "import-data/connect/Wells Fargo/SAVING ...5678/*.csv"
    config:
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: Assets:Bank:US:WellsFargo:Saving
          amount:
            number: "{{ -amount }}"
            currency: "{{ currency | default('USD', true) }}"
  - match: "import-data/connect/American Express/Blue Cash Everyday®/*.csv"
    config:
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: Liabilities:CreditCard:US:AMEXBlueCashEveryday
          amount:
            number: "{{ -amount }}"
            currency: "{{ currency | default('USD', true) }}"

They mostly look the same, but the match path and pending account are the main differences. To solve the problem, we introduced the new optional loop field that allows you to create multiple similar input rules with different variables. With the new syntax, you can rewrite the verbose repetitive input syntax above with the loop field like this:

inputs:
  - match: "import-data/connect/{{ match_path }}"
    config:
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: "{{ input_account }}"
          amount:
            number: "{{ -amount }}"
            currency: "{{ currency | default('USD', true) }}"
    loop:
      - match_path: "Wells Fargo/CHECKING ...1234/*.csv"
        input_account: Assets:Bank:US:WellsFargo:Checking
      - match_path: "Wells Fargo/SAVING ...5678/*.csv"
        input_account: Assets:Bank:US:WellsFargo:Saving
      - match_path: "American Express/Blue Cash Everyday®/*.csv"
        input_account: Liabilities:CreditCard:US:AMEXBlueCashEveryday

Much better, right? Please read the document about Loop to learn more about it.

The new input filter

When we migrated some of our handwritten Beancount books to use beanhub-import, we had a problem. The handwritten transactions were already there, and we didn’t want to write new import rules for generating transactions and replace the existing ones just for the sake of using the new import system. Obviously, we need a way to filter transactions at the source and only consume the ones we are interested in. In this case, it would be only the transactions after the cutoff day we started using beanhub-import. With that in mind, we introduced the new input filter field. Here’s an example to filter transactions from the input file only after or on March 10th, 2025:

inputs:
  - match: "import-data/connect/{{ match_path }}"
    config:
      default_file: "books/{{ date.year }}.bean"
      prepend_postings:
        - account: "{{ input_account }}"
          amount:
            number: "{{ -amount }}"
            currency: "{{ currency | default('USD', true) }}"
    filter:
      - field: date
        op: ">="
        value: "2025-03-10"
    loop:
      - match_path: "Wells Fargo/CHECKING ...1234/*.csv"
        input_account: Assets:Bank:US:WellsFargo:Checking
      - match_path: "Wells Fargo/SAVING ...5678/*.csv"
        input_account: Assets:Bank:US:WellsFargo:Saving
      - match_path: "American Express/Blue Cash Everyday®/*.csv"
        input_account: Liabilities:CreditCard:US:AMEXBlueCashEveryday

You can learn more about the new filter field by reading the documents here.

The schema of beanhub-import import rules is stable now

As you may have noticed, we mentioned on the repository README page that the beanhub-import project is in rapid development cycles and that the schema may not be stable. That’s not the case anymore, and we have removed that warning from the project. We have been using the import system internally for all of our personal and company books. It works great so far. With the new loop and filter features, it meets almost all our requirements.

We know there are still corners that need improvement, but the overall structure and flow are very stable. We haven’t introduced any breaking changes since the beginning of the project. Moving forward, we will try our best to maintain backward compatibility while introducing new features. And if there are any breaking changes, we will deprecate the legacy stuff first for a while before introducing the breaking changes. You can now rely on it without worrying about rapid changes.

Finally

As always, we value customer feedback and keep improving BeanHub piece by piece. If you think there’s anything we can improve, or if you have any feedback, please reach out to us at support@beanhub.io.