sheetforge

In Progress
Solo Builder·Side Project·2026

Google Sheets as a real backend. Serialized writes, idempotent retries, typed TypeScript SDKs generated live from your sheet's headers.

50 ordered

Parallel Writes

0

Row Drops

MIT

OSS Packages

60s

Self-host

Highlights

  • Per-sheet write queue with Postgres advisory-lock fencing turns Google Sheets into a serializable backend. 50 parallel POSTs land as 50 ordered rows, every time.
  • Idempotency via partial unique index on (sheet_id, idempotency_key). Network flakes never double-write.
  • Typed TypeScript SDK generated live from the sheet's header row. Literal unions inferred from sample cells. Compiler catches drift when you rename a column.
  • Upstash REST adapter written alongside the ioredis one so the same code runs on Cloudflare Workers later. Core packages ship MIT, npm-publishable.

The Problem

Google Sheets is the default backend for indie MVPs. Fast to iterate, free to host, shareable by link. Except the Sheets API has a documented concurrency bug: two parallel values.append calls can resolve to the same target row and one silently overwrites the other. Four POSTs, three rows. Every 'Sheets as a backend' wrapper on the market (SheetDB, Sheety, NoCodeAPI) forwards your request straight to the broken primitive and inherits the bug. Fine for a demo. Not fine when your signup form catches an HN spike.

What I Built

A per-sheet write queue with Postgres-advisory-lock fencing. Every write goes through submitWrite, which inserts a ledger row (partial unique index on sheet plus idempotency key so retries dedupe) and pushes to the sheet's Redis stream. The processor takes a Postgres advisory lock keyed by the stream, runs the handler inside a transaction, and acks Redis only after commit. Crash mid-handler, the transaction rolls back, Redis redelivers the message, the idempotency key catches the replay. No token protocol. No lease clock skew. The second half of the product generates a typed TypeScript SDK from the sheet's header row: literal unions inferred from sample cells, compile-time drift detection when you rename a column. On top sits a Next.js 15 dashboard with Google OAuth, an Upstash REST adapter so the same code runs on Cloudflare Workers later, and a public 'slam 50 parallel writes' demo on the landing page that paints a 50-tile grid as writes land. Core packages (queue, codegen, sdk-ts) ship under MIT once the V0 concurrency acceptance demo passes.

Tech Stack

  • TypeScript
  • Next.js
  • Hono
  • PostgreSQL
  • Drizzle ORM
  • Redis Streams
  • Upstash
  • Zod
  • Turborepo
  • Biome
  • Google Sheets API

Interested in working together?