How I Pick My Stack for Vibe Coding
Since I went all-in on vibe coding — around the time Claude 3.5 Sonnet made agentic AI editors genuinely useful — I’ve noticed that my technology selection process has settled into a repeatable, opinionated pattern. Every time I start something greenfield, I go through roughly the same mental checklist. This post documents that checklist.
What I Optimise For
Every decision comes back to three dimensions:
- Readability — how easy is it for me (and the AI) to read, understand, and confidently edit the code?
- Ecosystem — are the libraries, tooling, and community support mature enough that the AI has been trained on plenty of real-world examples?
- Speed — runtime performance; how fast will the resulting software actually be?
I grade these A, B, or C. No framework is perfect at everything and pretending otherwise wastes time.
A quick note on AI knowledge: all five languages below are too popular and well-documented for AI to struggle with any of them. That concern simply doesn’t factor into my decision.
Choosing a Programming Language
This applies when I’m building a library, a CLI tool, or a backend service with no frontend constraints.
| Language | Readability | Ecosystem | Speed |
|---|---|---|---|
| Python | A | A | C |
| TypeScript | B | A | B |
| C# | B | B | B |
| Go | B | B | B |
| Rust | C | B | A |
Python wins on readability and ecosystem but pays for it at runtime. Rust is the opposite — the ownership model and lifetimes make the code harder to reason about quickly, but the performance ceiling is essentially the highest you can get in userspace. TypeScript, C#, and Go all sit in a comfortable middle ground where the trade-offs are less dramatic.
For most business logic work where runtime performance is not the primary constraint, Python is my default. When I need native performance or the project is inherently systems-level, I reach for Rust or Go.
Choosing a Web Framework
Once the language is chosen, the framework decision follows roughly the same logic, with two extra dimensions: how much production code you actually have to write and eyeball yourself, and how much memory the running server will consume.
| Framework | App size | Manual code review | Speed | Memory |
|---|---|---|---|---|
| Django + Django Ninja | Big | Detailed | C | C |
| FastAPI | Big | Detailed | C | C |
| ASP.NET Core | Big | Light | B | B |
| Gin | Medium | Light | B | A |
| Axum | Small | None | A | A |
A few notes on this table:
Django + Django Ninja and FastAPI both get a C for speed and memory because the ceiling is Python’s ceiling, not the framework’s. FastAPI has a real async performance advantage over vanilla Django, but when you’re comparing across the full language spectrum that advantage doesn’t move the grade.
ASP.NET Core benefits from the .NET runtime’s mature JIT and a lighter review burden because C#’s strong type system and tooling surface many issues before code review.
Gin earns its A for memory thanks to Go’s small runtime and efficient concurrency model. App size is smaller than the JVM or Python stacks, and the review burden is light.
Axum earns “Manual code review: None” because Rust’s compiler is essentially the code reviewer. Memory safety, null safety, and data-race freedom are all enforced at compile time. You still review business logic, but the class of bugs that typically consumes review hours is eliminated before the PR even opens.
What about a modern frontend?
If the project needs a rich frontend, I’ll often drop Supabase in to handle auth, the database, and storage so I can get started quickly. However, I keep all the business logic in one of the backend frameworks above — not in Supabase itself. On a mid-sized project I tried coupling business logic tightly to Supabase’s edge functions and the result was painful: everything was entangled with PostgreSQL and the escape hatches were awkward. Supabase is a great accelerator for the infrastructure layer, not a replacement for a proper service layer.
Choosing a Desktop or Mobile UI Stack
Native first — now that vibe coding makes it approachable
Before AI-assisted coding, “native” meant weeks of learning platform-specific idioms. With vibe coding, the AI handles most of that. My default is now whichever stack the platform’s own documentation recommends:
- Windows — WinUI 3 with C# (Microsoft’s current recommendation for modern Windows apps)
- Android — Kotlin with Jetpack Compose
- iOS / macOS — Swift with SwiftUI
When to go cross-platform instead
I only reach for a cross-platform framework if the project genuinely needs to run on multiple platforms. Even then, I ask three questions:
-
Is the app simple enough to vibe code separately for each platform? Honestly, almost never — unless it’s a single-screen utility. A non-trivial app always benefits from a shared codebase.
-
Does the app need low-level APIs that the cross-platform framework can’t reliably expose? The Play Integrity API on Android is a good real-world example: technically reachable via platform channels, but fragile and high-maintenance. In that case I’d rather build the native Android app first and expand later if the app succeeds.
-
Does the app require top-end performance that a cross-platform framework can’t deliver? Same answer — drop platforms and go native on the highest-priority one first.
One exception: GNU/Linux. If I need a desktop app that runs on Linux, I’ll almost certainly use a cross-platform framework. The Linux desktop ecosystem is fragmented, inconsistent, and — to put it diplomatically — not a place I want to spend implementation time.
Which cross-platform framework?
My shortlist is three:
| Framework | When I use it |
|---|---|
| Flutter | UI is simple, performance matters, and I want consistent visuals across platforms |
| Electron | UI is complex and I need consistent rendering; I’m willing to trade binary size and memory for predictability |
| Tauri | UI is complex and I need a smaller, faster binary; I accept that web view differences across platforms will require extra polish to reach production quality |
Flutter’s rendering engine means it looks and behaves the same everywhere, which significantly reduces the QA surface. For anything with a rich, interaction-heavy UI, I lean toward web technologies because the tooling, layout primitives, and community knowledge for complex interfaces are simply better there. Between Electron and Tauri, the choice is a straightforward performance-vs-predictability trade-off: Electron ships Chromium so you know exactly what you’re getting; Tauri defers to the system web view, which is faster and leaner but introduces platform-specific rendering differences that add friction before you can call the app production-ready.
Closing Thoughts
The pattern boils down to this: start with the constraints that can’t be changed (target platforms, performance requirements, deployment environment), then let readability and ecosystem drive the language choice, and let the expected app size and review overhead drive the framework choice. Vibe coding hasn’t changed what a good stack looks like — it has just made it easier to execute on whichever choice you make.
Please let me know your opinions about my opinionated stack picking strategy for vibe coding in the comments.
By submitting a comment, your IP address will be stored in a database on Cloudflare. If you wish to prevent this, please use a VPN.
Your comment has been submitted and is awaiting moderation.
No comments yet. Be the first to comment!