How it works
object_storage is not a standalone feature. It is a sub-config of logs_store:
client_config.log_retention_days - see Retention policy below.
When logs_store.object_storage is set:
- Bifrost writes per-request metadata (timestamps, provider, model, latency, token counts, cost, status, IDs) to the logs database.
- Large payload fields (request body, response body, streamed chunks, tool call arguments, etc.) are uploaded to the configured bucket under
prefix/. - The database row stores the object key, so the UI and API can fetch the payload on demand.
object_storage_exclude_fieldslets you skip specific fields from offload (for example, when you do not want to retain raw user prompts at all).
Configuration via config.json
Amazon S3
env.<NAME> indirection to read from environment variables):
| Field | Required | Notes |
|---|---|---|
type | yes | Must be "s3". |
bucket | yes | Target bucket name. |
region | yes | AWS region, e.g. us-west-2. |
access_key_id | conditional | Required for static credentials. Omit when using role_arn or the default credential chain (IRSA, instance profile, env). |
secret_access_key | conditional | Pairs with access_key_id. |
session_token | optional | For temporary STS credentials. |
role_arn | optional | Assume this role instead of using static keys. |
endpoint | optional | Override for S3-compatible stores (MinIO, Cloudflare R2, Wasabi). |
force_path_style | optional | Set true for most S3-compatible endpoints. |
prefix | optional | Object key prefix. Defaults to bifrost. |
compress | optional | Gzip payloads before upload. Defaults to false. |
examples/configs/withobjectstorages3/config.json.
Google Cloud Storage
| Field | Required | Notes |
|---|---|---|
type | yes | Must be "gcs". |
bucket | yes | Target bucket name. |
credentials_json | conditional | Service-account JSON (or env.GCS_KEY pointing at it). Omit when running on GKE with Workload Identity or any environment where Application Default Credentials work. |
credentials | deprecated | Legacy alias for credentials_json. Use credentials_json in new configs. |
project_id | optional | Useful when ADC cannot infer the project. |
prefix | optional | Object key prefix. Defaults to bifrost. |
compress | optional | Gzip payloads before upload. Defaults to false. |
examples/configs/withobjectstoragegcs/config.json.
Choosing what stays in the database vs. what is offloaded
By default, every offloadable payload field is uploaded to object storage.object_storage_exclude_fields lets you pin specific fields to the database only, so they are never written to the bucket. Listed fields are not dropped - they continue to live in the logs DB row as before. Everything not listed is offloaded.
Values must be database column names (not JSON paths). Common choices:
| Column | Contents |
|---|---|
raw_request | The verbatim provider request body. |
raw_response | The verbatim provider response body. |
input_history | The full conversation sent to the model. |
output_message | The model’s primary output message. |
framework/logstore/hybrid_test.go.
Typical use cases:
- Data residency: keep raw prompts and responses inside the DB (which may itself sit inside a controlled VPC) while still benefiting from offload for less sensitive fields.
- Operational queries: keep
input_historyin the DB so SQL queries and the UI’s search can run against the full conversation without paying an object-fetch round trip.
Retention policy
Bifrost ships a background log cleaner that deletes old logs on a fixed schedule.Configuration
Retention is configured on the client config, not onlogs_store. The active key is client_config.log_retention_days:
| Aspect | Value |
|---|---|
| Default | 365 days |
| Minimum | 1 day (enforced by validator) |
| Disable | Set to 0 (cleanup is skipped entirely) |
| Cleanup cadence | Every 24 hours, plus a random jitter of 15-30 minutes |
| Startup behaviour | A cleanup pass runs immediately when Bifrost starts |
| Delete batch size | 100 rows per query |
| Per-pass timeout | 30 minutes |
framework/logstore/cleaner.go and transports/bifrost-http/server/server.go.
What gets deleted
The cleaner deletes database rows older thannow - retention_days (UTC). It deletes from the main Log table as well as the MCP tool logs table.
What does NOT get deleted automatically
Important: the retention cleaner does not delete the corresponding payloads in S3 or GCS. The hybrid log store explicitly delegates object cleanup to the bucket’s own lifecycle policy.If you have object storage enabled, configure a lifecycle / object-lifecycle-management rule on the bucket to expire objects under your
prefix/. Pick a duration that matches (or exceeds) log_retention_days.
Amazon S3 lifecycle rule (example)
aws s3api put-bucket-lifecycle-configuration --bucket <bucket> --lifecycle-configuration file://lifecycle.json. See the AWS docs on object lifecycle management.
Google Cloud Storage lifecycle rule (example)
gcloud storage buckets update gs://<bucket> --lifecycle-file=lifecycle.json. See the GCS docs on Object Lifecycle Management.
Manual deletes still cascade
Single and batch deletes triggered explicitly (via the UI’s Delete log action or the underlyingDeleteLog / DeleteLogs APIs) do remove the associated objects from S3 or GCS at the same time. Only the time-based retention sweep is bucket-blind.
Configuration via Helm
The Bifrost Helm chart athelm-charts/bifrost/ does not expose dedicated values for logs_store.object_storage. It renders the same config.json schema documented above, so you supply the block under the chart’s bifrost.* configuration tree (or mount your own config.json via an existing ConfigMap/Secret).
Inline values
objectStorage block:
snake_case form Bifrost expects when it writes the runtime config.json. Provide the referenced env vars (AWS_*, GCS_*) through extraEnv, envFrom, or an existing Kubernetes Secret.
BYO config.json
If you prefer to manage the fullconfig.json yourself, mount it as a Secret and point the chart at it. Use the same logs_store.object_storage blocks shown in the config.json section verbatim.
Configuration via the UI
The web UI does not currently expose a form forlogs_store.object_storage. To enable payload offload:
- Edit
config.json(or the Helm values) using the snippets above. - Restart Bifrost so the new log store wiring takes effect.
- Confirm new requests are landing in the bucket by browsing the configured
prefix/path.
Verifying the setup
- Send a request through Bifrost.
- Confirm a row appears in the logs DB (visible via the UI’s Logs screen).
- List the bucket under your
prefix/. You should see one or more objects per request. - Open the log entry in the UI. The payload pane should render the content fetched from object storage.
objectstore errors. The most common causes are missing credentials, a region/endpoint mismatch, or a bucket policy that blocks the credentials’ principal.
