Skip to content

Cache Configuration Guide

FinFocus includes an optional BoltDB-backed cache that stores cost query results locally. When enabled, repeated runs against the same resources return results from disk instead of making live plugin calls, cutting latency significantly for large stacks.

The cache is disabled by default. You opt in by setting a positive TTL value.

Target Audience: End Users, DevOps Engineers, CI/CD Operators

Prerequisites:

Learning Objectives:

  • Enable and configure the cost cache
  • Understand cache key structure and TTL behaviour
  • Disable or invalidate the cache when needed
  • Troubleshoot stale or corrupted cache entries

Estimated Time: 5 minutes



Enable the cache in under 2 minutes.

Edit ~/.finfocus/config.yaml (global) or your project’s .finfocus/config.yaml:

# yaml-language-server: $schema=https://rshade.github.io/finfocus/schemas/config.json
cost:
cache:
enabled: true
ttl_seconds: 3600 # 1 hour; 0 disables the cache
directory: "" # empty = auto-resolve
Terminal window
finfocus cost projected --pulumi-json plan.json
Terminal window
finfocus cost projected --pulumi-json plan.json

Expected Output (second run):

RESOURCE ADAPTER MONTHLY CURRENCY NOTES
aws:ec2/instance:Instance aws-public (cached) $73.00 USD t3.medium
aws:rds/instance:DbInstance aws-public (cached) $146.00 USD db.t3.medium

The (cached) suffix on the Adapter column confirms results came from disk.


Cache settings belong under the cost.cache key in either:

  • ~/.finfocus/config.yaml - global default, applies to all projects
  • $PROJECT/.finfocus/config.yaml - project-local override (takes precedence)
OptionTypeDefaultRequiredDescription
enabledbooleanfalseNoMaster switch. false disables caching entirely.
ttl_secondsinteger3600NoSeconds until a cached entry expires. 0 disables.
directorystring""NoExplicit cache directory path. Empty = auto.

Note: When enabled: true is set without specifying ttl_seconds, the default of 3600 seconds (1 hour) applies automatically. Setting ttl_seconds: 0 disables expiration even when enabled: true.

Override the TTL for a single run without changing config:

Terminal window
finfocus cost projected --cache-ttl 1800 --pulumi-json plan.json
# 0 disables the cache for this run
finfocus cost projected --cache-ttl 0 --pulumi-json plan.json
VariableDescriptionExample
FINFOCUS_CACHE_TTLOverride TTL in seconds (integer)7200
FINFOCUS_CACHE_TTL_SECONDSFallback alias for FINFOCUS_CACHE_TTL7200
FINFOCUS_CACHE_DIROverride cache directory/tmp/finfocus-cache

Precedence (highest to lowest): --cache-ttl flag > FINFOCUS_CACHE_TTL env > cost.cache.ttl_seconds config > built-in default (3600 when enabled).

When directory is empty, FinFocus resolves the cache location in this order:

  1. FINFOCUS_CACHE_DIR environment variable
  2. cost.cache.directory config value
  3. Project-local .finfocus/cache/ (when a Pulumi.yaml is found)
  4. ~/.finfocus/cache/

The database file is always named cache.db inside the resolved directory.


The cache uses BoltDB, a single-file embedded key-value store. No external database process is required.

~/.finfocus/cache/
└── cache.db # Single BoltDB file containing all cached data

The database contains three buckets, one per cost operation:

BucketKey FormatScope
projectedprojected/{provider}/{type}/{region}/{sku}Per resource
actualactual/{adapter}/{start}/{end}/{groupBy}/...Per query
recommendationsrecommendations/{provider}/{type}/{region}Per resource

Projected costs are cached per individual resource, so changing one resource only invalidates that resource’s entry. Actual cost queries are cached as a whole (the full query including time range and filters forms the key).

  • Expiration is lazy: entries are checked on read and discarded if past their TTL.
  • A startup cleanup pass removes all expired entries when the cache is opened.
  • Setting ttl_seconds: 0 or enabled: false disables the cache; no file is written.

Cache failures never block cost operations. If the cache file cannot be opened or a read fails, FinFocus logs a warning and continues with live plugin calls. If the file is corrupted, FinFocus automatically deletes and recreates it.

cost projected, cost actual, cost recommendations, cost estimate, overview, and analyzer serve all participate in caching when enabled.


Use Case: Speed up repeated cost projected runs during active development.

Configuration (in $PROJECT/.finfocus/config.yaml):

cost:
cache:
enabled: true
ttl_seconds: 3600

Usage:

Terminal window
# First run - fetches from plugins, populates cache
finfocus cost projected --pulumi-json plan.json
# Second run - returns cached results
finfocus cost projected --pulumi-json plan.json

Use Case: Force fresh data for a specific run without changing global config.

Terminal window
# Bypass cache entirely for this run
finfocus cost projected --cache-ttl 0 --pulumi-json plan.json
# Use a shorter TTL of 5 minutes for this run
finfocus cost projected --cache-ttl 300 --pulumi-json plan.json

Use Case: Always fetch live pricing data in automated pipelines.

Terminal window
# In your CI pipeline script
finfocus cost projected --cache-ttl 0 --pulumi-json plan.json

Alternatively, set the environment variable for the entire job:

env:
FINFOCUS_CACHE_TTL: "0"
steps:
- run: finfocus cost projected --pulumi-json plan.json

Symptoms: Running with fresh plugin data still shows (cached) results.

Cause: TTL is larger than expected, or the system clock changed.

Solution: Force a fresh run by passing --cache-ttl 0, then restore the desired TTL:

Terminal window
finfocus cost projected --cache-ttl 0 --pulumi-json plan.json

Symptoms: Cost output does not reflect a resource type or SKU change.

Cause: Projected cost cache is keyed by provider/type/region/sku. If you changed an input that is part of the key (e.g., instance type), the old key is no longer matched and the new key is a cache miss - fresh data is fetched automatically. If you changed a field that is NOT part of the key (e.g., tags), the cached entry is reused.

Solution: Use --cache-ttl 0 for a single run or reduce ttl_seconds in config.

Symptoms: Errors mentioning bbolt, unexpected EOF, or invalid database.

Cause: The cache.db file was corrupted (e.g., process killed mid-write).

Solution: FinFocus auto-recovers by deleting and recreating the file. If auto-recovery does not trigger, delete the file manually:

Terminal window
rm ~/.finfocus/cache/cache.db

Symptoms: Warning like failed to open cache: permission denied.

Solution: Check ownership of the cache directory:

Terminal window
ls -la ~/.finfocus/cache/
# Fix ownership if needed
chown -R $USER ~/.finfocus/cache/

Related Guides:

CLI Reference:

Configuration Reference:


Last Updated: 2026-02-17 FinFocus Version: v0.3.1 Feedback: Open an issue to improve this guide