Skip to content

factory-stack

Synced from factory-kit/skills/factory-stack.md at v0.1.2. The source of truth is the factory-kit repo.

Locked decisions (no per-project relitigation)

Section titled “Locked decisions (no per-project relitigation)”
LayerChoiceWhy
RuntimeNext.js App RouterConvergent across all customer repos; ecosystem fit for tRPC / server actions / Vercel deploy
LanguageTypeScriptConvergent; non-negotiable
ValidationZodPairs with both tRPC and server actions; field registry pattern depends on it
Server stateTanStack QueryConvergent across all repos that need server state
DBPostgres via Neon (dev branches) or RDS (compliance)Convergent
Formsreact-hook-form + Zod via resolverConvergent
EmailResendConvergent
LintingESLint + Prettier + ESLint Drizzle rules where applicableConvergent
Env varst3-oss/env-nextjs (Zod-validated, server/client split)Convergent

Decision-criteria choices (pick per project; document in project’s CLAUDE.md or DECISIONS.md)

Section titled “Decision-criteria choices (pick per project; document in project’s CLAUDE.md or DECISIONS.md)”

ORM — Drizzle vs Supabase auto-types vs raw pg

Section titled “ORM — Drizzle vs Supabase auto-types vs raw pg”
  • Drizzle — default. Schema partitioning by domain (_shared.ts, <domain>.ts) + shared timestamps helper. pgTableCreator() for prefixing if the DB is shared.
  • Supabase auto-generated types — when Supabase Auth + RLS is already doing real work. RLS policies are the contract; auto-types are a free byproduct.
  • Raw pg — never for new projects. Migrate if encountered.

Auth — Better Auth + orgs vs Supabase Auth + RLS vs Clerk

Section titled “Auth — Better Auth + orgs vs Supabase Auth + RLS vs Clerk”
  • Better Auth + organization plugin — default. Org + RBAC + 2FA out of the box; pairs with Drizzle.
  • Supabase Auth + RLS — when RLS pays for itself (multi-role partner/distributor model, deeply branched authz at row level).
  • Clerk — consumer/SSO-heavy, or when managed auth UI components matter.

The wrapper interface is the same regardless: requireAuth(), requireRole(), withOrgContext(). See factory-auth.md (Phase B) for the canonical wrapper shape.

  • Server actions — default for feature-folder-colocated apps with one frontend consumer. Pairs with TanStack Query (useMutation wrapping the action).
  • tRPC — when typed RPC contracts add leverage: ≥3 entities with cross-feature queries, multiple consumers, or a public API surface.
  • Pitfall: don’t import both. Pick a side per project.
  • Mantine — CRUD-heavy / form-table dense / internal-tool surfaces. Built-in date pickers, multiselects, notifications save weeks. Pair with mantine-form-zod-resolver.
  • shadcn — design flexibility / marketing-adjacent / unified Tailwind styling with a landing site. Pair with react-hook-form + zodResolver.
  • Same project, one choice. Mixing leads to design drift.
  • Web (Next.js): Vercel. PR previews via Neon dev branches in GitHub Actions.
  • Python services: Cloud Run. CLI / Cloud Run API / Pub/Sub handler — see factory-data-pipelines.md.
  • Infra-as-code: Terraform with environments/modules layout when AWS/RDS or HIPAA/FDA compliance is in play; skip when Vercel + Neon is sufficient.
  • PostHog + Sentry from day one. Non-negotiable. Easiest to start early, most expensive to backfill.
  • Tag events by tool/feature so per-tool usage is queryable later.
  • See factory-observability.md (Phase B) for activity logging and trace ID patterns.
  1. At project kickoff, read this file end-to-end.
  2. For decision-criteria choices, make the pick explicitly in the project’s CLAUDE.md or a one-page DECISIONS.md (one line per decision).
  3. Refer back when the project considers changing course — the criteria are the basis for that conversation.

See factory-pitfalls.md for the anti-patterns digest indexed across all factory-*.md skills.