If you run agents in production and you use Langfuse for observability, your traces have always been exportable to a bucket on a schedule. The friction was the format. CSV and JSON land as untyped text, so every downstream query started with a load-and-cast step: parse the CSV, CAST the numeric columns, pull fields out of JSON blobs, then analyze.

As of July 8, 2026, that step is optional. Langfuse's scheduled blob-storage exports can now write Apache Parquet — a columnar binary format with typed columns — alongside the existing CSV, JSON, and JSONL. The payoff is direct: point a query engine at the file and go.

The one-line version#

Here's the end state, so you know what you're setting up. Once exports write Parquet to your bucket, querying last night's agent runs in DuckDB is a single statement — no schema, no load script:

-- How many observations per model, and total spend, from last night's export
SELECT model, count(*) AS calls, sum(total_cost) AS usd
FROM read_parquet('s3://my-bucket/langfuse/observations/2026-07-16/*.parquet')
GROUP BY model
ORDER BY usd DESC;

Because Parquet carries typed columns, total_cost is already a number and model is already a string. No CAST, no CSV dialect flags, no JSON extraction. That's the whole pitch.

Turning it on#

The switch is one field — fileType — on the blob-storage integration.

In the UI: Project Settings → Integrations → Blob Storage → set the file type to Parquet.

Programmatically, read and write the integration config over the public API:

# Inspect the current blob-storage config
curl -s https://cloud.langfuse.com/api/public/integrations/blob-storage \
  -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY"

# Switch it to Parquet (send back the full config with fileType: PARQUET)
curl -s -X PUT https://cloud.langfuse.com/api/public/integrations/blob-storage \
  -u "$LANGFUSE_PUBLIC_KEY:$LANGFUSE_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "fileType": "PARQUET", "enabled": true }'

Two things worth knowing:

The schedule (hourly / daily / weekly), the destination (S3, GCS, or Azure Blob Storage), and the datasets (traces, observations, scores) are unchanged. You're only changing what the files are encoded as.

The gotcha that will bite a cost dashboard#

One behavior differs, and it's the kind that fails silently. Parquet observation exports omit the per-unit price columnsinput_price, output_price, and total_price are not in the Parquet files.

If you have a dashboard that multiplies tokens by a per-unit price, switching to Parquet will quietly drop those columns and your spend math breaks. The fix is already in the export:

Both are present in every file type, Parquet included. So the correct query never touched the per-unit columns in the first place — the example above uses total_cost for exactly this reason. If your current pipeline reads input_price/output_price, rewrite it against cost_details/total_cost before you flip the format, and the switch is invisible.

Why this is worth ten minutes#

The value isn't "Parquet is a nicer format." It's that Parquet collapses the distance between your trace store and the place you actually analyze. A daily Parquet export plus DuckDB gives a solo builder a real analytics stack over their agent behavior — cost per model, latency tails, error clustering, eval scores over time — with zero ETL code. Load the file, write SQL.

And it composes upward without change: the same files that read_parquet() opens in DuckDB load natively into BigQuery, Snowflake, or ClickHouse when you outgrow a laptop. You set the export format once; the warehouse you pick later reads it as-is.

If you're already on Langfuse, this is a ten-minute change — flip fileType, confirm your cost query uses total_cost, point a query engine at the bucket — for a permanent reduction in the glue code between "the agent ran" and "here's what it did and what it cost."