<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Chinyere John-Nnah</title>
    <description>The latest articles on DEV Community by Chinyere John-Nnah (@neraa).</description>
    <link>https://dev.to/neraa</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3883959%2Fc4575041-65f3-4192-82cb-0c6c81207030.jpg</url>
      <title>DEV Community: Chinyere John-Nnah</title>
      <link>https://dev.to/neraa</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/neraa"/>
    <language>en</language>
    <item>
      <title>From Playground to Code: Three Versions of One Prompt in Google AI Studio</title>
      <dc:creator>Chinyere John-Nnah</dc:creator>
      <pubDate>Thu, 07 May 2026 12:32:44 +0000</pubDate>
      <link>https://dev.to/neraa/from-playground-to-code-three-versions-of-one-prompt-in-google-ai-studio-3871</link>
      <guid>https://dev.to/neraa/from-playground-to-code-three-versions-of-one-prompt-in-google-ai-studio-3871</guid>
      <description>&lt;p&gt;A few weeks ago I wrote a breakdown of Cloud Next '26 for developers &lt;a href="https://coderlegion.com/15971/from-chatbots-to-coworkers-what-google-cloud-next-26-means-for-developers" rel="noopener noreferrer"&gt;Link to keynote&lt;/a&gt; and closed it with a line to other frontend devs: play with Agent Studio. I took my own advice.&lt;/p&gt;

&lt;p&gt;I tried to take my own advice and faced a technical issue with Google Cloud's new prepayment wall and pivoted. This post is what happened next: spending an hour in Google AI Studio, iterating one prompt three times and finishing with Typescript I could drop into a Next.js project. No billing required, no Cloud project. Just a Google account.&lt;/p&gt;

&lt;p&gt;If you're stuck at the same prepayment wall, or if you just want to know what the Gemini playground actually looks like before committing to anything paid, this is for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D12162020930476391931" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D12162020930476391931" alt="Empty AI Stuido interface" width="900" height="463"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;What AI Studio actually is&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A quick note for anyone confused by the naming, because Google has not made this easy. &lt;/p&gt;

&lt;p&gt;There's &lt;strong&gt;Gemini Enterprise&lt;/strong&gt;, which lives in Cloud Console behind a billing account; that's the enterprise stack I wrote about in the keynote piece. &lt;/p&gt;

&lt;p&gt;Then there's &lt;strong&gt;Google AI Studio&lt;/strong&gt; at &lt;a href="https://aistudio.google.com" rel="noopener noreferrer"&gt;aistudio.google.com&lt;/a&gt;, which is the public-facing Gemini playground. Sign in with any Google account. No card, no project, no setup.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Google AI Studio&lt;/th&gt;
&lt;th&gt;Gemini Enterprise&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;User Type&lt;/td&gt;
&lt;td&gt;Prototypers, Developers&lt;/td&gt;
&lt;td&gt;Data Scientists, Enterprise&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Low (Simple)&lt;/td&gt;
&lt;td&gt;High (Advanced)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Purpose&lt;/td&gt;
&lt;td&gt;Experimentation&lt;/td&gt;
&lt;td&gt;Production &amp;amp; Scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost&lt;/td&gt;
&lt;td&gt;Generous Free Tier&lt;/td&gt;
&lt;td&gt;Usage-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security&lt;/td&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;Enterprise-grade (GCP)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For this walkthrough, I used &lt;strong&gt;Gemini 3 Flash Preview&lt;/strong&gt; which is the cheaper, faster sibling to Gemini 3 Pro. Flash Preview is the right default when you're iterating because the latency difference matters when you're running the same prompt five or six times in a row.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The input I gave it&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;I wanted to see how the same prompt evolved across three versions. One task, three system prompts, same user input. The point wasn't to land at a perfect prompt on the first try; it was to show what changes when you take prompt iteration seriously instead of writing one prompt and hoping.&lt;/p&gt;

&lt;p&gt;I used the same input for all three versions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;We need a hero section for our SaaS landing page. The product is a project management tool for small design agencies. Should feel premium&lt;br&gt;
but approachable. Main goal is to get visitors to start a free trial.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is roughly how a brief actually arrives in a frontend dev's inbox: vague, opinion-loaded, half a sentence longer than it needs to be. The whole point of running it through an LLM is to turn that vagueness into a structured spec a developer can build from. So that's what I tried to make the model do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V1: The naive prompt&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I adjusted the temperature from 1(default)  to 0.7 and I gave sytem instructions.&lt;/p&gt;

&lt;p&gt;System instructions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You are a helpful assistant. Generate a component spec based on the design brief the user provides.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The kind of system prompt anyone would write on the first try. No structure, no constraints, just "do the thing."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D15556880556643919459" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D15556880556643919459" alt="v1 output" width="900" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output came back more beautifully than expected. An editorial document with visual guidelines, color palette with hex codes, typography choices, three headline options, a copy strategy section and even a Typescript interface for HeroProps inside the markdown.&lt;/p&gt;

&lt;p&gt;It's genuinely impressive. And that's the trap.&lt;/p&gt;

&lt;p&gt;V1 succeeded as a document. &lt;/p&gt;

&lt;p&gt;It did not succeed as a spec. &lt;/p&gt;

&lt;p&gt;There's a difference, and that difference is the whole reason this post exists.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D10061486269773184296" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D10061486269773184296" alt="Typescript buried in heroprops" width="900" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If I want to feed this output into a code generator, populate a Notion database, or render fields dynamically in a React form, I can't. I'd have to manually parse the markdown, find the HeroProps interface, scrape the hex codes out of the prose, copy the headline options into an array. The model wrote content for humans, when what I needed was data for machines.&lt;/p&gt;

&lt;p&gt;Token cost: 208. Cheap. Fast. Useless if you want to do anything programmatic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V2: Asking for structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If V1 returned prose because I asked for prose, maybe V2 returns data if I ask for data. With temperature still set at 0.7 I replaced system instructions.&lt;/p&gt;

&lt;p&gt;New system instructions:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are a frontend architect helping translate design briefs into &lt;br&gt;
component specifications. When given a design brief, return a &lt;br&gt;
structured component spec with the following information:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Component name&lt;/li&gt;
&lt;li&gt;Purpose&lt;/li&gt;
&lt;li&gt;Suggested props&lt;/li&gt;
&lt;li&gt;Accessibility considerations&lt;/li&gt;
&lt;li&gt;Suggested Tailwind classes for key elements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Return your response as JSON.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The output came back as JSON. Real JSON. Valid JSON. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D6329564136775187086" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D6329564136775187086" alt="v2 output 1" width="900" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Look at field names like component_name, purpose, suggested_props, primaryAction, productScreenshotUrl, trustBadges. Some snake_case, some camelCase. Some are top-level, some are nested. &lt;/p&gt;

&lt;p&gt;This looks better. But there's a quieter problem hiding in plain sight. I didn't define the schema. The model did.&lt;/p&gt;

&lt;p&gt;I ran the prompt again. "DesignAgencyHero" in the first prompt became "CreativeStudioHero". Also, suggested props like "headline" became "title" and "subheadline" became "description" etc. New fields appeared. Old ones vanished.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D4196956631710118537" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D4196956631710118537" alt="v2 output2" width="900" height="463"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output is JSON, but it's JSON I can't trust to stay the same shape across calls. And if the shape isn't stable, I can't write code that consumes it.&lt;/p&gt;

&lt;p&gt;Better than V1, still not deployable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;V3: Structured outputs&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where AI Studio earns its keep.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D1418638045851856562" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D1418638045851856562" alt="v3 showing structured outputs" width="900" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the parameters panel, there's a toggle called &lt;strong&gt;Structured outputs&lt;/strong&gt;. Flip it on, and AI Studio gives you a schema editor where you define exactly what comes back. Field names, types, what's required, what's optional, nested objects, all of it. The model has to conform to the shape you specified.&lt;/p&gt;

&lt;p&gt;Here's the schema I used:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "type": "object",
  "properties": {
    "componentName": { "type": "string" },
    "purpose": { "type": "string" },
    "props": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "type": { "type": "string" },
          "required": { "type": "boolean" },
          "description": { "type": "string" }
        },
        "required": ["name", "type", "required", "description"]
      }
    },
    "accessibilityNotes": {
      "type": "array",
      "items": { "type": "string" }
    },
    "suggestedTailwindClasses": {
      "type": "object",
      "properties": {
        "container": { "type": "string" },
        "heading": { "type": "string" },
        "subheading": { "type": "string" },
        "ctaButton": { "type": "string" }
      }
    }
  },
  "required": ["componentName", "purpose", "props", "accessibilityNotes", "suggestedTailwindClasses"]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Defining this schema took longer than writing the prompt. That's the honest tradeoff: structured outputs aren't free, and they aren't fast. You're doing real design work upfront in exchange for output you can actually consume.&lt;/p&gt;

&lt;p&gt;The system instruction got simpler:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You are a frontend architect helping translate design briefs into&lt;br&gt;
component specifications. Return a complete, well-considered component&lt;br&gt;
spec based on the design brief provided.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I no longer needed to list the fields in the system prompt. The schema does that job now.&lt;/p&gt;

&lt;p&gt;To show the payoff clearly, I ran V3 three times with the same input but different temperatures: 0.2, 0.7, and 0.9.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temperature 0.2&lt;/strong&gt;: conservative settings. The model returns a tight, safe spec.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D5529581301861245749" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D5529581301861245749" alt="v3 0.2" width="900" height="464"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Component name: &lt;strong&gt;AgencyHeroSection&lt;/strong&gt;. Compact descriptions. Predictable choices.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temperature 0.7&lt;/strong&gt;: middle ground.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D9748426993512525807" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D9748426993512525807" alt="v3 0.7" width="900" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Component name: &lt;strong&gt;PremiumStudioHero&lt;/strong&gt;. Richer descriptions. More distinctive framing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Temperature 0.9&lt;/strong&gt;: turn the creativity dial up.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D15338631489918215924" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D15338631489918215924" alt="v3 0.9" width="900" height="460"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Component name: &lt;strong&gt;DesignAgencyHero&lt;/strong&gt;. The most evocative copy of the three. The descriptions reach for words like "craft" and "flow."&lt;/p&gt;

&lt;p&gt;Three runs. Three different creative interpretations. The schema stayed identical across all three. Same fields. Same types. Same nesting. The model varied the content. It could not vary the shape.&lt;/p&gt;

&lt;p&gt;That's the entire point. Structured outputs separate the parts of the response you want stable from the parts you want creative. Field names and structure stay locked. Tone, copy, and specifics breathe within those constraints.&lt;/p&gt;

&lt;p&gt;A note on cost: V3 at temperature 0.9 burned 9,357 tokens, compared to V1's 208. Schema definitions are part of the prompt the model sees, and a detailed schema is a long prompt. Structured outputs are powerful, but they aren't cheap. For high-volume calls, this matters.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;From Playground to Code&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Here's the part where this stops being a playground exercise and starts being something I could actually ship.&lt;/p&gt;

&lt;p&gt;In the top-right of the Run settings panel, there's a button labeled &lt;strong&gt;Get code (&amp;lt;&amp;gt;)&lt;/strong&gt;. I clicked it with V3 still loaded schema enabled, temperature still set, system prompt still in place and AI Studio generates working code in your language of choice.&lt;/p&gt;

&lt;p&gt;I picked TypeScript.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D2224083358114419301" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcoderlegion.com%2F%3Fqa%3Dblob%26qa_blobid%3D2224083358114419301" alt="typescript" width="900" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is the code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// To run this code you need to install the following dependencies:
// npm install @google/genai mime
// npm install -D @types/node

import {
  GoogleGenAI,
  Type,
} from '@google/genai';

async function main() {
  const ai = new GoogleGenAI({
    apiKey: process.env['GEMINI_API_KEY'],
  });
  const config = {
    temperature: 0.7,
    thinkingConfig: {
      thinkingLevel: ThinkingLevel.HIGH,
    },
    responseMimeType: 'application/json',
    responseSchema: {
      type: Type.OBJECT,
      required: ["componentName", "purpose", "props", "accessibilityNotes", "suggestedTailwindClasses"],
      properties: {
        componentName: {
          type: Type.STRING,
        },
        purpose: {
          type: Type.STRING,
        },
        props: {
          type: Type.ARRAY,
          items: {
            type: Type.OBJECT,
            required: ["name", "type", "required", "description"],
            properties: {
              name: {
                type: Type.STRING,
              },
              type: {
                type: Type.STRING,
              },
              required: {
                type: Type.BOOLEAN,
              },
              description: {
                type: Type.STRING,
              },
            },
          },
        },
        accessibilityNotes: {
          type: Type.ARRAY,
          items: {
            type: Type.STRING,
          },
        },
        suggestedTailwindClasses: {
          type: Type.OBJECT,
          properties: {
            container: {
              type: Type.STRING,
            },
            heading: {
              type: Type.STRING,
            },
            subheading: {
              type: Type.STRING,
            },
            ctaButton: {
              type: Type.STRING,
            },
          },
        },
      },
    },
    systemInstruction: [
        {
          text: `You are a frontend architect helping translate design briefs into 
component specifications. Return a complete, well-considered 
component spec based on the design brief provided.

`,
        }
    ],
  };
  const model = 'gemini-3-flash-preview';
  const contents = [
    {
      role: 'user',
      parts: [
        {
          text: `INSERT_INPUT_HERE`,
        },
      ],
    },
  ];

  const response = await ai.models.generateContentStream({
    model,
    config,
    contents,
  });
  let fileIndex = 0;
  for await (const chunk of response) {
    if (chunk.text) {
      console.log(chunk.text);
    }
  }
}

main();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every parameter I touched in the UI is now a field in the code. Temperature. Thinking level. Response MIME type. The schema. The system prompt. Nothing got lost in translation between the playground and the script.&lt;/p&gt;

&lt;p&gt;The SDK is &lt;strong&gt;@google/genai&lt;/strong&gt;, the official Google package. Install with &lt;strong&gt;npm install @google/genai mime&lt;/strong&gt; and &lt;strong&gt;npm install -D @types/node.&lt;/strong&gt; Get a free API key from AI Studio's "Get API key" link in the left sidebar with no billing required and a generous free tier.&lt;/p&gt;

&lt;p&gt;This drops into a Next.js API route with minimal changes. The schema travels with the code. The system prompt travels with the code. The temperature you tuned travels with the code. The hour I spent in the playground became 60 lines of TypeScript I can paste into &lt;strong&gt;app/api/component-spec/route.ts&lt;/strong&gt; and call from a frontend form.&lt;/p&gt;

&lt;p&gt;That's the bridge. That's what makes AI Studio worth using even if you eventually move to Agent Platform: the iteration happens in the playground, the deployment happens in code, and the handoff is one button.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;What this means for frontend devs&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Three things I'm taking from this hour:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You don't need Cloud billing to start. AI Studio plus a free API key gets you most of the way to a working Gemini integration. If you're learning, prototyping, or building a personal project, this stack is plenty. The expensive enterprise tools are for a real production app at scale, not for figuring out whether the model can do what you need.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prompt iteration is engineering. V1 to V2 to V3 wasn't an aesthetic exercise. Each version was a deliberate response to a real problem with the previous one: V1's prose couldn't be parsed, V2's JSON couldn't be trusted, V3's schema solved both. Treat prompts the way you'd treat any other component of your system: iterate them, version them, write them down.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Structured outputs are the real unlock. The moment your model returns the same shape every time, you stop treating AI calls as dice rolls and start treating them as normal API calls. You can write TypeScript types for the response. You can render the output in a UI without defensive parsing. You can build product around the model's behavior, not around its randomness.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The last point is what I want to keep poking at. When my Cloud account clears the prepayment wall and I get into Agent Studio, the question I'm bringing with me is: how do these same patterns translate to a deployed agent? &lt;/p&gt;

&lt;p&gt;&lt;em&gt;For now: if you're stuck at billing, don't wait. AI Studio is right here. Sign in, pick a model, iterate something useful.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>googlecloud</category>
      <category>ai</category>
      <category>typescript</category>
      <category>beginners</category>
    </item>
    <item>
      <title>From Chatbots to Coworkers: What Google Cloud Next '26 Means for Developers</title>
      <dc:creator>Chinyere John-Nnah</dc:creator>
      <pubDate>Mon, 27 Apr 2026 09:14:39 +0000</pubDate>
      <link>https://dev.to/neraa/from-chatbots-to-coworkers-what-google-cloud-next-26-means-for-developers-2lnf</link>
      <guid>https://dev.to/neraa/from-chatbots-to-coworkers-what-google-cloud-next-26-means-for-developers-2lnf</guid>
      <description>&lt;p&gt;&lt;em&gt;A developer's breakdown of everything that matters from the Google Cloud Next '26 keynote and what to build with it next.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/google-cloud-next-2026-04-22"&gt;Google Cloud NEXT Writing Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For the last two years, every AI keynote has felt like a magic show "look at this thing that can write a poem." &lt;/p&gt;

&lt;p&gt;Google Cloud Next '26 was different. &lt;/p&gt;

&lt;p&gt;The magic show is over. &lt;/p&gt;

&lt;p&gt;The actual machinery is here.&lt;/p&gt;

&lt;p&gt;Thomas Kurian and Sundar Pichai opened the keynote with a single, quietly disruptive idea: we're done with chatbots that talk. The new era is about agents that do: systems with persistent reasoning and autonomous execution that can hold context for days, plan multi-step workflows, and verify their own work. &lt;/p&gt;

&lt;p&gt;2024 and 2025 asked, "Can we build an agent?", 2026 asks, "How do we manage thousands of them?"&lt;br&gt;
For developers especially those of us building at the intersection of frontend, data, and distributed systems this is the most consequential Next in years. Here's what actually shipped, what it means, and where to start.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Agentic Enterprise Blueprint
&lt;/h2&gt;

&lt;p&gt;Kurian framed the entire conference around one concept: &lt;strong&gt;The Agentic Enterprise&lt;/strong&gt;. The pitch is that the org chart of the future doesn't just have humans it has digital teammates working alongside them, and every employee becomes a builder who orchestrates a swarm of agents instead of executing tasks manually.&lt;/p&gt;

&lt;p&gt;The strategy rests on two ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Persistent reasoning&lt;/strong&gt;: Unlike a chatbot that forgets you the moment you close the tab, agents maintain state across days. They can pause, wait for an external trigger, resume, and finish the job like a human colleague would.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Owning the full stack:&lt;/strong&gt; Custom silicon (TPUs), the data layer (BigQuery), and the UX (Workspace) all built to work together. Kurian's not-so-subtle jab at competitors: they "hand you the pieces, not the platform."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Whether you buy that framing or not, the takeaway is clear Google is betting that vertically integrated infrastructure wins the agent era. And the rest of the keynote was them showing receipts.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gemini Enterprise Agent Platform (The Vertex AI Rebrand)
&lt;/h2&gt;

&lt;p&gt;The biggest rebrand of the event: &lt;strong&gt;Vertex AI&lt;/strong&gt; is now the &lt;strong&gt;Gemini Enterprise Agent Platform.&lt;/strong&gt; It's no longer a model garden it's a unified environment for the entire agent lifecycle, from prototype to production to post-deployment monitoring.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ygoiwx6ox5h0tgeg269.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8ygoiwx6ox5h0tgeg269.png" alt="Architecture diagram of the Gemini Enterprise Agent Platform" width="800" height="627"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The core features that make up the platform:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Studio:&lt;/strong&gt; A low-code, visual builder inside Workspace. Defines agent goals in natural language, wire up tools, and ship.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Development Kit (ADK) v1.0&lt;/strong&gt;: The pro-code framework for the rest of us. Supports Python, JavaScript, Java, and Go, and lets you build graph-based agent networks (think LangGraph, but native).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Identity:&lt;/strong&gt; Every agent gets a unique cryptographic ID. Every action it takes is auditable. This is huge for compliance finally, a real answer to "Which agent did that, and why?"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Gateway:&lt;/strong&gt; Air traffic control for your agent fleet. Enforces policy, manages traffic, and uses Model Armor to block prompt injection attacks at the edge.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A2A (Agent-to-Agent) Protocol&lt;/strong&gt;: A standardized handshake that lets a Google-based agent securely delegate tasks to a Salesforce or SAP agent. Cross-vendor interoperability, finally.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Runtime:&lt;/strong&gt; A re-engineered execution environment built for long-running agents. Your agent can fire off a task, wait three days for an external API to respond, and pick up exactly where it left off.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Simulation &amp;amp; Evaluation:&lt;/strong&gt; Stress-test your agent against thousands of simulated user interactions before it ever sees production. Catches logic drift before your users do.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's Actually Shipping
&lt;/h2&gt;

&lt;p&gt;If Day 1 sold the strategy, Day 2 showed the developer loop underneath it. The framing: build an agent system that plans a marathon for 10,000 runners through the Las Vegas Strip, using three agents — a planner (generates routes), an evaluator (scores them against constraints), and a simulator (runs the route end-to-end). The entire codebase and every demo were open-sourced as a GitHub repo plus Codelabs. The platform was anchored around four pillars and each pillar got its own demo segment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🛠️ Build&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ADK (Agent Development Kit)&lt;/strong&gt;: the code-first framework, supporting Python, JavaScript, Java, and Go, with a new graph-based runtime for defining how agents collaborate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Studio&lt;/strong&gt;: the low-code counterpart. Define agent goals in natural language, wire up tools, publish.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Managed MCP&lt;/strong&gt;: Google now hosts the Model Context Protocol layer, eliminating a week of self-hosting plumbing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Registry&lt;/strong&gt;: described as "the DNS of your internet of agents." Auto-indexes every agent deployed to Agent Runtime, making them discoverable and governable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Marketplace&lt;/strong&gt;: third-party agents from Atlassian, Box, Lovable, Oracle, ServiceNow, Workday, and more, deployable directly from Gemini Enterprise.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model Garden&lt;/strong&gt;: explicitly supports Claude, Gemini 3.1 Pro, Gemini 3.1 Flash, and others. Pick your model, swap when needed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;📈 Scale&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Serverless Agent Runtime&lt;/strong&gt;: handles long-running state across days. Agents pause, wait for an external trigger, and resume without losing context.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A2A (Agent-to-Agent) Protocol&lt;/strong&gt;: the cross-vendor handshake. Created by Google, donated to the Linux Foundation. A Google agent can hand work to a Salesforce or SAP agent without brittle API code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A2UI (Agent-to-User Interface)&lt;/strong&gt;: an open standard letting agents generate dynamic UI components instead of returning plain text. The marathon simulator's UI (Angular + 3D rendering of the Las Vegas Strip) was assembled live by the agent itself, not hardcoded.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The evaluation layer is now first-class. A separate model as a judge scores outputs across deterministic criteria (a marathon is exactly 26 miles 385 yards / 42.195 km) and non-deterministic ones (community impact, route quality). Agents auto-generate their evaluation UIs from the schema of their own outputs the path from "fragile, unpredictable agentic loops" to "a rigorously evaluated network of experts."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔒 Govern&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The framing here was sharp: stop telling developers to "shift left" (own everything earlier) and start letting them "shift down" push the responsibility into the platform layer.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Identity&lt;/strong&gt;: every agent gets a unique, immutable cryptographic credential. Every action is auditable back to a specific agent instance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Gateway&lt;/strong&gt;: air traffic control for the agent fleet. Understands MCP and A2A protocols. Uses IAM policies to scope which sources can invoke agent actions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Agent Policies&lt;/strong&gt;: configurable guardrails. An agent permitted to read from BigQuery but blocked from triggering spend over a threshold.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Model Armor&lt;/strong&gt;: inline protection against prompt injection, tool poisoning, and sensitive data leakage at the gateway layer.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚙️ Optimize&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The end-to-end debugging story for when an agent breaks in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent Runtime trace view&lt;/strong&gt;: surfaces exactly where the reasoning chain or tool call failed.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gemini Cloud Assist Investigation&lt;/strong&gt;: takes a natural-language query and explores logs and events to surface the failing component down to a specific line.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Antigravity IDE&lt;/strong&gt;: powered by Gemini 3, connected via MCP. Proposes parameter-level remediations. In the demo: a missing token_threshold on the event-compaction config that was silently truncating the agent's working memory.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Wiz Green Agent inside Claude Code with Opus&lt;/strong&gt;: Wiz now scans both agent code and infrastructure, and the same remediation surface runs inside Anthropic's IDE on Anthropic's model. An explicit multi-vendor signal: security tooling travels with the developer, regardless of stack.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What it means for you&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Day 1 sold the agentic enterprise. Day 2 laid out the loop you'll actually live in: build → scale → govern → optimize. Three things to actually act on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The evaluation layer is the part most teams will sleep on and regret. Judge models, deterministic + non-deterministic checks, auto-generated eval UIs: this is where agentic systems silently fail today, and it's now baked in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A2A and A2UI are open standards, not Google-only. The Linux Foundation handoff matters. Don't dismiss them as vendor lock-in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Antigravity is the bet to watch. It's Google's claim on what "agentic developer experience" means in 2026 and the multi-vendor Wiz/Claude Code integration shows the surface area is intentionally portable.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The AI Hypercomputer: 8th-Gen TPUs
&lt;/h2&gt;

&lt;p&gt;To run millions of persistent agents in production, you need silicon designed for the workload. Google's answer is the 8th-generation TPU and crucially, it's a dual-chip strategy that splits training and inference into purpose-built hardware. This is Google explicitly attacking the "memory wall" that's been bottlenecking large models.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi2iipcjlrqau26lrlqq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvi2iipcjlrqau26lrlqq.png" alt="TPUs comparison with the previous" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What it means for you:&lt;/strong&gt; Cloud developers now have a dedicated inference engine in the TPU 8i. The economics of running a complex, multi-turn agent for every single user in your app just got real. The "one agent per user" pattern was a fantasy in 2024 at these unit costs, it becomes a default architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Agentic Data Cloud: From Passive Storage to System of Action
&lt;/h2&gt;

&lt;p&gt;"Reasoning without context is just a guess" that's how Karthik Narain, Google Cloud's Chief Product and Business Officer, framed the thesis behind the Agentic Data Cloud, which reimagines data as something agents act on, not just query.&lt;/p&gt;

&lt;p&gt;Three pieces matter most:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Knowledge Catalog&lt;/strong&gt;: Replaces traditional metadata catalogs. It auto-maps the business meaning of data across your entire estate (Google Docs, Slack, SQL warehouses, the lot). Your agents now understand that "ARR" in finance means the same thing as "Annual Recurring Revenue" in your CRM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Bank:&lt;/strong&gt; Long-term memory for agents. Where chat sessions used to forget you in five minutes, Memory Bank persists user preferences and project history across months of interaction.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Managed MCP:&lt;/strong&gt; You no longer host your own Model Context Protocol servers. Google now manages the connective tissue between Gemini and your databases, which kills a whole class of plumbing work.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Agentic Defense: The Wiz Integration Goes Live
&lt;/h2&gt;

&lt;p&gt;With the $32 billion Wiz acquisition fully closed, Google rolled out a "Cyberforce" of defensive agents. The pitch: stop reacting to alerts, start hunting threats autonomously.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Threat Hunting Agent:&lt;/strong&gt; Proactively scans for novel attack patterns that signature-based firewalls miss.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Detection Engineering Agent&lt;/strong&gt;: Writes and deploys new security rules in real time as threats evolve. The rule that catches tomorrow's attack didn't exist yesterday.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Wiz "Red Agent"&lt;/strong&gt;: An autonomous penetration tester that constantly probes your cloud infrastructure for unlocked doors before real attackers find them.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;The Agentic Taskforce: Companies Already Shipping&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0w9hujnn4m5xd4dl3pky.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0w9hujnn4m5xd4dl3pky.png" alt="Grid of 10 enterprise companies using Gemini agents in production" width="800" height="733"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The keynote closed with proof points companies actually getting ROI from agents in production right now. The pattern across all of them: agents handling the long-tail repetitive work, humans focusing on judgment calls. A few standouts worth zooming in on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;KPMG's Tax Swarms&lt;/strong&gt; are the clearest A2A protocol use case in the wild; their tax agent talks directly to a client's audit agent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Virgin Voyages&lt;/strong&gt; going from 6-hour rebookings to 11 minutes is the clearest "Agent Runtime + long-running state" example.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Goldman Sachs&lt;/strong&gt; querying 10,000+ page filings in minutes is what the Knowledge Catalog actually unlocks at enterprise scale.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Walmart and Bosch&lt;/strong&gt; prove agents work at the edge — store floors and factory floors, not just data centers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;So What Should You Actually Do With This?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you take one thing from Next '26, take this: the agent era isn't a future bet, it's a current one. The infrastructure is shipping, the protocols are standardizing, and Fortune 500s are already in production.&lt;/p&gt;

&lt;p&gt;Concretely, here's where to start depending on your stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Frontend devs&lt;/strong&gt;: Play with Agent Studio. The low-code builder is the fastest way to feel what an agentic UX is even supposed to look like.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Backend / data folks&lt;/strong&gt;: The Knowledge Catalog and Memory Bank are the most underrated announcements. Try wiring an agent to your own data with Managed MCP and skip a month of plumbing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Infra / platform engineers&lt;/strong&gt;: Watch the TPU 8i pricing closely. The economics of "an agent per user" change your architecture decisions for the next two years.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security teams&lt;/strong&gt;: Don't wait. Threat Hunting and Red Agent are the kind of tools your blue team will quietly start depending on by Q3.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The chatbot era taught us how to prompt. The agent era is going to teach us how to delegate. The developers who figure that out first are going to look like wizards by the end of 2026.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;If you watched the keynote too, what stood out for you? Drop a comment especially if you've started prototyping with the ADK. I'm curious what's actually working vs. what's still demo-ware.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>cloudnextchallenge</category>
      <category>googlecloud</category>
      <category>agents</category>
    </item>
    <item>
      <title>I Automated 90% of The Ethers.js v5 v6 Migration using Codemods and AI</title>
      <dc:creator>Chinyere John-Nnah</dc:creator>
      <pubDate>Sat, 18 Apr 2026 13:29:53 +0000</pubDate>
      <link>https://dev.to/neraa/i-automated-90-of-the-ethersjs-v5-v6-migration-using-codemods-and-ai-22n6</link>
      <guid>https://dev.to/neraa/i-automated-90-of-the-ethersjs-v5-v6-migration-using-codemods-and-ai-22n6</guid>
      <description>&lt;p&gt;Ethers v6 dropped a breaking change on every project that touched BigNumber, utils, or providers — which is basically every DeFi frontend ever written. The migration guide listed over 40 breaking changes. Some were simple renames. Some required understanding whether a variable was a BigNumber before deciding what to do with it. Doing this by hand across 31 files is exactly the kind of work that makes engineers quit. I built a codemod pipeline to handle the mechanical ones automatically — and wrote AI prompts for the rest.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why ethers v5 → v6 is painful
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;BigNumber is gone.&lt;/strong&gt; In v5, every numeric value coming off a contract was a &lt;code&gt;BigNumber&lt;/code&gt; instance with its own method API: &lt;code&gt;.add()&lt;/code&gt;, &lt;code&gt;.mul()&lt;/code&gt;, &lt;code&gt;.toNumber()&lt;/code&gt;, &lt;code&gt;.toHexString()&lt;/code&gt;. In v6, native JavaScript &lt;code&gt;bigint&lt;/code&gt; takes over. That's a good change long-term, but it means every arithmetic expression, every comparison, every conversion in your codebase needs to change — and if you mix a &lt;code&gt;bigint&lt;/code&gt; with a &lt;code&gt;number&lt;/code&gt; by accident, you get a runtime &lt;code&gt;TypeError&lt;/code&gt; with no static warning unless you're fully strict about types.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The entire &lt;code&gt;ethers.utils&lt;/code&gt; namespace was flattened.&lt;/strong&gt; In v5, utility functions lived under &lt;code&gt;ethers.utils&lt;/code&gt;: &lt;code&gt;ethers.utils.parseEther&lt;/code&gt;, &lt;code&gt;ethers.utils.keccak256&lt;/code&gt;, &lt;code&gt;ethers.utils.arrayify&lt;/code&gt;. In v6, they're all top-level on the &lt;code&gt;ethers&lt;/code&gt; object. That's 15+ functions to find and rename across your codebase, and three of them got renamed too: &lt;code&gt;arrayify&lt;/code&gt; became &lt;code&gt;getBytes&lt;/code&gt;, &lt;code&gt;hexZeroPad&lt;/code&gt; became &lt;code&gt;zeroPadValue&lt;/code&gt;, and &lt;code&gt;splitSignature&lt;/code&gt; became &lt;code&gt;Signature.from()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Providers moved and Web3Provider is gone.&lt;/strong&gt; The entire &lt;code&gt;ethers.providers&lt;/code&gt; sub-namespace was dissolved. &lt;code&gt;new ethers.providers.JsonRpcProvider(url)&lt;/code&gt; is now &lt;code&gt;new ethers.JsonRpcProvider(url)&lt;/code&gt;. &lt;code&gt;new ethers.providers.Web3Provider(window.ethereum)&lt;/code&gt; — the line in basically every frontend DeFi app — is now &lt;code&gt;new ethers.BrowserProvider(window.ethereum)&lt;/code&gt;. &lt;code&gt;StaticJsonRpcProvider&lt;/code&gt; was merged into &lt;code&gt;JsonRpcProvider&lt;/code&gt;. If you have TypeScript type annotations using &lt;code&gt;ethers.providers.X&lt;/code&gt;, those need to change too.&lt;/p&gt;

&lt;h2&gt;
  
  
  My approach: codemods + AI
&lt;/h2&gt;

&lt;p&gt;The insight that made this tractable is recognizing that these changes fall into two completely different categories.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mechanical renames&lt;/strong&gt; have one right answer. &lt;code&gt;ethers.utils.parseEther&lt;/code&gt; always becomes &lt;code&gt;ethers.parseEther&lt;/code&gt;. &lt;code&gt;new ethers.providers.Web3Provider(x)&lt;/code&gt; always becomes &lt;code&gt;new ethers.BrowserProvider(x)&lt;/code&gt;. These changes are safe to automate because the transformation is deterministic — given the same input, there's only one correct output. A codemod handles these at AST level: it parses the source into a syntax tree, finds the exact nodes to change, replaces them, and prints the result with formatting preserved. No regex, no string munging, no accidental replacements inside comments or string literals.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Semantic changes&lt;/strong&gt; require context. When you see &lt;code&gt;someVar.toNumber()&lt;/code&gt;, the right migration depends on where &lt;code&gt;someVar&lt;/code&gt; came from. If it's the direct result of &lt;code&gt;BigNumber.from(x)&lt;/code&gt;, you can mechanically replace it with &lt;code&gt;Number(BigInt(x))&lt;/code&gt;. But if it came from a contract call two scopes away, you need to understand the data flow, check whether the value could exceed &lt;code&gt;Number.MAX_SAFE_INTEGER&lt;/code&gt;, and decide whether &lt;code&gt;Number()&lt;/code&gt;, &lt;code&gt;parseInt()&lt;/code&gt;, or staying with &lt;code&gt;bigint&lt;/code&gt; is right. No static tool makes that call correctly 100% of the time. AI does, given enough context.&lt;/p&gt;

&lt;p&gt;The combination is the only approach that scales. Codemods alone leave the semantic cases as silent bugs. AI alone on a 31-file codebase is slow and expensive. Together, you get deterministic correctness where it's possible and targeted AI review where it's necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 8 transforms I built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;rename-utils&lt;/strong&gt; — Lifts all 17 &lt;code&gt;ethers.utils.*&lt;/code&gt; functions to the top-level namespace. Handles both &lt;code&gt;import * as ethers&lt;/code&gt; and &lt;code&gt;import { utils }&lt;/code&gt; styles, rewrites the import declaration, and covers the two structural changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseEther&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;arrayify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hexString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseEther&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bytes&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hexString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;bigNumber-to-bigint&lt;/strong&gt; — Replaces &lt;code&gt;BigNumber.from(x)&lt;/code&gt; with &lt;code&gt;BigInt(x)&lt;/code&gt; and rewrites instance methods on statically-confirmed BigNumber variables to native operators. Uses a conservative two-phase approach: method rewrites run first to handle chains like &lt;code&gt;BigNumber.from(x).toNumber()&lt;/code&gt; atomically, then standalone &lt;code&gt;BigNumber.from()&lt;/code&gt; nodes are replaced.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BigNumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fee&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;BigNumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;500000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1000000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fee&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;BigInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;500000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;rename-providers&lt;/strong&gt; — Renames all 7 provider classes and updates TypeScript type annotations. &lt;code&gt;StaticJsonRpcProvider&lt;/code&gt; merges into &lt;code&gt;JsonRpcProvider&lt;/code&gt;. Handles destructured &lt;code&gt;import { providers }&lt;/code&gt; by injecting the specific v6 names that were actually used.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Web3Provider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JsonRpcProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BrowserProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ethereum&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;JsonRpcProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;gasPrice-to-feeData&lt;/strong&gt; — Rewrites &lt;code&gt;await provider.getGasPrice()&lt;/code&gt; by replacing the entire &lt;code&gt;AwaitExpression&lt;/code&gt; node. This means the parentheses around the await are handled automatically by recast's printer based on operator precedence — I don't insert them manually.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gasPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getGasPrice&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gasPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFeeData&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;gasPrice&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;rename-constants&lt;/strong&gt; — Replaces all &lt;code&gt;ethers.constants.*&lt;/code&gt; accesses with their v6 equivalents. Named constants become top-level properties (&lt;code&gt;AddressZero → ZeroAddress&lt;/code&gt;, &lt;code&gt;MaxUint256 → MaxUint256&lt;/code&gt;). The four numeric constants become native bigint literals since BigNumber is gone.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AddressZero&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MaxUint256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;One&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;zero&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ZeroAddress&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;max&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MaxUint256&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;one&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;rename-contract-methods&lt;/strong&gt; — Rewrites the four v5 contract method bucket patterns. In v5, less-common operations were accessed via intermediate buckets (&lt;code&gt;callStatic&lt;/code&gt;, &lt;code&gt;estimateGas&lt;/code&gt;, &lt;code&gt;populateTransaction&lt;/code&gt;, &lt;code&gt;functions&lt;/code&gt;). In v6 they moved to direct methods on the contract function itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callStatic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gas&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;estimateGas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;balanceOf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;staticCall&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;gas&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transfer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;estimateGas&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;rename-provider-methods&lt;/strong&gt; — Handles three provider/transaction method changes. &lt;code&gt;sendTransaction&lt;/code&gt; was renamed on the Provider side to &lt;code&gt;broadcastTransaction&lt;/code&gt; (Signer's &lt;code&gt;sendTransaction&lt;/code&gt; is unchanged — the transform adds a TODO so you can verify which one it is). &lt;code&gt;parseTransaction&lt;/code&gt; and &lt;code&gt;serializeTransaction&lt;/code&gt; became &lt;code&gt;Transaction.from()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signedTx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parseTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// after (with TODO comment added for sendTransaction)&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;broadcastTransaction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;signedTx&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;update-imports&lt;/strong&gt; — Runs last. Removes deprecated specifiers (&lt;code&gt;utils&lt;/code&gt;, &lt;code&gt;BigNumber&lt;/code&gt;, &lt;code&gt;providers&lt;/code&gt;, &lt;code&gt;constants&lt;/code&gt;) from &lt;code&gt;import { ... } from 'ethers'&lt;/code&gt; declarations once the other transforms have finished introducing their replacements. If no specifiers remain, it removes the entire import statement.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// before&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;utils&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BigNumber&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// after&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Contract&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ethers&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Does it actually work on real code?
&lt;/h2&gt;

&lt;p&gt;I ran the pipeline against &lt;a href="https://github.com/Uniswap/v3-periphery" rel="noopener noreferrer"&gt;Uniswap/v3-periphery&lt;/a&gt;, which is on ethers &lt;code&gt;^5.0.8&lt;/code&gt; — a production-grade codebase I had no hand in writing.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Files scanned&lt;/td&gt;
&lt;td&gt;31&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files automatically migrated&lt;/td&gt;
&lt;td&gt;28&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lines changed&lt;/td&gt;
&lt;td&gt;502 lines (231 insertions, 271 deletions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Files flagged for AI review&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Automated coverage&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;90.3%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;False positives&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I verified every change with &lt;code&gt;git diff&lt;/code&gt; before counting. The 0 false positives claim I validated separately: running the same pipeline against scaffold-eth-2 (already on ethers v6) produced 0 changes and 0 TODOs.&lt;/p&gt;

&lt;p&gt;One honest limitation: the codemod only tracks direct imports from &lt;code&gt;'ethers'&lt;/code&gt;. If your project wraps ethers behind an internal utility library or re-exports it from an index file, the transforms won't fire. I decided false negatives (missed cases) are safer than false positives (broken code), so the conservative approach was the right call.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the AI handles
&lt;/h2&gt;

&lt;p&gt;The 3 flagged files — &lt;code&gt;PairFlash.spec.ts&lt;/code&gt;, &lt;code&gt;snapshotGasCost.ts&lt;/code&gt;, &lt;code&gt;TickLens.spec.ts&lt;/code&gt; — all had the same pattern: BigNumber method calls on variables that came from contract return values or function parameters. The codemod added a comment to each one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// TODO(ethers-codemod): verify this BigNumber method call and migrate manually&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;returnedFromContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toNumber&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For these, I used this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;I&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;m migrating from ethers.js v5 to v6. In v6, BigNumber is replaced by native bigint.
The codemod flagged this code because it couldn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="nx"&gt;statically&lt;/span&gt; &lt;span class="nx"&gt;confirm&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;receiver&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt;
&lt;span class="nx"&gt;BigNumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt; &lt;span class="nx"&gt;Please&lt;/span&gt; &lt;span class="nx"&gt;help&lt;/span&gt; &lt;span class="nx"&gt;me&lt;/span&gt; &lt;span class="nx"&gt;migrate&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;paste&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;flagged&lt;/span&gt; &lt;span class="nx"&gt;code&lt;/span&gt; &lt;span class="nx"&gt;block&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="nx"&gt;Key&lt;/span&gt; &lt;span class="nx"&gt;rules&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toNumber&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nx"&gt;the&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="nx"&gt;fits&lt;/span&gt; &lt;span class="nx"&gt;safely&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;JS&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toHexString&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nf"&gt;x  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;both&lt;/span&gt; &lt;span class="nx"&gt;sides&lt;/span&gt; &lt;span class="nx"&gt;must&lt;/span&gt; &lt;span class="nx"&gt;be&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="err"&gt;—&lt;/span&gt; &lt;span class="nx"&gt;check&lt;/span&gt; &lt;span class="nx"&gt;that&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="nx"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;also&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;Values&lt;/span&gt; &lt;span class="nx"&gt;returned&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="nx"&gt;contract&lt;/span&gt; &lt;span class="nx"&gt;calls&lt;/span&gt; &lt;span class="nx"&gt;are&lt;/span&gt; &lt;span class="nx"&gt;already&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nx"&gt;ethers&lt;/span&gt; &lt;span class="nx"&gt;v6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;no&lt;/span&gt; &lt;span class="nx"&gt;conversion&lt;/span&gt; &lt;span class="nx"&gt;needed&lt;/span&gt;
&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;If&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="nx"&gt;could&lt;/span&gt; &lt;span class="nx"&gt;exceed&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MAX_SAFE_INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;keep&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;bigint&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three files, one prompt each, done in under ten minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;How to use it right now&lt;/strong&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx ts-node src/run.ts ./your-project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runner finds all &lt;code&gt;.ts&lt;/code&gt;, &lt;code&gt;.tsx&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.jsx&lt;/code&gt; files, skips anything with no ethers imports, runs all 5 transforms in the correct order, and prints a summary with per-transform change counts and a list of any files that need AI review.&lt;/p&gt;

&lt;p&gt;Source and full documentation: &lt;strong&gt;&lt;a href="https://github.com/Chinyereee/ethers-v5-to-v6-codemod" rel="noopener noreferrer"&gt;https://github.com/Chinyereee/ethers-v5-to-v6-codemod&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;28 files migrated automatically. 502 lines changed with zero false positives. 3 files handed off to AI with precise, targeted prompts. Total time to run: under 30 seconds.&lt;/p&gt;

&lt;p&gt;This is what software maintenance should look like. Mechanical changes — the ones with one right answer — get automated at the AST level, fast and correct. Human judgment gets reserved for the semantic changes that actually need it: the data flow questions, the precision questions, the "what did the original author intend" questions that no static tool can answer reliably. The codemod tells you exactly which files those are and why. The AI handles them in minutes.&lt;/p&gt;

&lt;p&gt;The weekend you were dreading becomes an afternoon. Most of it spent verifying a diff, not writing one.&lt;/p&gt;

&lt;p&gt;A note on the test repo choice: I tried scaffold-eth-2 first. It was already on v6 — which was actually useful, it confirmed the codemod produces zero changes on modern code. But I needed a real v5 target. Uniswap v3-periphery is widely known, actively maintained, and represents how real protocols actually use ethers. It felt like the honest benchmark to report against.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>automation</category>
      <category>etherjs</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
