Back to all projects

LEARNINGS

Honest retrospectives from building 102 side projects. What went well, what didn't, and what was outright painful.

24 retrospectives so far

102 Projects Hub
Next.jsTypeScriptTailwind CSSNextAuth

The Good

Server Components + Server Actions eliminated API boilerplate. Brutalist design was fast to implement. The globalThis pattern for dev-mode data persistence was a clever workaround.

The Bad

Route groups took several tries to structure correctly - had a frustrating redirect loop. NextAuth v5 docs are sparse.

The Ugly

Images for the projects are loaded from the db and only memcached, will need an s3 worthy upgrade soon.

Learning Platform Bundle
Next.jsTypeScriptPostgreSQLClaude AI

The Good

Single codebase serves Rust, TypeScript, JavaScript, PHP, SQL, and Zig courses across 6 domains. Monaco Editor with per-language syntax highlighting and WASM-based execution means code actually runs in the browser. Claude integration for hints was the feature that made it click for learners.

The Bad

Each language needs its own runtime for code execution. Rust compiles via WASM, PHP needs a serverless function, SQL runs in sql.js. Maintaining 6 different execution backends from one app is a constant juggle.

The Ugly

Lesson content is MDX files committed to the repo. Adding a new lesson means a PR, build, and deploy. Should have built a CMS from the start. Also, the playground output panel disappears on mobile — turns out 375px isn't enough for a code editor and output side by side.

NepaliGo
Next.jsReactTypeScriptTailwind CSS

The Good

Fabric.js handled canvas manipulation beautifully. The wizard-based generation flow feels intuitive. Color palette generator with multiple schemes adds real value.

The Bad

Fabric.js v6 docs are sparse - had to dig through source code. Export with masks required canvas-level clipping workarounds.

The Ugly

The smart generate feature with icon search is mocked - no actual icon API integration yet. Layer z-index reordering is fragile.

Cacao Juice Brand Package
Next.jsTypeScriptTailwind CSSMDX

The Good

One Next.js app serves 29 domains through middleware hostname detection. Each domain gets its own Umami tracking, theme preset, and localized content. The MDX wiki and recipe system makes content updates dead simple. SEO is strong — unique meta tags, sitemaps, and structured data per domain.

The Bad

29 domains means 29 SSL certs, 29 DNS configs, and 29 things that can break independently. Domain management tooling helped but the initial setup was a multi-day DNS debugging marathon.

The Ugly

The contact form reCAPTCHA integration is brittle across domains. Some ccTLDs have stricter cookie policies that break the CAPTCHA flow. We ended up switching to ALTCHA but the migration wasn't clean.

ClaudeBox
Next.jsTypeScriptReactTailwind CSS

The Good

The mobile-first constraint forced good design decisions. Touch-friendly code editing is possible if you rethink the interaction model instead of shrinking a desktop IDE.

The Bad

Code editing on mobile is still fundamentally awkward. Autocomplete, bracket matching, and indentation all fight the mobile keyboard. Every phone handles virtual keyboards differently.

The Ugly

Currently more of a fancy REPL than an actual IDE. File management, project structure, and multi-file editing are all TODO. The sandbox execution is mocked.

Claude Skill Manager
Next.jsTypeScriptReact

The Good

E2E encryption means we never see the skill content. The sync model is simple: push from one machine, pull from another. Skills are just markdown files so the data model is trivial.

The Bad

Key management UX is always painful. Users need to understand that losing their encryption key means losing their skills. We can't recover them by design.

The Ugly

The Claude Code skill format isn't officially documented anywhere. We're reverse-engineering the frontmatter spec from existing skills and hoping Anthropic doesn't change it.

Axinite
Next.jsTypeScriptPGliteCodeMirror 6

The Good

PGlite running Postgres entirely in the browser is wild. Full SQL queries on local data with zero server dependency. CodeMirror 6 is a massive upgrade from v5 — the extension system actually makes sense now.

The Bad

Syncing local-first data across devices is the unsolved hard problem. PGlite doesn't have built-in replication, so we're essentially building our own sync layer. That's a project within the project.

The Ugly

The knowledge graph visualization is more of a prototype than a feature. It renders nodes but the interaction model isn't there yet. Dragging nodes around works, clicking through to notes doesn't.

TenantShield
Next.jsTypeScriptTailwind CSSClaude AI

The Good

Jurisdiction-aware responses are the differentiator — asking about your lease in Amsterdam gives different answers than asking in Berlin. Claude handles the nuance well when prompted with the right legal context.

The Bad

Legal accuracy is everything and we can't guarantee it. Every response needs disclaimers, which undermines the confident UX we want. Walking the line between helpful and liable is harder than the code.

The Ugly

We started with US tenant law and quickly realized European housing law is a completely different beast. The jurisdiction detection based on user location is hacky at best.

The Good

React 19 hooks made RSVP timing clean. ORP focal letter calculation was straightforward. Vite gave instant HMR feedback.

The Bad

Only demo text - no file upload or paste. Could use better mobile responsiveness.

The Ugly

No persistence - refresh loses position. Delay multipliers are simplistic, ignoring word complexity.

OmniRun
RustTypeScriptFirecrackerDocker

The Good

Firecracker boots a microVM in under 150ms. The E2B-compatible API means existing tooling just works. Having a CLI and SDK as separate packages from day one keeps things clean.

The Bad

Firecracker requires KVM, which means bare metal or nested virt. That rules out most cloud providers for development. Testing locally on macOS requires a Linux VM to run the Linux VM. It's VMs all the way down.

The Ugly

Networking between the host and the microVM was a multi-day rabbit hole involving tap devices, iptables, and bridge interfaces. The docs assume you already know Linux networking at a kernel level.

DataGigant
PythonTypeScriptAirflowPostgreSQL

The Good

Airflow orchestrates all the data pipelines. Each scraper (LinkedIn, finance, webtech) is its own microservice with its own API, which keeps failures isolated. The monorepo structure means shared types and configs without the npm package publishing dance.

The Bad

LinkedIn actively fights scrapers. Rate limits, CAPTCHAs, and session invalidation mean the LinkedIn pipeline needs constant babysitting. What works today breaks tomorrow.

The Ugly

The VPN rotation setup is held together with shell scripts and prayer. IP rotation works 80% of the time. The other 20% you're debugging iptables rules at midnight wondering why traffic is routing through the wrong exit node.

ChipTS
RustCraneliftTypeScript

The Good

Cranelift generates machine code fast — way faster than LLVM for our use case. Parsing TypeScript's grammar in Rust forces you to really understand every edge case in the language spec.

The Bad

TypeScript's type system is Turing-complete. Implementing even basic generics correctly is a months-long effort. We're focusing on a useful subset first.

The Ugly

The compiler currently handles maybe 40% of real-world TypeScript. Decorators, complex mapped types, and conditional types are all missing. It compiles hello world blazingly fast though.

Sigil Logo Maker
Next.jsTypeScriptTailwind CSSFabric.js

The Good

Fabric.js handled all the heavy canvas lifting. Smart Generate with Iconify gives access to 100k+ icons through natural language, which turned out to be the killer feature nobody expected. Building the wizard flow with color palette generation was the most fun part.

The Bad

Fabric.js v7 has spotty docs. Gradient backgrounds needed a workaround with invisible rect objects because Fabric doesn't support CSS gradients on the canvas background natively. Took a few tries to get that right.

The Ugly

Mobile experience is rough — a 400px canvas on a 375px screen does exactly what you'd expect. It was designed desktop-first and it shows. Also, no save/load project files yet, so closing the tab means starting over.

ScalarOps
Next.jsTypeScriptTailwind CSSFramer Motion

The Good

Framer Motion animations make the site feel alive without being obnoxious. next-intl handles all three languages cleanly. The audit funnel is the entire business model — one CTA, no confusion.

The Bad

Three languages means triple the content to maintain. Every copy change is a three-file edit. Should have built a CMS integration from the start instead of hardcoded translation files.

The Ugly

Some content sections render as empty white space in production due to a rendering issue with server components. Content exists in the DOM but doesn't paint. Embarrassing for a company selling AI competence.

Bun API Template
BunTypeScriptHonoPostgreSQL

The Good

Bun's native SQL driver is measurably faster than pg. Hono's API is clean and the middleware system makes sense. Auto-migrations on startup save so much time in early development.

The Bad

Bun's ecosystem is still catching up. Some npm packages don't work, and when they break, the error messages point nowhere useful. Had to vendor a few fixes.

The Ugly

It grew organically from real projects, so some patterns are opinionated to the point of being weird. The auth middleware assumes a specific JWT structure that not everyone uses.

Next.js Starter
Next.jsTypeScriptBunTailwind CSS

The Good

Every 102 Projects web app starts from this template. Biome + Lefthook + Bun gives a fast, consistent dev experience. The conventions page saves hours of setup debates.

The Bad

Templates rot fast. Next.js releases a new major version every few months and each one breaks something. Keeping the template current is a maintenance tax.

The Ugly

The auto-migration setup assumes Drizzle + Postgres. If you want SQLite or MongoDB, you're ripping out plumbing on day one. Should have made the database layer pluggable.

OmniRun CLI
TypeScriptBun

The Good

Clean CLI design: create, start, stop, exec. Feels like a lightweight Docker CLI but for microVMs. Bun makes the startup time instant.

The Bad

Depends on the OmniRun server running locally or remotely. Without the server, the CLI is just a fancy HTTP client that errors out.

The Ugly

Error messages from Firecracker are cryptic kernel-level messages. The CLI tries to translate them but sometimes just passes through raw error strings that mean nothing to most users.

OmniRun SDK
TypeScriptBun

The Good

E2B API compatibility means developers can switch from E2B to OmniRun by changing one import. The SDK handles connection pooling and automatic reconnection.

The Bad

Matching E2B's API surface exactly while running on different infrastructure creates weird abstraction leaks. Some E2B features don't map cleanly to Firecracker.

The Ugly

Test coverage is thin. The SDK works for our use cases but edge cases in concurrent sandbox creation haven't been stress-tested.

Story Creator
TypeScriptReact

The Good

Kids actually used it during testing and wanted to keep playing. Branching narratives are simple enough for a 6-year-old to understand.

The Bad

Generating age-appropriate illustrations at scale is the bottleneck. Stock images don't cut it and AI image generation needs heavy filtering for kid-safe content.

The Ugly

The story engine is basically a big switch statement. It works for 10 stories but won't scale to hundreds without a proper content management system behind it.

LM Studio Proxy
TypeScriptDocker

The Good

Turns a local LM Studio instance into a proper API service. Rate limiting prevents abuse when sharing with a team. Request logging helps debug prompt issues.

The Bad

LM Studio updates sometimes change the internal API format. The proxy breaks silently. Requests go through but responses are malformed.

The Ugly

Auth is basic API keys stored in a JSON file. No rotation, no expiry, no per-key rate limits. Fine for a small team, embarrassing for anything else.

GitLab Status Bot
TypeScriptDockerGitLab API

The Good

Pipeline failures surface immediately in the team chat instead of sitting in GitLab unnoticed. The webhook-based approach means near-instant notifications.

The Bad

GitLab's webhook payload format is inconsistent across event types. Every new event type we handle needs its own parser.

The Ugly

The bot was built for one specific GitLab instance's workflow. Self-hosted GitLab versions have slightly different API responses. It works on ours, your mileage may vary.

Closet Designer
TypeScriptReactCanvas

The Good

Parametric design means changing one dimension recalculates everything. The cut list export saves hours of manual measurement for actual woodworking projects.

The Bad

3D preview was planned but 2D ended up being sufficient for most use cases. The pivot saved time but the UI feels flat compared to IKEA's planner.

The Ugly

Material thickness calculations have rounding errors that compound across nested shelves. Off by 2mm on a single shelf, off by a centimeter on ten. Needs proper fixed-point math.

Betaald Bereik
Next.jsTypeScriptTailwind CSSPostgreSQL

The Good

Scraped and analyzed nearly 10k political ads with automated image classification. The municipality map view and sponsor analysis give journalists something they can actually use. Search across parties, advertisers, and municipalities works fast even on the full dataset.

The Bad

Meta's ad library API is rate-limited and inconsistent. Some ads disappear between observation rounds with no explanation, which makes the 'new since last round' metric unreliable for deleted ads.

The Ugly

The image classification model flags about 15% false positives as campaign material. A photo of a politician at a birthday party isn't a campaign ad, but the model doesn't know that. Manual review is still needed for borderline cases.

mlxstudio
SwiftMLXApple SiliconmacOS

The Good

The multi-node setup actually works over WiFi. Two Macs split model layers automatically — Mac Mini handles 0-39, MacBook Pro takes 40-79. Getting 42.8 tok/s on a 70B model from consumer hardware felt like a breakthrough. The app is 10 MB, not 200.

The Bad

WiFi latency between nodes adds up. Layer-to-layer handoff over the network is the bottleneck, not the compute. Ethernet doubles throughput but nobody has their Macs wired together.

The Ugly

Model compatibility is a moving target. Every new MLX release changes the quantization format slightly. We've had to re-download and re-convert models three times since launch.