Build1 publisher2 min readPublished
Porting one Iceberg agent across three frameworks rewrites the invocation and auth code
A step-by-step build of the same Apache Iceberg data agent on Google ADK, AWS Strands and Microsoft Agent Framework measures what a cloud move costs in code, in latency and in storage wiring.
The Engineer · Build desk

What happened
- One small Iceberg data agent was built three times: Google ADK on gemini-2.5-flash reading BigLake, AWS Strands on us.amazon.nova-micro-v1:0 reading Glue, and Microsoft Agent Framework on gpt-5-mini reading OneLake.
- The four tools and the instruction are the same Python objects in all three builds, and each framework's construction differs by one argument and one keyword.
- The agent builds portably, but calling it, signing in and reading its answer are three different jobs per framework.
- Median response times sit 3.72x apart, 12.36 seconds against 3.33, with no overlap in the middle half of the runs.
- All four setups returned the same largest id and filtered count in all twenty runs of the data test, each citing the exact Iceberg snapshot it read.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- decision Budget a framework switch as harness work: the invocation path, the sign-in and the response parser are what a team rewrites, and the tool functions are not in the estimate.
- cost The storage configuration is the recurring per-cloud bill, and its failure mode bills debugging time against a catalog that is behaving correctly.
- constraint The 3.72x spread cannot be quoted as a framework comparison, because each leg ran a different model; only the cell that holds Gemini fixed isolates framework overhead.
- capability With PyIceberg computing the answer and the agent naming a snapshot, cross-cloud equivalence can be verified against the catalog instead of assumed.
Per 100 generated tokens, the three agents land between 0.59 and 0.97 seconds, and gpt-5-mini is slowest because it writes the most [7]. That is a spread of 1.64x [2], against a median wall-clock gap of 9.03 seconds [1]. The dev.to write-up says speed follows the model, and how much it writes [15].
One cell holds the model fixed. On the same Gemini model, Strands was slower than ADK on both questions, by 1.52x on the simple one and 10.86 seconds against 7.89 on the data one [8], a ratio of 1.38x [3]. Strands was also slower per generated token in both [8].
For 1.38x to transfer, your agent has to look like this one: four tools, one instruction string, a small table, and a job that lists tables, describes one, counts or reads rows, and cites the version it read [3][13]. The measurements are ten runs per cell on 2026-09-15 UTC, twenty on the data test [5]. A larger tool set or a longer context would change how much of the wall clock is framework overhead and how much is generation, and the build does not test that.
The per-cloud work is storage. The tools bind unchanged, but reading a catalog's files needs its own configuration for OneLake, Glue and S3 Tables, and a wrong one lets the catalog keep answering while the data read fails with an error naming something else [9].
Apache Polaris is in the harness for that reason. It is an open-source implementation of the Iceberg REST catalog, run locally in Docker, and it holds the same 11-row test table as three of the four managed catalogs. A failure against it rules out the vendor without ruling out the model [11]. The REST specification is what makes the control meaningful: one API for finding tables, served by Google, AWS, Microsoft, Snowflake and Databricks [14].
The answers agree because PyIceberg computes them. Each leg scans GCS, S3 or ADLS through its own catalog, and the scan filters and counts in PyIceberg before the model sees a row [10]. Every answer in the build is checked back against the catalog itself [12].
So a second cloud costs the invocation path, the sign-in and the response parsing for the new framework [4], plus one storage configuration per catalog [9]. The four tools and the instruction move as they are [3].
What to watch
- A rerun with a larger tool set or streaming responses, which would change the share of wall clock that framework overhead accounts for.
- Whether the Strands-versus-ADK gap holds on a second held-fixed model, since only the Gemini cell isolates the framework.
- Whether the storage-wiring step for OneLake, Glue and S3 Tables gets folded into the frameworks' own catalog clients.