---
title: "HitKeep S3 Backups and Object Storage | HitKeep"
description: "Configure HitKeep backups and archives for AWS S3 and S3-compatible object storage such as MinIO, Cloudflare R2, and Backblaze B2."
canonical: "https://hitkeep.com/guides/data/s3-backups/"
---

# HitKeep S3 Backups and Object Storage

HitKeep can write both backups and retention archives to S3-compatible object storage.

Use this guide when you want:

- off-host backups
- object storage retention instead of local disks
- MinIO or R2 in self-hosted environments

## What Uses S3

Two separate paths can point at S3-compatible storage:

- `HITKEEP_BACKUP_PATH` for `EXPORT DATABASE` snapshots
- `HITKEEP_ARCHIVE_PATH` for retention Parquet archives

They share the same S3 credential configuration.

Live `HITKEEP_DB_PATH` and `HITKEEP_DATA_PATH` values must remain on local writable storage. S3 is the backup, restore, and retention-archive plane; HitKeep does not open live DuckDB database files from S3.

## Required Settings

At minimum:

```
export HITKEEP_BACKUP_PATH=s3://my-bucket/hitkeep/backups
export HITKEEP_S3_REGION=eu-central-1
```

Static credentials:

```
export HITKEEP_S3_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export HITKEEP_S3_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
```

Or rely on the AWS credential chain for IAM roles, ECS task roles, or similar.

## Which path should use S3?

Use S3 for backups when the server disk is not enough protection. Use S3 for archives when retention rules move older analytics rows out of the live DuckDB files.

| Need | Set this | Result |
| --- | --- | --- |
| Off-host snapshots | HITKEEP_BACKUP_PATH=s3://... | Built-in backup snapshots are written to object storage |
| Long-term Parquet archives | HITKEEP_ARCHIVE_PATH=s3://... | Retention archives are written to object storage |
| Both | Set both paths | Backups and archives share S3 credentials but use separate prefixes |

Keep backup prefixes and archive prefixes separate. Backups are restore points. Archives are reporting/history files created by retention policy.

## AWS S3 Example

```
export HITKEEP_DATA_PATH=/var/lib/hitkeep/data
export HITKEEP_BACKUP_PATH=s3://my-analytics-bucket/hitkeep/backups
export HITKEEP_BACKUP_INTERVAL=60
export HITKEEP_BACKUP_RETENTION=24
export HITKEEP_S3_REGION=eu-central-1

./hitkeep
```

## MinIO Example

```
export HITKEEP_BACKUP_PATH=s3://hitkeep/backups
export HITKEEP_ARCHIVE_PATH=s3://hitkeep/archive
export HITKEEP_S3_ACCESS_KEY_ID=minioadmin
export HITKEEP_S3_SECRET_ACCESS_KEY=minioadmin
export HITKEEP_S3_ENDPOINT=localhost:9000
export HITKEEP_S3_URL_STYLE=path
export HITKEEP_S3_USE_SSL=false
export HITKEEP_S3_REGION=us-east-1

./hitkeep
```

## Cloudflare R2 Example

```
export HITKEEP_BACKUP_PATH=s3://my-r2-bucket/hitkeep/backups
export HITKEEP_S3_ACCESS_KEY_ID=YOUR_R2_ACCESS_KEY
export HITKEEP_S3_SECRET_ACCESS_KEY=YOUR_R2_SECRET_KEY
export HITKEEP_S3_ENDPOINT=YOUR_ACCOUNT_ID.r2.cloudflarestorage.com
export HITKEEP_S3_REGION=auto

./hitkeep
```

## Bucket Layout

Built-in backups use this logical layout:

```
s3://bucket/hitkeep/backups/
  shared/
    2026-03-08T120000Z/
  tenants/
    default-or-team-id/
      2026-03-08T120000Z/
```

Retention archives use your configured archive prefix and write Parquet objects there.

One timestamp is a valid restore point only when the shared export and every tenant export complete. The backup status reports the run as failed if any database fails. Object storage may retain objects already written under a failed timestamp because S3 prefixes are not transactional; do not restore that timestamp, and let your bucket lifecycle policy expire abandoned partial prefixes.

## Retention on S3

For local backup destinations, HitKeep prunes older snapshots automatically based on `HITKEEP_BACKUP_RETENTION`.

For S3 destinations, prefer provider-side lifecycle rules:

- keep recent snapshots hot
- expire old snapshots automatically
- move older archives to cheaper storage classes if your provider supports it

That keeps retention behavior transparent and avoids a surprise cost curve in object storage.

## Restore From S3

When restoring from S3, provide the exact snapshot timestamp:

```
./hitkeep recover restore-backup \
  -from s3://my-analytics-bucket/hitkeep/backups \
  -snapshot 2026-03-08T120000Z \
  -s3-region eu-central-1 \
  -yes
```

Unlike local snapshots, HitKeep does not currently auto-discover “latest” from S3.

## Common Mistakes

- Using only `HITKEEP_ARCHIVE_PATH` and assuming backups are enabled
- Backing up only the shared DB while teams are enabled
- Forgetting `HITKEEP_S3_URL_STYLE=path` for MinIO-style endpoints
- Using HTTP endpoints without `HITKEEP_S3_USE_SSL=false`
- Assuming S3 restore can infer the latest snapshot automatically
- Treating a timestamp from a failed backup run as a complete restore point

## Related

- [Backups and Restore](https://hitkeep.com/guides/data/backups-and-restore/)
- [Data Retention and Archiving](https://hitkeep.com/guides/data/retention/)
- [Disaster Recovery](https://hitkeep.com/guides/data/disaster-recovery/)
- [Configuration Reference](https://hitkeep.com/reference/configuration/)

[Previous Backups and restore](https://hitkeep.com/guides/data/backups-and-restore/)[Next Data retention and archiving](https://hitkeep.com/guides/data/retention/)
