Storage Backends¶
Hardy uses a dual storage model: one backend for bundle metadata (tracking state and timestamps) and another for bundle payload data (the actual bytes). The two backends can be mixed independently.
When no storage is configured, the server defaults to SQLite metadata and local-disk bundle data: a stock build persists to disk out of the box, writing to the platform default paths listed below, and will fail to start if those locations are unwritable (read-only filesystem, full volume). The non-persistent memory backends are never chosen by default — they must be selected explicitly, and the server logs a warning at startup when they are in use. The sqlite-storage and localdisk-storage build features that provide the default backends are enabled by default; a build that disables either feature refuses to start while the corresponding storage section is unconfigured (the backend must then be selected explicitly, e.g. type: memory), so the default never silently shifts to non-persistent storage.
storage — Cache Settings¶
| Key | Valid Values | Default | Description |
|---|---|---|---|
lru-capacity | Positive integer | 1024 | Maximum bundles in the in-memory LRU cache. |
max-cached-bundle-size | Positive integer (bytes) | 16384 | Maximum bundle size eligible for caching. Bundles larger than this bypass the cache. |
storage.metadata — Metadata Backend¶
| Key | Valid Values | Default | Description |
|---|---|---|---|
type | memory, sqlite, postgres | sqlite | Metadata storage engine. |
Memory¶
No persistence — metadata is lost on restart, and the server logs a warning at startup to say so. Suitable for testing only, and must be selected explicitly.
| Key | Valid Values | Default | Description |
|---|---|---|---|
type | memory | - | Selects the in-memory backend. |
max-bundles | Positive integer | 1048576 | Maximum entries held before the oldest are evicted. |
SQLite¶
The default for single-node deployments. Zero external dependencies. Uses WAL mode for concurrent read/write access. The database is created automatically on first run; migrations are applied automatically on upgrade.
| Key | Valid Values | Default | Description |
|---|---|---|---|
type | sqlite | - | Selects the SQLite backend. |
db-dir | Directory path | OS-dependent (see below) | Directory for the database file. |
db-name | Filename | metadata.db | Database filename. |
Default db-dir by platform:
| Platform | Default path |
|---|---|
| Linux | $HOME/.cache/hardy-sqlite-storage (XDG) |
| macOS | $HOME/Library/Caches/dtn.Hardy.hardy-sqlite-storage |
| Windows | C:\Users\<user>\AppData\Local\Hardy\hardy-sqlite-storage\cache |
Container (no $HOME) | /var/spool/hardy-sqlite-storage |
Example:
PostgreSQL¶
Recommended for production and multi-container deployments where the BPA container needs to be stateless. The database and tables are created automatically on first connection.
| Key | Valid Values | Default | Description |
|---|---|---|---|
type | postgres | - | Selects the PostgreSQL backend. |
database-url | PostgreSQL connection string | DATABASE_URL env var | Standard postgresql://user:pass@host:port/db connection URL; absent falls back to the DATABASE_URL environment variable, and startup fails if neither is set. |
max-connections | Positive integer | 20 | Maximum pooled connections. Scale deployments should size this to worker_threads * 2 or higher. |
min-connections | Non-negative integer | 2 | Idle connections kept alive in the pool. |
connect-timeout | Duration string (e.g. 30s) | 30s | How long to wait when acquiring a connection before erroring; must be greater than zero. |
idle-timeout | Duration string (e.g. 10m) | 10m | How long a connection may sit idle before it is closed; must be greater than zero. |
max-lifetime | Duration string (e.g. 30m) | 30m | Maximum lifetime of a pooled connection; must be greater than zero. |
poll-page-size | Positive integer | 64 | Rows fetched per page in keyset-paginated poll queries. |
Example:
storage.bundle — Bundle Data Backend¶
| Key | Valid Values | Default | Description |
|---|---|---|---|
type | memory, localdisk, s3 | localdisk | Bundle data storage engine. |
Memory¶
No persistence — bundle data is lost on restart, and the server logs a warning at startup to say so. Suitable for testing only, and must be selected explicitly.
| Key | Valid Values | Default | Description |
|---|---|---|---|
type | memory | - | Selects the in-memory backend. |
capacity | Positive integer (bytes) | 268435456 (256 MiB) | Total bytes held before least-recently-used bundles are evicted. |
min-bundles | Positive integer | 32 | Bundle count never evicted below, even when over the byte capacity. Must be at least 1. |
Local Disk¶
Stores bundles as individual files in a structured two-level hash directory layout (xx/yy/).
| Key | Valid Values | Default | Description |
|---|---|---|---|
type | localdisk | - | Selects the local disk backend. |
store-dir | Directory path | OS-dependent (see below) | Root directory for bundle files. |
fsync | true, false | true | Flush all changes to disk after each write. Set false for higher throughput at the risk of data loss on power failure. |
Default store-dir by platform:
| Platform | Default path |
|---|---|
| Linux | $HOME/.cache/hardy-localdisk-storage (XDG) |
| macOS | $HOME/Library/Caches/dtn.Hardy.hardy-localdisk-storage |
| Windows | C:\Users\<user>\AppData\Local\Hardy\hardy-localdisk-storage\cache |
Container (no $HOME) | /var/spool/hardy-localdisk-storage |
Example:
Amazon S3¶
Stores bundles in any S3-compatible object store (AWS S3, Google Cloud Storage, MinIO, Ceph, etc.). Credentials are provided via standard AWS mechanisms: environment variables (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY), IAM instance roles, or shared credentials file.
| Key | Valid Values | Default | Description |
|---|---|---|---|
type | s3 | - | Selects the S3 backend. |
bucket | Bucket name | Required | S3 bucket for bundle storage. |
prefix | Key prefix | (none) | Key prefix for all objects (no leading or trailing slash), for buckets shared with other applications. |
endpoint-url | URL | AWS default | S3 endpoint URL. Set for non-AWS S3-compatible stores (MinIO, GCS, etc.). |
region | AWS region string | AWS_DEFAULT_REGION / AWS_REGION env vars | AWS region for the bucket. |
force-path-style | true, false | false | Path-style addressing (http://host/bucket/key), required for MinIO and some S3-compatible stores. |
multipart-threshold | Non-negative integer (bytes) | 8388608 (8 MiB) | Bundle size above which multipart upload is used. Must be at least the part size, and at most 5 GiB (the S3 PutObject limit). |
multipart-part-size | Positive integer (bytes) | 8388608 (8 MiB) | Size of each multipart part. Must be between 5 MiB and 5 GiB (the S3 part bounds). |
Example (AWS S3):
Example (MinIO / self-hosted):
storage:
bundle:
type: s3
bucket: hardy-bundles
endpoint-url: "http://minio:9000"
region: us-east-1
force-path-style: true
Tip
S3 storage makes the BPA container fully stateless when combined with PostgreSQL metadata — ideal for auto-scaling Kubernetes deployments.
Choosing a Backend¶
| Deployment | Metadata | Bundle Data | Notes |
|---|---|---|---|
| Development / testing | Memory | Memory | No persistence, zero setup |
| Single node | SQLite | Local Disk | Default, no external dependencies |
| Production (single node) | SQLite | Local Disk + fsync | Durable, simple operations |
| Cloud / multi-node | PostgreSQL | S3 | Stateless BPA, scalable |
| Hybrid | PostgreSQL | Local Disk | When S3 latency is unacceptable |
See also:
- BPA Server -- core BPA configuration