Tariff Accounting Chaos: My Clients' COGS Just Jumped 25-40% and Nobody's Books Are Ready—How Are You Tracking Landed Costs?

My phone hasn’t stopped ringing since the new tariff schedules hit in April. I manage books for 22 small businesses and at least 8 of them import goods—either directly from China/EU or indirectly through domestic distributors who are now passing tariff surcharges through.

Here’s the problem in plain English: tariffs must be capitalized into inventory, not expensed immediately. Under GAAP (ASC 330-10-30-1), inventory cost is “the sum of applicable expenditures and charges directly or indirectly incurred in bringing an article to its existing condition and location.” That means the 25% tariff on a $10,000 shipment of electronics components isn’t a $2,500 expense—it’s $2,500 added to inventory value that hits COGS only when those units sell.

Most of my clients on QuickBooks are doing it wrong. They’re expensing tariff payments immediately (because that’s when the cash leaves), which overstates COGS in the import month and understates it when inventory actually sells. For a business with thin margins, this distortion can make a profitable month look like a loss and vice versa.

The Landed Cost Nightmare

Getting the “true cost” of imported goods requires tracking what’s called landed cost—the total of:

  • Purchase price from supplier
  • Freight/shipping charges
  • Insurance during transit
  • Customs duties and tariffs (10% to 145% depending on country/product in 2026)
  • Broker fees and handling charges

QuickBooks has a “landed cost” feature but it’s clunky—you have to manually allocate costs across line items, and when tariff rates change mid-shipment (which has happened THREE TIMES this year), recalculating is a nightmare.

Where I Think Beancount Has an Edge

I’ve been moving my own practice’s books to Beancount over the past year, and I’m now seriously considering it for my import-heavy clients. Here’s why:

1. Metadata tagging for tariff components

2026-04-02 * "Acme Electronics" "Q2 component shipment"
  tariff-rate: "25%"
  hs-code: "8542.31"
  origin-country: "CN"
  shipment-id: "ACM-2026-0402"
  Assets:Inventory:Electronics:Components  12,500.00 USD
    { {10000.00 USD, "base-cost"} }
  Expenses:Shipping:Freight                   800.00 USD
  Expenses:Import:Tariff                    2,500.00 USD
  Expenses:Import:BrokerFees                  200.00 USD
  Liabilities:AccountsPayable:AcmeElec    -12,500.00 USD
  Liabilities:AccountsPayable:CustomsBroker -3,000.00 USD

Wait—actually, if I’m capitalizing properly, those tariff and freight costs should be part of inventory, not separate expenses. Let me rethink this…

2. Python scripts for tariff rate changes

When the tariff rate on HS code 8542.31 changed from 25% to 34% mid-March, I could theoretically write a script that:

  • Scans all open purchase orders with that HS code
  • Recalculates landed cost at new rate
  • Generates adjustment entries
  • Flags inventory that was valued at old rate

Try doing THAT in QuickBooks.

3. Git history as audit trail

Every tariff rate change, every recalculation, every adjustment—all tracked in Git commits with timestamps. When the IRS asks “why did your client’s inventory valuation change on March 15?” I can show the exact commit.

My Questions for the Community

  1. Has anyone built a Beancount account structure specifically for import businesses? I’m struggling with whether tariffs should be a sub-account under inventory (Assets:Inventory:TariffComponent) or tracked via metadata on the inventory lot.

  2. Lower of cost or net realizable value (LCNRV): The Fed data shows businesses are only passing about half their tariff increases to customers. That means some inventory may need to be written down. Has anyone automated LCNRV testing in Beancount?

  3. LIFO vs FIFO considerations: In an inflationary tariff environment, LIFO could reduce taxable income by matching current high-cost inventory against revenue first. But Beancount’s lot tracking is FIFO by default. Has anyone implemented LIFO cost flow in Beancount?

  4. For fellow bookkeepers: How are you explaining tariff accounting to clients who just want to expense everything? I’ve had two clients push back saying “my old bookkeeper just put it in Expenses:Tariffs and called it a day.”

This feels like the biggest accounting challenge since COVID PPP loan forgiveness tracking. Would love to hear how others are handling it.


Disclosure: I’m not a CPA—always consult your tax professional for specific tariff treatment advice.

Bob, good on you for flagging this—I’m seeing the same panic across my CPA practice. Let me address your questions from a compliance perspective because getting this wrong has real consequences.

The Capitalization Question: You Caught Your Own Mistake

Your instinct to self-correct was exactly right. In your example, the tariff ($2,500), freight ($800), and broker fees ($200) should all be capitalized into inventory, not expensed separately. Here’s how I’d restructure that entry:

2026-04-02 * "Acme Electronics" "Q2 component shipment - landed cost"
  tariff-rate: "25%"
  hs-code: "8542.31"
  origin-country: "CN"
  shipment-id: "ACM-2026-0402"
  Assets:Inventory:Electronics:Components  13,500.00 USD
  Liabilities:AccountsPayable:AcmeElec   -10,000.00 USD
  Liabilities:AccountsPayable:CustomsBroker -3,500.00 USD

The $13,500 represents the full landed cost: $10,000 base + $2,500 tariff + $800 freight + $200 broker fees. When you sell those components, the entire $13,500 flows through COGS. This is what ASC 330 requires.

Why “Expense It All” Is a Compliance Risk

For your clients pushing back: expensing tariffs immediately can trigger IRS scrutiny. Here’s what I tell my clients:

  1. Uniform Capitalization Rules (UNICAP, IRC §263A) require businesses with average annual gross receipts over $29 million to capitalize all indirect costs, including tariffs. Even smaller businesses that maintain inventories must capitalize direct costs of acquisition.

  2. Misstating inventory = misstating taxable income. If you expense $50K in tariffs that should be capitalized, you’re understating inventory by $50K and overstating deductions. That’s the kind of discrepancy that flags automated IRS matching.

  3. Audit defense: When (not if) the IRS starts auditing tariff treatment—and they will, given the magnitude of these tariffs—“my old bookkeeper expensed it” is not a defense.

On the LIFO Question

LIFO is getting a LOT of attention right now. RSM’s guidance suggests many businesses may be able to increase COGS deductions by adopting or modifying their LIFO method in an inflationary environment. But two caveats:

  • LIFO requires IRS Form 970 to elect, and the election is binding. You can’t switch back to FIFO next year when tariffs drop.
  • LIFO conformity rule: If you use LIFO for tax, you must use it for financial reporting too. This can make your financial statements look worse to lenders and investors.

For Beancount implementation: you’d need a custom plugin that tracks lots by acquisition date but selects the MOST RECENT lot for cost relief instead of the oldest. Not trivial, but I’ve seen similar plugins for investment lot selection.

My Recommendation

For Bob’s import clients, I’d suggest:

  1. Separate “tariff staging” accounts in your chart: Assets:Inventory:InTransit:TariffHolding where tariff payments land before being allocated to specific inventory lots
  2. Allocation journal entries when goods are received and inspected that roll tariff costs into the inventory lot
  3. Monthly reconciliation of tariff payments vs. customs broker invoices (these often don’t match due to estimated vs. actual duty rates)

The metadata approach you described is powerful—HS codes as metadata means you can query “show me all inventory exposed to China tariff rate changes” in seconds. That’s not possible in QuickBooks without custom reporting.

Jumping in here because the tax implications of tariff misclassification are something I deal with daily as an Enrolled Agent—and they’re more serious than most bookkeepers realize.

The IRS Is Already Watching

I spent 8 years at the IRS before going private, and I can tell you: when tariff revenue jumps from $80 billion to $300+ billion in a single year, the Service notices. They’re already updating their audit selection algorithms to flag businesses with:

  • Sudden spikes in “Expenses:Tariffs” or “Expenses:Import Duties” line items (indicating possible incorrect expensing)
  • Inventory valuations that don’t track with reported import volumes
  • COGS-to-revenue ratios that shifted dramatically without corresponding price increases

Alice nailed the UNICAP point. But let me add something most people miss: even businesses BELOW the $29M threshold must capitalize tariffs if they maintain inventories for sale. IRC §471 requires all businesses with inventories to use an inventory method that “clearly reflects income.” Expensing $50K in tariffs when you still have $200K of that inventory sitting in your warehouse does NOT clearly reflect income.

The Section 301 Exclusion Trap

Here’s a landmine I’ve seen three clients step on already in 2026: some tariffs have retroactive exclusions. The USTR periodically grants exclusions from Section 301 tariffs for specific products. If your client paid 25% tariff on a product that later gets excluded retroactively, they’re entitled to a refund—but ONLY if they can document:

  1. The exact HS code of each imported product
  2. The date each tariff payment was made
  3. The customs entry number for each shipment
  4. Proof the product qualifies for the exclusion

Bob’s metadata tagging approach (HS codes, origin country, shipment IDs) would make exclusion refund claims almost trivial. One BQL query: “show me all inventory with hs-code matching excluded codes and tariff-rate > 0.” Compare that to digging through boxes of customs broker invoices—which is what most of my clients are doing right now.

LIFO Warning from a Tax Perspective

On the LIFO question: Alice mentioned Form 970 and the conformity rule, which are correct. But there’s another angle—LIFO liquidation risk. If a business adopts LIFO now because tariffs are inflating costs, but then tariffs are reduced or eliminated in 2027-2028 (possible under a new trade deal or administration change), they could face LIFO liquidation. That means old, low-cost layers suddenly flow through COGS, creating a massive taxable income spike in a future year.

I’m advising most of my import clients to stay on FIFO and instead focus on:

  • Maximizing Section 199A deductions where applicable
  • Timing inventory purchases to manage taxable income across quarters
  • Documenting tariff costs meticulously for potential refund claims

What I Wish Beancount Had

For my practice, the dream Beancount tariff workflow would be:

  1. Tariff rate schedule file (YAML or CSV) that maps HS codes to current duty rates, updated when rates change
  2. Validation plugin that checks: does the tariff amount on this transaction match the rate schedule for this HS code? Flag mismatches.
  3. Exclusion tracker that flags inventory eligible for retroactive exclusion refunds
  4. Quarterly estimated tax impact report that calculates how tariff capitalization affects estimated tax payments

If anyone’s building something like this, I’d love to collaborate. This is exactly the kind of structured, auditable tracking that plain text accounting was made for.

Great thread, and incredibly timely. I want to share a practical angle from someone who’s actually been tracking import costs in Beancount for my small side business (handmade furniture using imported hardwoods) for the past two years.

What I Learned the Hard Way

When tariffs on Canadian lumber first spiked in 2024, I made exactly the mistake Bob described—I expensed the duties immediately. It was only when I sat down with my accountant at tax time that I realized my P&L was showing losses in months I imported wood and huge profits in months I sold finished furniture. My actual margins were fine; my timing was completely wrong.

Here’s the account structure I eventually settled on, and it’s held up well through three tariff rate changes:

; Chart of accounts for import tracking
2024-01-01 open Assets:Inventory:RawMaterials:Hardwood
2024-01-01 open Assets:Inventory:InTransit:Hardwood
2024-01-01 open Assets:Inventory:LandedCostAccrual
2024-01-01 open Expenses:COGS:Materials
2024-01-01 open Expenses:COGS:TariffComponent

The key insight: I use a two-step booking process.

Step 1: When goods ship (I get the commercial invoice)

2026-03-15 * "Brazilian Hardwood Co" "Ipe decking shipment in transit"
  origin-country: "BR"
  hs-code: "4407.29"
  estimated-tariff-rate: "27.5%"
  Assets:Inventory:InTransit:Hardwood    8,000.00 USD
  Liabilities:AccountsPayable:BHCo     -8,000.00 USD

Step 2: When goods clear customs (I get the customs broker statement with actual duties)

2026-03-22 * "US Customs / Pacific Brokerage" "Duty on Ipe shipment"
  hs-code: "4407.29"
  actual-tariff-rate: "27.5%"
  customs-entry: "E26-0398541"
  Assets:Inventory:InTransit:Hardwood   -8,000.00 USD
  Assets:Inventory:RawMaterials:Hardwood 11,150.00 USD
  Liabilities:AccountsPayable:PacBrokerage -3,150.00 USD

That $11,150 is the full landed cost: $8,000 base + $2,200 tariff (27.5%) + $650 freight + $300 broker fees. The inventory sits at landed cost until I use it in a project.

The Tariff Rate Change Script I Actually Use

Nothing fancy—just a Python script that reads a CSV of current tariff rates and compares against metadata in my ledger:

# Simplified version of my tariff_checker.py
import csv
from beancount import loader

def check_tariff_rates(ledger_file, rates_file):
    entries, errors, options = loader.load_file(ledger_file)
    current_rates = {}
    with open(rates_file) as f:
        for row in csv.DictReader(f):
            current_rates[row["hs_code"]] = float(row["rate"])
    
    for entry in entries:
        if hasattr(entry, "meta") and "hs-code" in entry.meta:
            hs = entry.meta["hs-code"]
            booked_rate = entry.meta.get("actual-tariff-rate", "")
            if hs in current_rates and booked_rate:
                # Flag if rate has changed since booking
                if float(booked_rate.strip("%")) != current_rates[hs] * 100:
                    print(f"RATE CHANGE: {entry.date} {hs} "
                          f"booked at {booked_rate}, "
                          f"current rate: {current_rates[hs]*100}%")

It’s not production-grade, but it saved me $340 last month when it flagged that one of my HS codes had been retroactively excluded from Section 301 tariffs. Without the metadata, I would never have caught it.

Answering Bob’s LCNRV Question

For lower of cost or NRV testing, here’s my simple approach: I maintain a prices.beancount file with my selling prices, and I wrote a BQL query that compares inventory cost to expected sale price minus completion costs:

SELECT account, cost(position), meta("hs-code")
WHERE account ~ "Assets:Inventory:RawMaterials"
  AND cost(position) > 0

Then I manually compare against my price list. It’s not automated NRV testing, but for a small operation it takes about 20 minutes quarterly. For someone with 22 clients like Bob… yeah, you’d want to automate that.

The Real Win: Scenario Modeling

What I love about having all this in plain text is scenario modeling. When the new tariff schedules were announced in March, I copied my ledger, updated the tariff rates in my CSV, ran a script, and within 10 minutes knew:

  • My material costs would increase ~$4,200 per quarter
  • I needed to raise furniture prices by 12% to maintain margins
  • Two pending orders would be unprofitable at current quoted prices

Try doing that analysis in QuickBooks before calling your customer to renegotiate pricing. By the time you’ve figured it out, the order is already shipped.

For anyone starting from scratch with tariff tracking in Beancount: start with the metadata. Even if your account structure isn’t perfect yet, having HS codes and origin countries on every import transaction gives you the queryability you need when (not if) tariff rates change again.

This thread is gold. I’m coming at this from a different angle—I’m not a professional bookkeeper, but I track my personal finances obsessively in Beancount for FIRE planning, and tariffs are hitting my household budget in ways I didn’t expect.

The Consumer Side: Tariffs You Don’t See on Any Invoice

The Tax Foundation estimates tariffs amount to an average $1,500 tax increase per US household in 2026. But unlike Bob’s clients who see tariff line items on customs invoices, consumers absorb tariffs invisibly through price increases. My grocery bill is up 8% since January. Electronics are up 12-15%. Even domestic goods are more expensive because domestic manufacturers have raised prices to match the tariff-inflated imported competition.

For FIRE tracking, this matters enormously: my projected annual expenses just increased by $3,000-4,000, which at a 4% withdrawal rate means I need an additional $75,000-100,000 in my FIRE target.

Here’s how I’m tracking the tariff impact in my personal Beancount ledger:

; Tag tariff-impacted purchases for analysis
2026-04-01 * "Best Buy" "New laptop - tariff-inflated price"
  tariff-impact: "estimated-15%"
  pre-tariff-estimate: "870 USD"
  Expenses:Electronics:Computing    1,000.00 USD
  Liabilities:CreditCard:Chase     -1,000.00 USD

I tag purchases where I can estimate the tariff component, then run quarterly analysis:

SELECT account, sum(cost(position)), count(position)
WHERE meta("tariff-impact") != ""
  AND date >= 2026-01-01

Over Q1 2026, I estimate I paid roughly $780 in embedded tariffs across electronics, clothing, and household goods. Annualized, that’s $3,120—almost exactly matching the Tax Foundation’s per-household estimate.

For Bob’s Clients: The Pricing Pass-Through Problem

Here’s the data point that should terrify every import-dependent small business: Federal Reserve Bank of Boston research shows businesses expected to pass on only about half their cost increases to customers in 2025. That means the other half comes directly out of margins.

If your client imports $500K in goods annually and faces a 25% tariff ($125K), they might only be able to pass $62K to customers through price increases. The remaining $63K is margin compression—and if their net margin was 10% on $2M revenue ($200K profit), that $63K tariff absorption just eliminated 31% of their profit.

This is why the LCNRV issue Mike mentioned is so critical. If you’re holding inventory that cost $13,500 landed (including tariffs) but can only sell it for $12,000 because customers won’t accept the full price increase, you have a write-down. And you need to recognize that write-down in the period you become aware of it, not when you eventually sell at a loss.

The Macro Dashboard I Built

I built a Beancount-adjacent Python dashboard that tracks tariff exposure across my portfolio:

  1. Direct exposure: My import-tagged expenses (described above)
  2. Investment exposure: How much of my stock portfolio is in companies with significant China/EU supply chain exposure (scraped from 10-K filings, tagged as metadata on my investment positions)
  3. FIRE impact: Rolling 12-month expense trend with tariff components highlighted, projected forward to my FI target date

The tariff volatility has actually pushed back my projected FI date by 8 months. That’s real and quantifiable—and I only know it because I track everything in Beancount with enough metadata to slice the data this way.

Quick Thought on Tina’s Plugin Idea

Tina’s wish list for a tariff rate schedule + validation plugin is absolutely buildable. The USITC publishes the Harmonized Tariff Schedule as downloadable data. You could:

  1. Parse the HTS data into a CSV/YAML lookup table
  2. Write a Beancount plugin that validates hs-code metadata against the lookup
  3. Flag entries where the booked tariff rate doesn’t match the current HTS rate
  4. Generate a “tariff exposure report” showing total inventory value at risk of rate changes

I’d contribute to this if someone sets up a GitHub repo. The combination of structured metadata + Python scripting + version-controlled data is exactly what makes Beancount the right tool for this particular chaos.