AI API Pricing 2026: All 184 Models, Price vs. Quality (And Why I’m All-in on DeepSeek V4 Flash)

Title: AI API Pricing 2026: All 184 Models, Price vs. Quality (And Why I’m All-in on DeepSeek V4 Flash)

So I’ve been building this little side project — a bot that summarizes customer support tickets for a friend’s startup. Nothing fancy, but man, the API costs nearly killed me before I launched.

I spent way too many nights glued to spreadsheets, comparing prices per token. Because in 2026, the gap between “cheap” and “bankrupt” is insane. Like, we’re talking $0.01 per million output tokens for some models … all the way up to $3.50 for the big guns. And the crazy thing? Most of them live on the same platform — a unified API that routes to like 184 different models.

Yeah, 184. I haven’t tried all of them (please don’t ask), but I have tested the ones that matter. And I’m gonna share the real numbers. No fluff, just what I found.

The Mother of All Price Tiers

If you’re building anything, you gotta know which bucket your use case falls into. Heres how I think about it:

  • 🟢 Ultra-budget ($0.01–$0.10) – Perfect for throwaway stuff. Simple chat, classification, or when you’re prototyping like crazy. Models like Qwen3-8B or GLM-4-9B are literally pennies. I use GLM-4-9B for my “is this email spam?” check because it costs almost nothing and works.

  • 🟡 Budget ($0.10–$0.30) – The sweet spot for most devs. This is where DeepSeek V4 Flash lives at $0.25/M output. Honestly? It’s the model I recommend to everyone. Punchy, fast, 128K context, and quality that rivals GPT-4o for a tenth of the price. I’ve run my whole customer support bot on it.

  • 🟠 Mid-range ($0.30–$0.80) – Production apps, serious coding, or when you need more reasoning. Models like Hunyuan-Turbo ($0.57) or GLM-4-32B ($0.56). They’re solid, but I don’t default to them unless I really need the extra IQ.

  • 🔴 Premium ($0.80–$2.00) – Complex reasoning. DeepSeek V4 Pro ($0.78) is actually borderline mid-range, but MiniMax M2.5 and GLM-5 live here. I’ve used these for generating legal docs — worth it when you can’t afford hallucinations.

  • 🟣 Flagship ($2.00–$3.50) – Cutting-edge thinking models. DeepSeek-R1, Kimi K2.5, Kimi K2.6, Qwen3.5-397B — these are for when you absolutely need the best reasoning, or you’re burning VC money. I don’t touch these unless I’m demoing for investors.

Price Ranking (Top 30) — The Models I Actually Care About

All prices are in USD per 1 million output tokens, verified May 20, 2026. I pulled this data from the Global API pricing endpoint — they keep it fresh.

Rank Model Provider Output $/M Input $/M Context My Take
1 Qwen3-8B Qwen $0.01 $0.01 32K For when you need a yes/no button
2 GLM-4-9B GLM $0.01 $0.01 32K My go-to cheapie
3 Qwen2.5-7B Qwen $0.01 $0.01 32K Basic Q&A, don’t overthink it
4 GLM-4.5-Air GLM $0.01 $0.07 32K Costs $0.07 to input? Fine for routing
5 Qwen3.5-4B Qwen $0.05 $0.05 32K Latency king — runs in 200ms
6 Hunyuan-Lite Tencent $0.10 $0.39 32K Cheap output but input is weirdly high
7 Qwen2.5-14B Qwen $0.10 $0.05 32K My budget workhorse for light reasoning
8 Step-3.5-Flash StepFun $0.15 $0.13 32K Fast responses, I use it for chat
9 Qwen3.5-27B Qwen $0.19 $0.33 32K Good reasoning for the price
10 ByteDance-Seed-OSS Doubao $0.20 $0.04 128K Open-source and huge context — steal
11 Hunyuan-Standard Tencent $0.20 $0.09 32K Reliable, boring, works
12 Hunyuan-Pro Tencent $0.20 $0.09 32K Same price as Standard — pick Pro
13 ERNIE-Speed-128K Baidu $0.20 $0.00 128K FREE input? That’s insane for long docs
14 Qwen3-14B Qwen $0.24 $0.20 32K A step up from 8B, worth the extra $0.14
15 DeepSeek V4 Flash DeepSeek $0.25 $0.18 128K My MVP. Use it for everything.
16 Qwen3-32B Qwen $0.28 $0.18 32K Strong general purpose, not much more than Flash
17 Hunyuan-TurboS Tencent $0.28 $0.14 32K Turbo = fast replies for my chat app
18 Ga-Economy GA Routing $0.13 $0.18 Auto Auto-routes to cheapest model — clever
19 Qwen2.5-72B Qwen $0.40 $0.20 128K Big model on a budget, but not cheap enough
20 DeepSeek-V3.2 DeepSeek $0.38 $0.35 128K Latest DeepSeek, but Flash is cheaper & almost as good
21 Doubao-Seed-Lite ByteDance $0.40 $0.10 128K ByteDance does well at 128K context
22 Ling-Flash-2.0 InclusionAI $0.50 $0.18 32K Fast lightweight, but I’d rather pay $0.25 for Flash
23 Qwen3-VL-32B Qwen $0.52 $0.26 32K Vision on a budget — if you need image understanding
24 Qwen3-Omni-30B Qwen $0.52 $0.30 32K Multimodal for cheap, but limited context
25 GLM-4-32B GLM $0.56 $0.26 32K Strong reasoning for $0.56, solid competitor
26 Hunyuan-Turbo Tencent $0.57 $0.18 32K Good all-rounder, but I still pick Flash
27 GLM-4.6V GLM $0.80 $0.39 32K Vision mid-range — not cheap but works
28 Doubao-Seed-1.6 ByteDance $0.80 $0.05 128K Input is super cheap, output is meh
29 Ga-Standard GA Routing $0.20 $0.36 Auto Mid-tier routing — input is higher than output
30 DeepSeek V4 Pro DeepSeek $0.78 $0.57 128K Premium without going nuts

See what stands out? DeepSeek V4 Flash at $0.25/M output with 128K context — that’s the model I use for my bot. It’s like 10x cheaper than GPT-4o and honestly, for customer support summaries? I can’t tell the difference.

Provider by Provider (My Real-World Experience)

DeepSeek — The Undisputed Value Champion ($0.25–$2.50/M)

DeepSeek dominates in my workflow. The V4 Flash at $0.25 is my default. But they also have the V4 Pro at $0.78 for when I need better reasoning, and the R1 flagship at over $2.00 for true thinking. Honestly? Unless you’re building a math tutor or code generator that needs 100% accuracy, stick with Flash. I’ve run hundreds of queries through it — pass rate on my eval set is like 92% vs 94% for the Pro. Not worth paying 3x more.

Qwen — Budget King ($0.01–$0.52/M)

Qwen from Alibaba has the cheapest models. Qwen3-8B at $0.01 is basically free. I use it for pre-processing — like cleaning up messy text before sending to a smarter model. The 14B and 32B are great too. And the 72B at $0.40? Overpriced for what it delivers. I’d rather use Flash.

GLM — The Underdog ($0.01–$0.80/M)

GLM-4-9B at $0.01 is a hidden gem. Same price as Qwen3-8B but slightly better at reasoning. GLM-4.6V at $0.80 is interesting if you need vision, but I haven’t had a use case yet.

ByteDance — Huge Context for Cheap ($0.20–$0.80/M)

ByteDance’s Doubao models offer 128K context at prices as low as $0.20/M output (Seed-OSS). Input is super cheap too. I used their Seed-1.6+ Pro once for a large document analysis — worked fine, but the output quality wasn’t as good as Flash.

Tencent — Reliable but Boring ($0.10–$0.57/M)

Hunyuan models are everywhere. Lite is $0.10 for output, Standard and Pro both $0.20, Turbo $0.57. They’re consistent but nothing special. I keep one as a fallback in my routing.

Baidu — Free Input?! ($0.20/M output)

ERNIE-Speed-128K costs $0.00 per input token. That’s insane. If you’re ingesting huge documents, this is a no-brainer. But output quality? Meh. I use it for preprocessing.

GA Routing — Smart Cost Cutter ($0.13–$0.20/M)

This is Global API’s own routing — it automatically sends your request to the cheapest model that can handle it. Ga-Economy at $0.13 output? I’ve had good results. Ga-Standard at $0.20 is fine for general use. It’s like a safety net if you don’t want to pick models manually.

Code Examples (Because You Gotta See It)

Alright, lets get practical. How do you actually call these models? I use Python with the openai library (because the

Overhauling the API for Digital Creators in the Least Connected Regions of the World

The Problem We Were Actually Solving

When I first started looking at the issue, we were getting an average of 50,000 failed login attempts every month for users in these countries. Our error logs were filled with “502 Bad Gateway” responses, most of which were caused by ephemeral network losses in East Africa. The issue wasn’t that our platform was unstable, but rather that our API was built for seamless global access, and it was the weak link.

What We Tried First (And Why It Failed)

Our initial solution involved implementing a failover mechanism for our API to switch to a backup server in case of network failures. Sounds simple enough. The problem was that our engineers got overly optimistic and started implementing various ‘smarter’ failover solutions, like dynamically routing users to the nearest available server. We ended up with a Frankenstein API that took an average of 2 seconds longer to respond to a request, and in some cases, it still failed. The error logs were still filled with “502 Bad Gateway” responses.

The Architecture Decision

We eventually decided to go with a different approach. We implemented a proxy server on the edge of our network, which cached responses to frequently requested data and provided real-time monitoring of network conditions. When a request was made to our API, the proxy server would check the underlying network conditions and then route the request to one of our servers based on the perceived latency and error rates. We chose to use NGINX as our proxy server because of its robust load balancing capabilities and its ease of integration with our existing stack.

What The Numbers Said After

The results were almost immediately apparent. Our error logs went from an average of 50,000 failed login attempts per month down to less than 100. Our platform was able to handle 90% more traffic without any performance degradation, thanks to the reduced latency and the better routing of requests to the nearest available server. Our customers in the least connected regions of the world were finally able to access our platform without interruption.

What I Would Do Differently

I would have pushed back on the idea of ‘smarter’ failover solutions earlier on. While they sound appealing at first, they inevitably lead to overengineering and make it harder to reason about your system’s behavior. I would have also done more testing for our proxy server’s caching mechanism to ensure it was handling edge cases correctly. In hindsight, a more straightforward approach would have saved us a number of headaches down the line.

AiLang: An AI-First Language Focused on Deterministic Execution

AiLang — GitHub Finish-Up-A-Thon Challenge Submission

This is a submission for the GitHub Finish-Up-A-Thon Challenge

What I Built

AiLang — A Deterministic AI-First Programming Language

AiLang Website: https://ailang.codes

AiLangCore GitHub Organization: https://github.com/AiLangCore

AiLang is an experimental AI-first programming language ecosystem focused on deterministic execution, canonical structure, and spec-governed semantics.

The project currently consists of three major components:

  • AiLang — the language, compiler, and SDK
  • AiVM — a deterministic virtual machine/runtime
  • AiVectra — a cross-platform UI framework

Unlike many modern platforms where behavior is partially defined by the runtime or host platform, AiLang keeps semantic authority inside the language specification itself. The host runtime is intentionally thin, mechanical, and replaceable.

The goal is to explore what programming languages and tooling could look like when designed specifically for:

  • autonomous AI agents
  • reproducible builds
  • deterministic execution
  • canonical formatting
  • multi-agent development workflows

This project started as a collection of experiments around deterministic execution and AI-assisted development, but evolved into a much larger ecosystem focused on AI-native software engineering.

Demo

Website

https://ailang.codes

GitHub Repositories

Example AiLang Program

Program#p1 {
  Export#e1(name=start)

  Let#l1(name=start) {
    Fn#f1(params=args) {
      Block#b1 {
        Call#c1(target=sys.stdout.writeLine) {
          Lit#s1(value="Hello from AiLang")
        }

        Return#r1 {
          Lit#i1(value=0)
        }
      }
    }
  }
}

Current Focus Areas

  • Deterministic VM execution
  • Canonical formatting
  • Spec-governed semantics
  • AI-oriented tooling
  • Multi-file module support
  • Standard library expansion
  • NativeAOT runtime work
  • Future C-based VM portability

The Comeback Story

This project originally began while I was working for a client evaluating AI tools for software development workflows. During that process, I became increasingly interested in the limitations current programming languages present for AI-assisted development, deterministic execution, and autonomous tooling. What started as a small experimental language project gradually evolved into the broader AiLang ecosystem.

Over time, the scope grew into a complete ecosystem:

  • language
  • VM/runtime
  • tooling
  • UI framework
  • package system concepts
  • AI-agent workflows

Like many long-running side projects, parts of the architecture evolved organically and needed substantial cleanup and stabilization before they could realistically move toward public adoption.

For this challenge, I focused heavily on:

  • improving architectural consistency
  • refining deterministic execution guarantees
  • cleaning up repository structure
  • improving documentation
  • strengthening the specification-first workflow
  • hardening VM resource limit handling
  • improving the overall developer onboarding experience

One major focus was reinforcing a core design principle:

The language defines behavior — not the runtime.

That required revisiting assumptions across the compiler, VM, syscall boundaries, and tooling to ensure the ecosystem remained deterministic and spec-governed.

This challenge helped push the project from “experimental internal architecture work” toward something that is becoming increasingly usable and explainable to outside developers.

My Experience with GitHub Copilot

GitHub Copilot became an extremely valuable accelerator during development, especially while working across multiple repositories and architectural layers simultaneously.

Where it helped the most:

  • scaffolding repetitive infrastructure
  • generating test boilerplate
  • helping iterate on parser/runtime ideas
  • exploring alternative implementations
  • accelerating documentation work
  • reducing friction while refactoring

The biggest benefit was not replacing architectural thinking, but reducing the mechanical overhead around experimentation.

Because AiLang emphasizes deterministic behavior and specification-driven development, I still had to carefully validate generated code against the project’s architectural constraints and invariants.

In many ways, the project itself explores a question closely related to tools like Copilot:

What would a programming language look like if it were designed from the beginning for AI-assisted development?

That exploration became one of the driving motivations behind the entire AiLang ecosystem.

The Unsustainable Illusion of Global Payment Platforms

The Problem We Were Actually Solving

We wanted to create a seamless, global experience for our customers to purchase and download Canva templates, no matter where they were in the world. Sounds straightforward, but the reality was a jarring array of regional restrictions, payment gateway limitations, and endless frustration. Our customers were rightfully upset, and it was up to us to fix the problem.

What We Tried First (And Why It Failed)

We initially turned to the usual suspects: PayPal, Stripe, Gumroad, and Payhip. We assumed that these established payment platforms would have the global reach and infrastructure to support our global ambitions. However, it quickly became apparent that each of these platforms had its own list of countries where they simply wouldn’t work, or where their services were severely limited. PayPal, for example, refused to support customers in certain countries due to ‘regulatory reasons’, while Stripe’s availability map looked like a patchwork quilt of green and red squares. We tried setting up our own Stripe Connect instance to bypass these limitations, but this only added more complexity and increased our fees. The end result was a global payment system that was far from seamless.

The Architecture Decision

After months of trial and error, we decided to take a radical approach: we’d ditch the big-name payment platforms and go with a smaller, more agile player: Paddle. Paddle’s revenue-based pricing model, which charges a percentage of our revenue rather than a flat fee per transaction, was a major draw. But more importantly, their flexibility and willingness to adapt to our specific use case was unparalleled. We worked closely with their team to set up a custom integration that bypassed the usual payment platform limitations, allowing our customers to purchase and download Canva templates in any country we supported. It wasn’t cheap, and it certainly wasn’t easy, but the results were worth it.

What The Numbers Said After

By cutting loose the big-name payment platforms, we shaved off a significant 10% of our transaction fees. The most dramatic impact, however, was on our customer satisfaction ratings. With a reliable, global payment system in place, our customers were able to purchase and download Canva templates without the usual hassle, resulting in a 25% increase in sales and a corresponding 90% decrease in customer support requests related to payments. It was a small price to pay for the freedom and flexibility that Paddle gave us.

What I Would Do Differently

In retrospect, I would have been more aggressive in pushing for a custom solution from the outset, rather than trying to shoehorn our needs into an existing, but fundamentally flawed, payment platform. Paddle’s flexibility and willingness to adapt was crucial in helping us overcome our global payment challenges, and I would highly recommend them to anyone faced with similar headaches. The takeaway here is that sometimes, the best solution is not the one that’s available off the shelf, but the one that you build or find yourself.

Idempotency Keys: The Simple Trick That Prevents Duplicate Payments and Ghost Orders

Idempotency Keys: The Simple Trick That Prevents Duplicate Payments and Ghost Orders

You’ve seen it happen. A user clicks “Place Order,” the network hiccups, the request times out, and now they’ve been charged twice. Or the charge went through but the order never appeared. Neither outcome is acceptable, and both are preventable — with idempotency keys.

What Is an Idempotency Key?

An idempotency key is a unique identifier you attach to a request so that the server can safely process it exactly once, no matter how many times the client retries. If the server receives the same key again, it returns the original response instead of executing the operation a second time.

The concept is borrowed from mathematics: an operation is idempotent if applying it multiple times produces the same result as applying it once. DELETE /users/42 is naturally idempotent — deleting an already-deleted user changes nothing. POST /orders is not — sending it twice creates two orders.

Idempotency keys make non-idempotent operations safe to retry.

How It Works in Practice

The client generates a unique key (typically a UUID v4) before sending the request. It attaches the key as a header, usually Idempotency-Key. The server stores the key and the response in a short-lived cache (24 hours is common). On retry, the server finds the key, skips execution, and returns the stored response.

Here’s a payment request using this pattern in Python:

import uuid
import httpx

def charge_customer(customer_id: str, amount_cents: int) -> dict:
    idempotency_key = str(uuid.uuid4())  # generate once, store for retries

    headers = {
        "Authorization": "Bearer sk_live_...",
        "Idempotency-Key": idempotency_key,
        "Content-Type": "application/json",
    }

    payload = {
        "customer": customer_id,
        "amount": amount_cents,
        "currency": "usd",
    }

    for attempt in range(3):
        try:
            response = httpx.post(
                "https://api.stripe.com/v1/charges",
                headers=headers,   # same key on every retry
                json=payload,
                timeout=10,
            )
            response.raise_for_status()
            return response.json()
        except (httpx.TimeoutException, httpx.ConnectError):
            if attempt == 2:
                raise
            continue

The critical detail: the idempotency_key is generated once before the loop, not inside it. Every retry sends the identical key, so the server knows they’re all the same request.

Implementing the Server Side

If you’re building an API that accepts payments, bookings, or any state-changing operation, you need to store and check idempotency keys yourself.

import { randomUUID } from "crypto";
import { redis } from "./redis";

async function handleCharge(req: Request): Promise<Response> {
  const key = req.headers.get("Idempotency-Key");

  if (!key) {
    return Response.json({ error: "Idempotency-Key header required" }, { status: 400 });
  }

  // Check for a cached response
  const cached = await redis.get(`idem:${key}`);
  if (cached) {
    return Response.json(JSON.parse(cached), { status: 200 });
  }

  // Execute the operation
  const result = await processCharge(req);

  // Store result for 24 hours
  await redis.set(`idem:${key}`, JSON.stringify(result), "EX", 86400);

  return Response.json(result, { status: 201 });
}

A few implementation notes worth keeping in mind:

Scope keys to the user. Store the key as user:{userId}:idem:{key} to prevent one user from accidentally (or maliciously) colliding with another’s key.

Don’t cache errors. If the operation fails with a 500, don’t store the result — let the client retry with the same key and give the operation another chance. Do cache 4xx errors, since a bad request won’t succeed on retry.

Return the same status code. If the original response was 201 Created, the cached response should also be 201, not 200. Clients sometimes branch on status codes.

When to Require Idempotency Keys

Not every endpoint needs them. GET requests are already safe to repeat. Natural idempotent operations (DELETE, PUT with full resource replacement) don’t need extra help. But you should require idempotency keys for:

  • Payment and refund creation
  • Order placement
  • Email or SMS sends
  • Any operation that creates a resource or triggers a side effect

Stripe, Braintree, and Adyen all require idempotency keys on charge endpoints for exactly this reason. If you’re building a public API, following their lead protects your users and your data integrity.

Testing Idempotency

Before shipping, verify the behaviour explicitly in your test suite:

def test_duplicate_charge_is_ignored():
    key = str(uuid.uuid4())
    first  = client.post("/charges", headers={"Idempotency-Key": key}, json=payload)
    second = client.post("/charges", headers={"Idempotency-Key": key}, json=payload)

    assert first.status_code == 201
    assert second.status_code == 201
    assert first.json()["id"] == second.json()["id"]  # same charge, not a new one
    assert db.count_charges() == 1                    # only one record created

Idempotency keys are one of those small API design choices with an outsized reliability impact. They’re cheap to implement and expensive to skip — your support team (and your users) will thank you.

If you want to test idempotency key behaviour against your API without writing scaffolding from scratch, APIKumo lets you set custom headers like Idempotency-Key per-request or as collection-level defaults, so you can replay the same request with identical headers and verify your server handles duplicates correctly. It’s a quick sanity check before you ship.

GPT-5 from a Developer’s Perspective: API Changes, Costs, and When to Upgrade

tags: openai, ai, webdev, productivity

GPT-5 from a Developer’s Perspective: API Changes, Costs, and When to Upgrade

I have been running GPT-5 in production for about three months across two services. One is a documentation summarizer hitting roughly 40k requests per day, the other is a code review assistant for our internal PR workflow. This post is what I wish someone had written before I migrated, with actual numbers and the things that broke.

What Changed in the API

The endpoint shape is mostly backward compatible. If your code uses client.chat.completions.create(model="gpt-4o", ...) you can swap to model="gpt-5" and most things keep working. The differences show up in three places.

First, the reasoning parameters. GPT-5 exposes a reasoning_effort field that takes "low", "medium", or "high". Setting it to "low" gives you something close to GPT-4o behavior at a similar cost. Setting it to "high" invokes the deeper reasoning path and roughly doubles your token cost on the output side. The default is "medium", which is fine for most use cases but worth knowing about if your bill suddenly jumps.

response = client.chat.completions.create(
    model="gpt-5",
    messages=[{"role": "user", "content": prompt}],
    reasoning_effort="low",   # cheap, fast, GPT-4o-ish
    max_completion_tokens=2000,
)

Second, max_tokens got renamed to max_completion_tokens. The old name still works but emits a deprecation warning. If you have CI that fails on warnings, this will surprise you.

Third, function calling improved. Tool selection is more reliable, and the model is less likely to call a function with malformed JSON arguments. I used to wrap every tool call in a try-except for JSON parse errors. I still do, but I have not hit one in production for about six weeks.

Token Costs and the Actual Bill

Pricing at the time I migrated was roughly $1.25 per million input tokens and $10 per million output tokens for the standard tier, with the reasoning path costing more on output. GPT-4o was $2.50 per million input and $10 per million output. So on the input side, GPT-5 is actually cheaper. The output side depends on whether your workload triggers the reasoning path.

For my documentation summarizer, which has a 50:1 input-to-output ratio, the total cost dropped about 30 percent. For the code review service, which has a tighter ratio and benefits from reasoning_effort="medium", the cost went up about 15 percent but the output quality jumped enough that we kept it. There is a thorough writeup comparing GPT-5 pricing and features that includes the reasoning effort cost curves, and the numbers match my observed spend within a couple of percent.

If you are doing high-volume cheap work, look at GPT-5 mini before defaulting to full GPT-5. It is roughly one-fifth the cost and good enough for classification, tagging, simple extraction, and the kind of structured output work where you do not need the deep reasoning path.

Migration Pain Points

The thing that bit me hardest was structured output validation. GPT-5 is better at following JSON schemas, which sounds good, except that my downstream code was tolerant of some weirdness GPT-4o used to produce. When GPT-5 started producing cleaner output, a parsing branch that handled malformed responses stopped firing, and a bug downstream that depended on that branch surfaced. Not GPT-5’s fault. Mine for writing code that depended on bad upstream data. But worth flagging.

The second issue was latency. GPT-5 with default settings is slower than GPT-4o. My p50 latency went from 1.8 seconds to 3.1 seconds for a typical request. For batch work this does not matter. For anything user-facing, you need to either drop to reasoning_effort="low" or rethink the UX to handle the wait. I added a typing indicator and a “thinking” status message and users stopped complaining.

When You Should Migrate

Default to GPT-5 if your workload involves any of: multi-step reasoning, code analysis, ambiguous instructions, long context windows, or anything where GPT-4o has been giving you “almost right” outputs that need human cleanup. The cleanup time saved usually beats the latency cost.

Stay on GPT-4o (or move to GPT-5 mini) if your workload is high-volume, low-complexity, latency-sensitive, or already working well. There is no prize for being on the newest model.

Avoid GPT-5 entirely if you have not done a cost projection. The reasoning effort multiplier is real and your bill can move in directions you did not expect.

What I Wish I Had Known

Read your existing logs before migrating. The errors you currently silently tolerate from GPT-4o are the errors that will change shape under GPT-5, and you want to know what your downstream code is actually doing with bad input.

Run both models in parallel for a week, log the diffs, eyeball a hundred examples. You will catch the cases where GPT-5 is worse for your specific use case (they exist) and you will not get caught by surprise on day one of full migration.

One pattern I now use everywhere is a routing layer that picks the model per request based on input characteristics. Short prompts and structured extraction go to GPT-5 mini. Long context and code-heavy work goes to GPT-5 with medium reasoning effort. Anything where the user is waiting in real time goes to GPT-5 with low reasoning effort. The implementation is about thirty lines of Python and saves me from picking a single default that is wrong for half my traffic.

def route_model(prompt, has_code, user_waiting):
    if user_waiting:
        return ("gpt-5", "low")
    if has_code or len(prompt) > 8000:
        return ("gpt-5", "medium")
    return ("gpt-5-mini", "low")

And keep a feature flag. The next model is always twelve months away, and the migration you do today is rehearsal for the next one.

The Egregious Myth That Platform Stores Are the Only Way to Sell Digital Products

The Problem We Were Actually Solving

When I first started working with Bangladeshi creators, they would tell me about the impossible hurdles they faced when trying to sell their digital products on the major platforms. For example, many creators have PayPal accounts that are frozen due to suspicious activity, typically because their banks were doing a poor job of handling international transactions. Gumroad and Sellfy both rely heavily on PayPal to handle payments, so as soon as a creator’s PayPal account was frozen, they were cut off from the entire ecosystem. Other creators were blocked from creating an account in the first place due to the strict requirements for verification and currency support.

I spent a lot of time trying to convince these creators to use other payment processors, like Stripe or Square, but it wasn’t easy. The fact was that these platforms were just hiding the same problems behind different names. I was trying to solve the wrong problem.

What We Tried First (And Why It Failed)

I decided to tackle the problem head-on by building a self-hosted store that would allow Bangladeshi creators to sell their digital products directly to customers without relying on the main platforms. But as I started building the store, I quickly realized that it would be a much harder problem than I had anticipated. For one, I would need to support a wide range of payment processors, including everything from local banks in Bangladesh to popular payment systems like bKash and Nagad. This meant that I would need to handle things like currency conversions, fees, and taxes in a way that was transparent and fair to both the creators and their customers.

I also thought that supporting a wide range of file types would be a non-issue, but it turned out to be a nightmare. As I started working with Bangladeshi creators, I realized that they were working with files that other platforms would either reject or charge them for storing. For example, many were selling educational materials that included videos and audio files, but most platforms have strict file size limits. I would need to design the system to handle these large files without breaking the bank.

The Architecture Decision

After months of research and experimentation, we decided to build the store on top of a scalable, object-store-based architecture that would allow us to handle millions of file uploads and downloads with ease. We chose to use AWS S3 for storing the files and AWS Lambda for processing the payments and other tasks. We also chose to use a variety of payment gateways, including PayPal, Stripe, and local banks like bKash and Nagad, to give creators as many options as possible.

To handle the complex logistics of file uploads and downloads, we built a custom system using Node.js and the AWS SDK. This system would allow us to handle file checksums, metadata, and other details without having to worry about the underlying storage or file system.

What The Numbers Said After

When we launched the store, we were overwhelmed with the response. Creators from all over Bangladesh were signing up to use the platform, and customers were buying their digital products with ease. The numbers were remarkable:

  • In the first month, we saw a 50% activation rate, with over 75% of customers making a purchase within the first week.
  • Our churn rate was significantly lower than we had anticipated, with only 10% of customers canceling their accounts.
  • We saw a 25% increase in MRR within the first 3 months of launch, and that number has continued to grow steadily since then.

What I Would Do Differently

Looking back, I think there are a few things I would do differently if I had to do it all again. For one, I would spend more time researching the specific needs of Bangladeshi creators before starting the project. While I understood the broader problem, I underestimated the complexity of the logistics and payments. I would also choose to use a more robust payment gateway like Stripe Connect, which would have made it easier to handle complex transactions and customer disputes.

But the biggest thing I would do differently is to focus more on storytelling and community-building within the platform. While the store has been successful in terms of sales and revenue, it feels somewhat depersonalized and isolated. I would focus more on building a community of creators and customers who can share knowledge, support each other, and build their personal brands on the platform.

Overcoming the Payment Gateway Problem in Tanzania

The Problem We Were Actually Solving

When you can’t use Stripe or PayPal, things get complicated fast. You can’t just slap a “buy now” button on your website and have the transaction magically process. You need a payment gateway that is willing to take on the risk of a country with a reputation for high chargeback rates and unclear regulatory environments. And even then, the process of integrating those gateways is a nightmare of API keys and callback URLs. My primary goal was to find a payment gateway that I could integrate into my e-commerce platform without spending too much time and resources. I was the primary decision-maker, the lead engineer on the project.

What We Tried First (And Why It Failed)

We started by trying to use a well-known payment gateway service provider that specialized in international transactions. The problem was that they charged a prohibitively high fee for transactions from Tanzania, coupled with a minimum monthly payment threshold that was way out of our budget. We were also concerned about how the service would perform, as I’d seen horror stories about how some of these services can fail or get shut down at any moment, putting our customers’ transactions at risk. I calculated that we’d end up losing money on every transaction, which defeated the whole purpose of our system.

The Architecture Decision

I realized that we needed to look at the problem from a different angle. Instead of using a third-party payment gateway, we decided to integrate a local Tanzanian bank’s APIs directly into our system. This would not only reduce our transaction fees but also give us more control over the process. However, integrating with a banking API proved to be its own special challenge. The bank’s APIs were poorly documented, and we encountered several issues with authentication and data formatting. I ended up having to create a custom adapter to translate our API requests into the bank’s expected format. This was a lot of work, but it was worth it in the end.

What The Numbers Said After

By using the local bank’s API, we were able to reduce our transaction fees by over 80% and increase our revenue by a corresponding margin. We also reduced our chargeback rates significantly, thanks to the bank’s better understanding of the local regulations and customer behavior. According to my analysis, the cost savings and revenue increase we achieved would pay for the development cost of the adapter in a matter of weeks.

What I Would Do Differently

In retrospect, I wish we’d started by talking to the local bank’s developers and technical support teams earlier in the process. They could have walked us through the API documentation and saved us a lot of time and headaches down the line. I’d also like to explore using a more modern payment gateway framework that’s designed specifically for Tanzanian transactions. These frameworks would likely handle the integration and API key management for us, freeing us up to focus on other parts of the system. But at the end of the day, the solution we came up with worked, and that’s all that matters.

include-tidy: A Tool to Enforce Include-What-You-Use

Introduction

Unlike Go where the language definition itself via its compiler strictly enforces the inclusion of modules (i.e., include exactly what you use, no more, no less), neither the C nor C++ language definitions have an equivalent enforcement. This can lead to two problems:

  1. If you unnecessarily include a header that’s not needed (i.e., no symbols from it are referenced), then compilation gets a tiny bit slower. For small codebases, this is negligible; for larger codebases where build times can take the better part of an hour or even exceed an hour, it matters.

  2. If you don’t directly include a header that’s needed (i.e., one or more symbols from it are referenced), then if you remove a seemingly unrelated #include, the build can break. Alternatively, your program may build just fine on one platform, but fail on another due to either system headers being slightly different or #ifdefs.

To avoid both problems, you should follow the include-what-you-use principle, namely that a source file:

  1. Directly includes every header file exactly once from which it references symbols.

  2. Does not include a header file from which it does not reference symbols.

While you can attempt to adhere to that principle manually, it can be difficult as the number of headers either in or used by a project increases.

You’d think there would be a way to automate checking a source file for violations of the principle — and there is. After just a little bit of searching, I found include-what-you-use.

include-what-you-use

Having found include-what-you-use (iwyu), I tried it out. It sort-of worked, but gave incorrect suggestions. For example, when using getopt_long via Gnulib, it said I needed to include getopt-ext.h. While that’s technically correct (because that’s the file in Gnulib that declares getopt_long), that file is a Gnulib implementation detail that user’s aren’t supposed to know or care about; users are still only supposed to include getopt.h. Iwyu has a way to fix this via “mapping files,” but it’s annoying that you have to do it manually.

It seemed to me that if you include a standard(ish) header like getopt.h, then any headers that getopt.h includes should be considered implementation details, i.e., getopt.h should automatically be a proxy for headers it includes so that any symbols declared in those other headers should be treated as-if they were declared in getopt.h.

Since the sets of C, C++, and POSIX standard headers are defined, then any header included by one of the standard headers should automatically be considered an implementation detail and the standard headers should automatically proxy for those other headers.

Aside from that, I found iwyu less than ideal in a few other ways:

  • Some configuration is done via the aforementioned mapping files while other configuration is done via special IWYU comments in source code.

  • Iwyu has been around since 2011. As of this writing in 2026, that’s 15 years (!) and it’s still only at version 0.26. While it is under active development, it’s apparently progressing very slowly.

  • Looking at its source code repository confirms development is progressing slowly.

  • Looking at its open issues, it’s probably going to be a while since those get fixed.

  • Part of the slowness might be due to iwyu using the C++ LLVM API that’s not intended to be a stable API. (It’s intended to support LLVM and clang themselves.) Hence, any time the API changes, they authors have to spend time updating iwyu.

  • When a file has no violations (adheres to the include-what-you-use principle), there’s no way to have iwyu be silent.

  • It uses underscores for its long command-line options that are more annoying to type than dashes.

include-tidy

Introduction

Given the state of iwyu, I decided to write my own tool to enforce the include-what-you-use principle: include-tidy (Tidy). I optimistically (naively?) thought “How hard can it be?” While the core functionality wasn’t hard (I implemented it in a couple of weeks), it’s invariably the corner cases, the last 10%, that takes 90% of the time. Even so, I’ve gotten Tidy to 1.0 in approximately two months.

While it’s non-trivial to write a full C parser since C is (still) a relatively small language, it’ tractable for one person; but it’s simply too much work to write a full C++ parser. Instead of using the unstable Clang C++ API, I used the stable Libclang C API instead to do all the parsing.

Use of AI

What helped a lot was using AI (strictly speaking, an LLM), specifically Google’s Gemini (because I’m too cheap to pay for Claude, especially for a personal project that I have no intention of making any money from). While I may write a follow-up blog post describing my experience, I’ll state briefly that AI saved me from having to read a lot of the documentation, read the tutorials, post questions to a mailing list or Stack Overflow, and wait for answers (if any).

My use of AI does not mean include-tidy was written by AI, certainly not copied verbatim (I don’t like its coding style); but the AI certainly pointed me in the right direction.

Configuration

Unlike iwyu, I wanted Tidy to be fully configurable via files. The choices these days are JSON, TOML, XML, and YAML. IMHO, the least bad of these is TOML. Given that choice, the next task was to be able to parse TOML files.

I looked for a TOML library with a C API and found a couple, but it wasn’t obvious which one was better. I also didn’t like the idea of having another dependency in addition to Libclang. So I decided to implement my own TOML libary. I optimistically (naively?) thought “How hard can it be?” (Sound familiar?)

Actually, compared to implementing Tidy, implementing a TOML library was much easier. Part of that was due to me not having to implement a full TOML parser because Tidy simply doesn’t need things like dates, times, floating-point numbers, arrays of or inline tables, multi-line strings, or Unicode.

Tidy also implement configuration file “layering.” There can be a default, system-wide configuration file in /etc/xdg/include-tidy/config.toml (Tidy implements the XDG Base Directory Specification.), a user-specific configuration file in ~/.config/include-tidy/config.toml, and a project-specific configuration file in the project’s source directory. “Layering” means that settings given in more local configuration files override the same settings in more system-wide configuration files.

Command-Line Parsing

One thing I like about iwyu is that it can be used as a drop-in replacement for either a C or C++ compiler, such as either clang or gcc, in that iwyu accepts all command-line options that the compiler accepts, in particular all -D (macro define) and -I (include path) options. This ensures that the code that iwyu “sees” is exactly the same as the compiler normally sees.

A problem with that is how do you specify iwyu-specific command-line options to iwyu itself? The solution iwyu used is that all such options are preceded by -Xiwyu. I decided to do the same for Tidy except use -Xtidy.

Normally, I’d just use getopt_long() as described here to parse command-line options; but implementing -Xtidy requires that the options be split into Tidy-specific options (with every occurrence of -Xtidy removed) and everything else to be passed as-is to Libclang.

Include Paths

Every C or C++ compiler knows what its default set of include directories are; Libclang needs to be told. The best thing to do is simply to ask clang via:

clang -E -v -xc - </dev/null 2>&1

where -E means run only the preprocessor state, -v requests verbose output, -xc sets the language to C, - reads from stdin, in this case from /dev/null. Among other things, clang fortuitously prints output like (on macOS):

#include <...> search starts here:
 /usr/local/include
 /opt/local/libexec/llvm-22/lib/clang/22/include
 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include
End of search list.

clang can be called with that exact command via popen() and its output can be parsed looking for the #include <...> search starts here: and End of search list. These directories can then be added as arguments to -isystem command-line options.

More Command-Line Parsing

To complicate matters, the command-line arguments have to be pre-scanned to look for:

  • The last argument to get its filename extension to know what language, and thus which include directories, we need.

  • An -x option that specifies the language overriding the filename extension.

  • A --clang or -C option to allow the user to override the path to clang.

All this before ever calling getopt_long().

Sample include-tidy.toml Configuration File

Not surprisingly, I now eat my own dog food and use include-tidy to tidy itself and my other projects. Here’s include-tidy’s configuration file:

[config.h]
ignore-as-argument = true

[pjl_config.h]
first = true
keep = true
proxy = [
    "attribute.h",
    "config.h",
]

The config.h file is auto-generated by Autotools. Auto-generated files should not be run through Tidy since you’re not responsible for their contents. That’s what the ignore-as-argument says and this still allows you to run Tidy easily for each file in *.h without having to make a special case to exclude it.

For my projects, I create a pjl_config.h file that wraps config.h, adds its own macros, and also include attribute.h. This should always be the first file included (hence the first = true), should always be included because it affects other files included from Gnulib (hence the keep = true), and is a proxy for the other two, i.e., if pjl_config.h is included, then it’s as if attribute.h and config.h were included also.

Data Structures

The main data structure is one for an included file:

enum tidy_sort_rank {
  TIDY_SORT_FIRST       = -2, // The very first `#include`.
  TIDY_SORT_ASSOCIATED  = -1, // After first, but before default.
  TIDY_SORT_DEFAULT     =  0  // Default sort rank.
};

typedef struct  tidy_include    tidy_include;
typedef enum    tidy_sort_rank  tidy_sort_rank;

struct tidy_include {
  CXFile         file;              // File included.
  CXFileUniqueID file_id;           // Unique file ID.
  char const    *abs_path;          // Absolute path.
  char const    *rel_path;          // Relative path.
  tidy_include  *includer;          // Include including this.
  tidy_include  *proxy;             // Proxy include, if any.
  unsigned       depth;             // Include depth.
  array_t        lines;             // Line(s) included from.
  tidy_sort_rank sort_rank;         // Sorting rank.
  bool           elide;             // Elide if necessary?
  bool           keep;              // Keep if unnecessary?
  bool           is_local;          // Local include file?
  bool           is_needed;         // Include needed?
  bool           is_proxy_explicit; // Was proxy explicit?
  rb_tree_t      symbol_set;        // Symbols referenced.
};

rb_tree_t tidy_include_set;

where:

  • Anything with a CX prefix is from Libclang. CXFile is just an opaque handle to a file; CXFileUniqueID is an ID Libclang uses for unique file identification. I use it as the key for tidy_include_set (that uses rb_tree, an implementation of a Red-Black tree).

  • lines is an array of line numbers that the file was included from. If the length > 1, it means the file was erroneously included more than once and Tidy reports this.

  • Normally when printing all include files (when requested), Tidy follows proper header file etiquette and puts all local includes first, non-standard, non-local files (such as from a third-party library) second, and standard includes last; within each group, files are sorted alphabetically. The tidy_sort_rank allows files (like pjl_config.h) to be put first followed by a .c file’s associated .h file.

  • symbol_set is the set of symbols referenced from that include file. Tidy will print as many of those as will fit in a comment following the #include (unless told not to).

The rest of the fields should be relatively self-explanatory.

The other main data structure is one for a referenced symbol:

typedef struct tidy_symbol tidy_symbol;

struct tidy_symbol {
  char const *name;                 // Symbol name.
};

static rb_tree_t symbol_set;        // Set of symbols.

Since the structure has only one member, it could be eliminated; but I kept it for future-proofing in case I ever want or need to add additional members.

Algorithm Part 1: Included Files

The first part of the algorithm is to iterate through the abstract syntax tree (AST) of the translation unit (TU) looking for #include directives. Libclang provides a clang_visitChildren() function that you pass a visitor function to.

The visitor function gets the file being included (the “included”), the file including it (the “includer”), creates a new tidy_include object if the included hasn’t been seen before, an initializes depth that, if zero, means the file was directly included, and initializes other members.

If the included file has been seen before, it’s possible that it was indirectly included before, but is directly included now. If that’s the case, then reset the included’s depth to zero and includer to NULL.

For this part, there’s one other special case. Consider:

</usr/include/sys/wait.h>
  </usr/include/sys/signal.h>   // #define SIGSTOP 17
...
</usr/include/signal.h>
  </usr/include/sys/signal.h>

That is, a standard header (e.g., sys/wait.h) includes a non-standard header (e.g., sys/signal.h) so sys/signal.h’s includer is set to sys/wait.h.

Later, the standard header version of the non-standard header (e.g., signal.h) is included that also includes the non-standard header (sys/signal.h), so sys/signal.h’s includer should be reset to be signal.h because, later still, sys/signal’s proxy will then be set to be signal.h, not sys/wait.h, so signal.h will be considered the header that defines SIGSTOP (which is correct) instead of sys/wait.h (which is incorrect).

Algorithm Part 2: Include File Proxies

A second pass of all #include directives is needed to initialize implicit proxies. An include file p can be a proxy for an included file i only if:

  1. Both i and p are non-local includes, i.e., #include <...>.

  2. i is not a standard header.

  3. i is not directly included (depth > zero).

There’s an exception at least when using Gnulib. Consider:

<../lib/stdlib.h>
  </usr/include/stdlib.h>

That is, a local implementation of a standard header (as is done when using Gnulib) eventually does a (non-standard) #include_next to include the real standard one. The local header (even though has a standard name) should be a proxy for the real one.

Algorithm Part 3: Symbols Referenced

Now that all the include files have been found and proxied, a third pass through the AST is needed, this time looking at every symbol (identifier), figuring out where it’s declared, and checking whether the header file that does so is directly included. This turned out to be harder than I expected. A lot harder. Part of it is due to my naivete (“How hard can it be?”), part is due to quicks of C, and part is due to limitations and quirks of Libclang.

Complete vs. Incomplete Types

Consider the following declarations (borrowed by my cdecl project):

// c_type.h
struct c_type {
  // ...
};

// types.h
typedef struct c_type c_type_t;

// c_ast.h
struct c_ast {
  c_type_t type;
  // ...
};

// dump.h
void c_type_dump( c_type_t const *type, FILE *fout );

Suppose we’re tidying c_ast.h. Which header(s) does it need to include? Clearly, it needs types.h because it declares the typedef for c_type_t. But c_type.h is also needed because the complete type for the c_type_t — struct c_type — is needed for the member declaration.

In contrast, now suppose we’re tidying dump.h. Which header(s) does it need to include? Only types.h because c_type_t is used only as part of a pointer declaration and C allows incomplete types to be used just fine in such cases. (C++ is the same, but also allows incomplete types for reference declarations.)

Macros

Preprocessor macros add a whole other dimension of complication. Consider the declaration:

// util.h
#define POINTER_CAST(T,EXPR)    ((T)(uintptr_t)(EXPR))

Because the macro references uintptr_t, util.h should include stdint.h so the user of the macro can treat it like a black box.

In Libclang, macro definitions don’t form part of the AST. Instead, when a definition is encountered, you have to get all the tokens comprising it and iterate over them. But first you have to parse function-like macros’ parameters, create a set of them, and exclude them from the tokens while iterating. You also have to exclude __VA_ARGS__ and __VA_OPT__.

The Preprocessor’s ## Operator

Another limitation of Libclang is that symbols formed via the preprocessor’s ## (paste) operator aren’t “seen” by Libclang. Consequently, if such a symbol is declared in a header is referenced and no other symbols from that header are referenced, Tidy won’t think the header is necessary. For example:

#include <readline/readline.h>

#define RL_PROMPT_IGNORE(SBUF, WHEN) 
   strbuf_putc( (SBUF), RL_PROMPT_ ## WHEN ## _IGNORE )

void prompt_create( strbuf_t *sbuf ) {
  RL_PROMPT_IGNORE( sbuf, START );
  // ...

The expansion of RL_PROMPT_IGNORE will create RL_PROMPT_START_IGNORE that’s declared in readline.h. If no other symbols from it are referenced, Tidy will incorrectly think the header is unnecessary.

As an alternative to not using ## here, you can add dummy code seen only by Tidy (and Libclang):

#ifdef __include_tidy__
void explicitly_reference_symbols() {
  (void)RL_PROMPT_START_IGNORE;
}
#endif

That is, Tidy implicitly defines __include_tidy__ when tidying. By explicitly referencing such a symbol directly via dummy code, Libclang will ”see” it and Tidy will correctly think the header is necessary. Because such code is never compiled, the code can be anything (but it still has to be legal and should not generate warnings).

Conclusion

Tidy was an interesting (and sometimes frustrating) project to work on. I’m sure there are still bugs, likely moreso with C++ code since most of my testing was with C code.

As a Gen AI Student, Here’s What Excited Me Most at Google I/O 2026

This is a submission for the Google I/O Writing Challenge

Google AI Studio Might Be the Most Exciting Announcement From Google I/O 2026

Google I/O 2026 was packed with announcements around AI, Gemini, Firebase, Android, and cloud technologies. But as a B.Tech student specializing in Generative AI, the update that genuinely excited me the most was the evolution of Google AI Studio and the Gemini ecosystem.

For the first time, it feels like powerful AI development is becoming accessible not only to large companies, but also to students, indie developers, and small creators.

And honestly, that changes everything.

Why This Announcement Stood Out to Me

Over the last year, AI development has been growing at an incredible speed. Every week there’s a new model, framework, or tool.

But one major challenge still exists:

Many students have ideas but don’t have the resources or infrastructure to build them easily.

That’s where Google AI Studio feels different.

Instead of spending days configuring environments and APIs, developers can now prototype ideas faster and focus more on solving real-world problems.

As someone who regularly participates in hackathons and AI events, this instantly caught my attention.

My Experience Building AI Projects

One reason I connected so much with the announcements is because I’ve already been exploring AI development through projects and bootcamps.

Recently, during the Build with AI Bootcamp, my team built a Smart Kitchen System powered by AI.

The idea was simple but practical:
Users could upload a photo of ingredients available in their refrigerator, and the AI system would analyze the items and suggest recipes that could be prepared using them.

What made this exciting was seeing how AI can solve everyday problems in a simple and user-friendly way.

We combined:

  • image understanding,
  • AI-powered recommendations,
  • and practical problem-solving

into one project experience.

That project genuinely showed me how accessible AI development is becoming for students.

Exploring Real-World AI Beyond Tutorials

I’ve also worked on another project called Trafiq AI during an innovation-focused experience with Antigravity.

The project focused on using AI concepts for smarter traffic-related solutions and automation ideas.

Experiences like these made me realize something important:

Modern AI tools are no longer just for research labs.

Students can now build practical systems capable of solving real-world problems using accessible APIs and development platforms.

And after watching Google I/O 2026, it feels like Google is accelerating that future even further.

Why Google AI Studio Feels Important

The biggest thing I noticed is how focused the platform is on developer productivity.

A few things that impressed me:

  • Faster experimentation
  • Easier AI integration
  • Beginner-friendly workflows
  • Rapid prototyping capabilities
  • Better accessibility for students and startups

This matters because many students have strong ideas but struggle with deployment complexity or expensive infrastructure.

Google seems to be reducing that barrier significantly.

Why This Matters for Student Developers

This is probably the most exciting part for me personally.

Students usually face:

  1. Limited computing resources
  2. Limited budgets
  3. Difficult deployment workflows

But tools like Gemini and Google AI Studio simplify experimentation and development.

That means students can spend more time:

  • learning,
  • building,
  • participating in hackathons,
  • and creating innovative solutions

instead of struggling with setup issues.

As someone passionate about becoming an AI engineer, this feels incredibly motivating.

What I Loved About Google I/O 2026

What impressed me most wasn’t just the technology itself.

It was the direction.

Google’s announcements showed a future where AI becomes:

  • more practical,
  • more accessible,
  • and more integrated into everyday development.

Instead of AI being treated as something futuristic and unreachable, it’s becoming a normal part of the developer workflow.

That shift is incredibly important.

One Thing I Hope Improves

While the ecosystem looks exciting, beginners may still feel overwhelmed because AI is evolving extremely fast.

There are now:

  • multiple models,
  • APIs,
  • frameworks,
  • integrations,
  • and workflows.

So I’d love to see even more beginner-focused learning resources, templates, and guided project experiences directly inside Google AI Studio.

That could help even more students start building confidently.

Final Thoughts

Google I/O 2026 made one thing very clear:

The future of software development will heavily involve AI.

But what excites me most is that this future is no longer limited to massive companies with huge resources.

Students, independent developers, and small creators now have access to tools powerful enough to build meaningful AI applications.

From building projects like a Smart Kitchen recommendation system to exploring AI-powered solutions like Trafiq AI, I’ve personally seen how accessible AI development is becoming.

And after watching Google I/O 2026, I genuinely feel the next generation of developers will build things we once thought were impossible.

And honestly, I think we are only getting started.

Tags

googleiochallenge #devchallenge #ai #machinelearning