Tools are levers, not identities.
Technology gets chosen based on the problem in front of it, not the trend of the month. Click anything below for how and why it actually gets used.
TypeScript
Uses it for: The default for anything that will exist longer than a prototype.
Typical context: Every production project since 2022.
Why he likes it: Catches the mistakes that used to surface as bug reports.
When he avoids it: Rarely — occasionally skipped for a genuinely throwaway script.
JavaScript
Uses it for: For quick scripts and experiments that don't need the ceremony of types.
Typical context: Prototyping and small experiments.
Why he likes it: Fast to write, fast to throw away.
When he avoids it: Once a project has more than one contributor or a second week of life.
Python
Uses it for: Data cleanup, automation scripts, one-off analysis.
Typical context: Internal tooling, not client-facing products.
Why he likes it: Readable enough that a script from a year ago still makes sense.
When he avoids it: For anything needing a strict type system across a large codebase.
SQL
Uses it for: Directly, before reaching for an ORM's abstraction of it.
Typical context: Every project with a relational database.
Why he likes it: Nothing translates intent as precisely as writing the query itself.
When he avoids it: Never really — even with an ORM, understanding the generated SQL matters.
React
Uses it for: Interfaces with real state and interaction complexity.
Typical context: Product interfaces, dashboards, this site's interactive pieces.
Why he likes it: The component model matches how interfaces actually get more complex over time.
When he avoids it: For a mostly static page — that's often overkill.
Vue
Uses it for: Client projects where a gentler learning curve mattered for handoff.
Typical context: Threadline and a few client builds.
Why he likes it: Templates read closer to plain HTML, easier for a client's team to maintain.
When he avoids it: Rarely a first choice for personal projects now.
Plain HTML/CSS/JS
Uses it for: Static, content-first sites — like this one.
Typical context: Marketing sites, documentation, portfolios.
Why he likes it: No build step means no build step ever breaking at 2am.
When he avoids it: Once the interface needs real shared state across many views.
Framer Motion
Uses it for: The rare orchestrated animation moment that's worth the dependency.
Typical context: Used sparingly, for one meaningful transition at a time.
Why he likes it: Physics-based defaults feel less mechanical than easing curves alone.
When he avoids it: For hover states — CSS transitions handle those fine on their own.
Node.js
Uses it for: APIs and backend services across most projects.
Typical context: KoboFlow, Mazi, Relayroom.
Why he likes it: Same language on both ends reduces context-switching for a solo builder.
When he avoids it: For CPU-heavy processing — that gets handed to something better suited.
Fastify
Uses it for: Lightweight APIs where Express felt heavier than necessary.
Typical context: Relayroom's backend.
Why he likes it: Fast defaults, low ceremony to get an endpoint running.
When he avoids it: When a project already has deep Express-specific middleware needs.
Express
Uses it for: The safe, well-understood default for most Node APIs.
Typical context: Threadline and several client projects.
Why he likes it: Predictable, well-documented, easy for someone else to pick up later.
When he avoids it: Rarely — mostly a style preference between this and Fastify.
GraphQL
Uses it for: When a mobile client needed precise control over payload shape.
Typical context: Fieldnote's sync layer.
Why he likes it: Solved real over-fetching problems on slow field connections.
When he avoids it: For a simple CRUD API — REST is usually less overhead.
PostgreSQL
Uses it for: The default relational database for anything with real structure.
Typical context: KoboFlow, Mazi, Threadline.
Why he likes it: Handles the edge cases you don't think about until you need them.
When he avoids it: For a tiny local-only tool — SQLite is lighter.
SQLite
Uses it for: Small, self-hosted tools with one clear owner.
Typical context: Relayroom, Fieldnote's local store.
Why he likes it: Zero setup, a single file you can just look at.
When he avoids it: Once concurrent writes from many users become common.
Redis
Uses it for: Caching and lightweight job queues.
Typical context: KoboFlow's notification queue.
Why he likes it: Simple mental model, fast enough not to think about.
When he avoids it: As a primary datastore — it's a cache, not a database, in most of my projects.
Figma
Uses it for: Interface exploration before any code gets written.
Typical context: Every project, early stage.
Why he likes it: Fast enough to explore several directions before committing to one.
When he avoids it: For final visual polish — that mostly happens in the browser now.
Excalidraw
Uses it for: System diagrams and quick architecture sketches.
Typical context: Early planning for every project on this site.
Why he likes it: The hand-drawn look keeps early sketches from looking more final than they are.
When he avoids it: For anything meant to be a polished, shareable diagram.
Git
Uses it for: Version control, obviously, but also as a thinking tool — small commits as a record of decisions.
Typical context: Every project.
Why he likes it: A clean commit history is its own kind of documentation.
When he avoids it: Never — but squash-happy workflows lose the history I actually value.
Vite
Uses it for: Local dev server and bundler for anything that needs a build step.
Typical context: KoboFlow, Mazi.
Why he likes it: Fast enough that the feedback loop stops being a tax.
When he avoids it: For projects with no build step needed at all.
Docker
Uses it for: Consistent local environments and simple deployment.
Typical context: KoboFlow, Relayroom deployments.
Why he likes it: Removes the 'works on my machine' class of problem entirely.
When he avoids it: For a static site with nothing to containerize.