# Eden Stack - Complete Documentation > The full-stack SaaS starter kit with 60+ primitives, 40+ Claude skills, and zero lock-in. Full source code with proven patterns so AI writes production-quality code that actually fits your project. --- ## Overview Eden Stack is a production-ready full-stack monorepo template that provides: 1. **Type-Safe Full Stack**: End-to-end TypeScript with Eden Treaty 2. **Multi-Platform**: Web (TanStack Start), Mobile (Expo), API (Elysia) 3. **AI-Native**: Built-in AI agents with Inngest AgentKit 4. **Production Ready**: Auth, payments, email, jobs, analytics pre-configured --- ## Documentation ## Blog Posts ### Add a Feature in 10 Minutes *Published: 2025-01-25* See how Eden Stack's layered architecture lets you ship complete features fast—from database to UI # Add a Feature in 10 Minutes Eden Stack's architecture makes adding features predictable. Every feature follows the same pattern across four layers. Once you understand the pattern, you can ship complete functionality in minutes. ## The Four-Layer Pattern Every feature in Eden Stack touches these layers: ``` ┌─────────────────────────────────────────────────┐ │ 1. SCHEMA → Define the data structure │ │ 2. API → Expose CRUD operations │ │ 3. HOOKS → Connect React to API │ │ 4. UI → Render and handle interactions │ └─────────────────────────────────────────────────┘ ``` Let's see this in action with a **bookmarks** feature. ## Layer 1: Schema (Drizzle) Define what a bookmark looks like: ```typescript // src/lib/db/schema.ts export const bookmarks = pgTable("bookmarks", { id: text("id").primaryKey().$defaultFn(() => crypto.randomUUID()), userId: text("user_id").notNull().references(() => users.id), conversationId: text("conversation_id").notNull(), createdAt: timestamp("created_at").defaultNow(), }); ``` Run `bun run db:push`. Schema done. ## Layer 2: API (Elysia) Expose the operations: ```typescript // src/server/routes/bookmarks.ts export const bookmarksRoutes = new Elysia({ prefix: "/bookmarks" }) .get("/", /* list bookmarks */) .post("/", /* add bookmark */) .delete("/:id", /* remove bookmark */); ``` Each endpoint: authenticate → query/mutate → return. Eden Treaty auto-generates the typed client. ## Layer 3: Hooks (TanStack Query) Connect React to your API: ```typescript // src/hooks/use-bookmarks.ts export const useBookmarks = () => useQuery({ queryKey: ["bookmarks"], queryFn: /* ... */ }); export const useAddBookmark = () => useMutation({ mutationFn: /* ... */ }); export const useRemoveBookmark = () => useMutation({ mutationFn: /* ... */ }); ``` Queries cache automatically. Mutations invalidate related queries. ## Layer 4: UI (React) Use the hooks in components: ```tsx function BookmarkButton({ id }: { id: string }) { const { data } = useIsBookmarked(id); const add = useAddBookmark(); const remove = useRemoveBookmark(); return ( ); } ``` That's it. Four layers, one feature. ## The Files You Touch | Layer | Location | What You Add | |-------|----------|--------------| | Schema | `src/lib/db/schema.ts` | Table definition | | API | `src/server/routes/` | New route file | | Hooks | `src/hooks/` | Query/mutation hooks | | UI | `src/components/` | React components | ## Or Just Ask Claude Instead of writing this yourself: ``` Add a bookmarks feature. Users should be able to bookmark conversations and see them in a sidebar. Include database schema, API endpoints, and React components. ``` Claude knows the patterns. It'll generate all four layers, following the conventions already in your codebase. **The architecture is the documentation.** Consistent patterns mean AI assistants (and new team members) can contribute immediately. --- Ready to build? Check out the [Getting Started guide](/docs/getting-started) or see [10 SaaS ideas](/blog/saas-use-cases-eden-stack) you can build with this pattern. --- ### AI-Driven Promotional Videos with Claude Skills *Published: 2024-01-25* Generate professional marketing videos programmatically using Remotion, ElevenLabs, and Claude skills # AI-Driven Promotional Videos with Claude Skills Marketing video production traditionally requires expensive software, professional voiceover artists, and hours of editing. With Eden Stack, you can generate polished promotional videos using code—and let AI handle the heavy lifting. ## The Traditional Video Production Problem Creating a 60-second promo video typically involves: 1. Writing the script (~2 hours) 2. Recording or hiring voiceover talent (~$100-500 + coordination time) 3. Learning video editing software (~10+ hours) 4. Manually syncing audio to visuals (~4 hours) 5. Exporting for different platforms (~1 hour per format) 6. Re-doing everything when branding changes **Total: 8-20+ hours and $100-500 per video.** ## The Eden Stack Approach You don't write JSON or code. You have a conversation: ``` You: "I need a 60-second promo video for my SaaS. Hook about saving time, show the pain of manual setup, then the solution, end with a clear CTA." Claude: "I'll create a 6-scene structure for you..." [Updates scenes in generate-voiceovers.ts] [Generates voiceovers via ElevenLabs] [Builds React scene components] [Renders to all formats] You: "The hook feels too slow, make it punchier" Claude: [Updates the hook text and regenerates voiceover] ``` **Total: ~30 minutes of conversation. Free tier covers ~25 videos/month.** ## How It Works You describe what you want. Claude—equipped with Eden Stack's video skills—handles everything: writing the script, generating voiceovers, building scenes, and rendering. ```mermaid flowchart LR subgraph You["You"] Idea["Describe your video"] end subgraph Claude["Claude + Skills"] Script["Write script"] Voice["Generate voice"] Scenes["Build scenes"] end subgraph Output["Output"] MP4_16x9["16:9
YouTube"] MP4_9x16["9:16
TikTok/Reels"] MP4_1x1["1:1
Instagram"] end Idea --> Script Script --> Voice Voice --> Scenes Scenes --> MP4_16x9 Scenes --> MP4_9x16 Scenes --> MP4_1x1 ``` ## Claude Skills: Encoded Expertise Claude skills are markdown files that inject domain expertise into AI assistants. Eden Stack includes three skills for video production: ### 1. `remotion-best-practices` Best practices for programmatic video creation: - Scene composition with `TransitionSeries` - Audio synchronization patterns - Animation utilities (`spring`, `interpolate`) - Multi-format export configuration - Performance optimization ### 2. `elevenlabs-remotion` Professional voiceover generation: - Voice selection with preset names (Alexandra, Archer, Mark, etc.) - Voice settings for natural delivery (stability, similarity, style, speed) - Scene-by-scene generation - Timing validation with `ffprobe` ### 3. `promo-video-workflow` End-to-end video production workflow: - Script writing templates - Project structure - Scene patterns (hook, problem, solution, CTA) - Audio synchronization - Brand theming ## Quick Start ### 1. Define Your Scenes Scenes are defined in the voiceover generation script: ```typescript // apps/video/scripts/generate-voiceovers.ts const scenes = [ { id: "scene-1-hook", text: "Ship your startup this weekend.", }, { id: "scene-2-problem", text: "Setting up authentication. Configuring payments. A hundred hours before you write your first feature.", }, { id: "scene-3-solution", text: "With Eden Stack, everything is pre-configured. Just describe what you want to build.", }, { id: "scene-4-cta", text: "Get started in five minutes. Visit get eden dot dev.", }, ]; ``` ### 2. Generate Voiceovers Eden Stack includes a video app (`apps/video`) with voiceover generation built-in: ```bash # From apps/video directory cd apps/video # Generate with default voice (Alexandra) bun run generate:voice # Use a different voice bun run generate:voice -- --voice archer # Adjust voice settings bun run generate:voice -- --voice alexandra --stability 0.5 --similarity 0.9 # List available voices bun run generate:voice:list ``` This generates MP3 files in `apps/video/public/voiceovers/` for each scene. ### 3. Build Scene Components ```tsx // src/scenes/HookScene.tsx import { AbsoluteFill, Img, staticFile } from "remotion"; import { useCurrentFrame, useVideoConfig } from "remotion"; import { spring, interpolate } from "remotion"; export const HookScene: React.FC = () => { const frame = useCurrentFrame(); const { fps } = useVideoConfig(); const logoScale = spring({ frame, fps, config: { damping: 20, stiffness: 200 }, }); const textOpacity = interpolate(frame, [15, 30], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp", }); return (

Ship your startup this weekend.

); }; ``` ### 4. Assemble the Video ```tsx // src/compositions/PromoVideo.tsx import { TransitionSeries, linearTiming } from "@remotion/transitions"; import { fade } from "@remotion/transitions/fade"; import { Audio, Sequence, staticFile } from "remotion"; const SCENES = { hook: { duration: 150, component: HookScene }, // 5s @ 30fps problem: { duration: 240, component: ProblemScene }, solution: { duration: 240, component: SolutionScene }, cta: { duration: 180, component: CTAScene }, }; export const PromoVideo: React.FC = () => { return ( {/* Background music */} ); }; ``` ### 5. Render All Formats ```bash # Render for YouTube (16:9) bun run render:16x9 # Render for TikTok/Reels (9:16) bun run render:9x16 # Render for Instagram (1:1) bun run render:1x1 # Or all at once bun run render:all ``` ## Voice Presets The generation script includes curated voice presets optimized for promo content: | Voice | Style | Best For | |-------|-------|----------| | **alexandra** (default) | Super realistic young female | Most natural-sounding | | archer | Grounded British male | Charming, conversational | | mark | Relaxed, laid-back male | Casual tone | | adam | Deep professional male | Classic narrator | | hope | Bright, uplifting female | Positive energy | | eryn | Friendly, relatable female | Conversational | ### Voice Settings Fine-tune how the voice sounds: | Setting | Range | Effect | |---------|-------|--------| | `--stability` | 0-1 | Lower = more dynamic/emotional (default: 0.4) | | `--similarity` | 0-1 | Higher = clearer, closer to original voice (default: 0.8) | | `--style` | 0-1 | Higher = more expressive (default: 0.0) | | `--speed` | 0.25-4.0 | Speech rate (default: 1.1) | ```bash # Energetic, dynamic delivery bun run generate:voice -- --voice alexandra --stability 0.3 --speed 1.2 # Calm, consistent narration bun run generate:voice -- --voice adam --stability 0.7 --speed 1.0 ``` **Tip**: For natural-sounding promo videos, use lower stability (0.3-0.4) to avoid the AI-monotone effect. ## Why Claude Skills Matter Without skills, you'd need to: 1. Read Remotion docs to understand composition patterns 2. Read ElevenLabs docs to understand voice settings 3. Figure out how to sync audio to video frames 4. Learn the project structure conventions 5. Discover the CLI commands through trial and error With skills, the AI assistant already knows: - Optimal voice settings for different content types - Frame-accurate audio synchronization patterns - Scene transition best practices - Multi-format export configuration - The exact CLI commands and flags **Skills are institutional knowledge encoded as AI instructions.** ## Cost: Free to Start ElevenLabs has a generous free tier: | Plan | Credits/Month | 1-Min Videos | |------|---------------|--------------| | **Free** | 10,000 | **~25 videos** | | Starter ($5) | 30,000 | ~75 videos | | Creator ($22) | 100,000 | ~250 videos | **A 1-minute promo video uses approximately 400 credits.** Let that sink in: you can create **25 professional promo videos per month** on the free tier. That's enough for: - Weekly product updates - A/B testing different hooks - Multi-language versions - Platform-specific cuts | Traditional | Eden Stack | |-------------|------------| | Voiceover artist: $100-500 | ElevenLabs: **Free** (25 videos/mo) | | Video editor: $50-200/hr | Your time: ~30 min conversation | | Re-edits: Same cost again | Re-render: Free | | Multi-format: Extra charge | Included | **Total cost to get started: $0.** ## Next Steps - [Remotion Documentation](https://remotion.dev) — Learn advanced composition patterns - [ElevenLabs Documentation](https://elevenlabs.io/docs) — Explore voice customization - [Claude Skills Guide](/docs/claude-skills) — Create your own skills ## Example: Full Promo Video Check out the Eden Stack promo video—entirely generated with these tools: ```bash # Clone the template bunx gitpick magnusrodseth/eden-stack my-app cd my-app bun install # Navigate to video app cd apps/video # Generate voiceovers (requires ELEVENLABS_API_KEY in .env) bun run generate:voice # Preview in browser at localhost:3003 bun dev # Render all formats (16:9, 9:16, 1:1) bun run render:all ``` The entire video—script, voiceover, visuals, and export—is defined in code and version controlled with your project. --- ### AI-Powered Project Setup *Published: 2024-01-20* Set up your entire project with one prompt using MCP servers # AI-Powered Project Setup Eden Stack is the first template designed for **AI-native development**. Instead of manually creating accounts, copying API keys, and configuring services, you describe what you want and Claude Code sets it up for you. ## The Problem with Traditional Setup Setting up a full-stack app typically requires: 1. Create a database on Neon → Copy connection string 2. Create Stripe account → Set up products → Copy API keys 3. Create Resend account → Verify domain → Copy API key 4. Create PostHog project → Copy API key 5. Create Sentry project → Copy DSN 6. Create Cloudflare R2 bucket → Generate access keys 7. Manually paste all 15+ values into `.env` **Time: 30-60 minutes of clicking and copying.** ## The Eden Stack Way ``` "Set up my Eden Stack project using eden.setup.json" ``` **Time: 5 minutes. One prompt.** ## How It Works Eden Stack uses [Model Context Protocol (MCP)](https://modelcontextprotocol.io) servers that let AI assistants interact directly with external services. ```mermaid flowchart TD subgraph User["👤 You"] Prompt["Set up my project"] end subgraph Claude["🤖 Claude Code"] AI[AI Assistant] end subgraph MCP["MCP Servers"] Neon["🐘 Neon"] Stripe["💳 Stripe"] Resend["📧 Resend"] Cloudflare["☁️ Cloudflare"] PostHog["🦔 PostHog"] Sentry["🔍 Sentry"] Inngest["⚡ Inngest"] end subgraph Output["📄 Generated"] Env[".env file"] end Prompt --> AI AI --> Neon AI --> Stripe AI --> Resend AI --> Cloudflare AI --> PostHog AI --> Sentry AI --> Inngest Neon --> Env Stripe --> Env Resend --> Env Cloudflare --> Env PostHog --> Env Sentry --> Env Inngest --> Env ``` ## Quick Start ### 1. Create Your Config ```bash cp eden.setup.example.json eden.setup.json ``` Edit with your project details: ```json { "project": { "name": "my-saas", "domain": "my-saas.com" }, "services": { "database": { "provider": "neon", "region": "aws-us-east-1" }, "payments": { "provider": "stripe", "products": [ { "name": "Pro", "price": 2900, "interval": "month" } ] }, "email": { "provider": "resend" }, "storage": { "provider": "cloudflare-r2" }, "analytics": { "provider": "posthog" }, "errors": { "provider": "sentry" } } } ``` ### 2. Authenticate Services ```bash # GitHub CLI gh auth login # Neon npx neonctl auth ``` Other services (Stripe, Cloudflare, PostHog, Sentry) authenticate via OAuth popup when first used. ### 3. Run Setup in Claude Code Open Claude Code and say: ``` Set up my Eden Stack project using eden.setup.json ``` Claude will: - Read your configuration - Create resources on each service via MCP - Collect all credentials - Generate your `.env` file ## Available MCP Servers ### MUST HAVE (Core Functionality) | Service | What It Does | |---------|--------------| | **Neon** | Creates database projects, branches, runs migrations | | **Stripe** | Creates products, prices, webhooks, retrieves API keys | | **Resend** | Verifies domains, sends test emails | | **Inngest** | Lists functions, triggers events, monitors jobs | ### SHOULD HAVE (Production-Ready) | Service | What It Does | |---------|--------------| | **Cloudflare** | Creates R2 buckets, generates access tokens | | **PostHog** | Creates projects, sets up feature flags | | **Sentry** | Creates projects, retrieves DSN | | **Expo** | Provides latest docs for mobile development | | **Drizzle** | Manages schema, runs migrations via AI | ## Declarative Configuration The `eden.setup.json` config is validated against a JSON Schema. You define what you want, the AI figures out how to create it. ### Example: Different Pricing Tiers ```json { "services": { "payments": { "products": [ { "name": "Starter", "price": 0, "interval": "month", "features": ["100 requests/month", "Community support"] }, { "name": "Pro", "price": 2900, "interval": "month", "features": ["Unlimited requests", "Priority support"] }, { "name": "Enterprise", "price": 9900, "interval": "month", "features": ["Everything in Pro", "Custom integrations", "SLA"] } ] } } } ``` The Stripe MCP will create all three products with their prices and feature lists. ## Why This Matters 1. **Reproducible** — Same config, same setup every time 2. **Self-Documenting** — Config file shows exactly what services you use 3. **Fast** — 5 minutes vs 60 minutes 4. **Error-Free** — No typos in API keys, no missed steps 5. **Onboarding** — New team members run one command ## Future: Any AI Editor While currently optimized for Claude Code, the MCP servers work with any MCP-compatible client: - Cursor - VS Code with Copilot - Claude Desktop - Any future AI coding tools ## Next Steps - [Getting Started](/docs/getting-started) - Full setup guide - [Background Jobs](/docs/background-jobs) - Using Inngest - [Stripe Payments](/docs/stripe-payments) - Payment integration --- ### Best Full-Stack TypeScript Starter Kit in 2026 *Published: 2026-04-03* Comparing starter kits that deliver true end-to-end type safety from database to UI # Best Full-Stack TypeScript Starter Kit in 2026 Almost every starter kit in 2026 claims to be "built with TypeScript." That bar is on the floor. Using TypeScript and delivering true type safety are fundamentally different things. I want to talk about what separates the good from the great: whether a change to your database schema actually surfaces a type error in your frontend code. Most starters don't deliver this. The ones that do are worth examining closely. ## What "Full-Stack Type Safety" Actually Means Here is the chain that matters: ``` Database Schema → ORM Types → API Response Types → Client Types → UI Components ``` True end-to-end type safety means that if you rename a column in your database schema, TypeScript should catch every place in your frontend that references the old name. No runtime surprises. No "it worked in dev but crashed in production" bugs. Most TypeScript starters break this chain somewhere. The usual failure points: 1. **Database to ORM**: The ORM requires a code generation step, so types go stale between edits. 2. **ORM to API**: The API serializes data manually, losing type information. 3. **API to Client**: The client uses `fetch` with manually typed interfaces that drift from the actual API response. 4. **Client to UI**: Components receive `any` or loosely typed props. A starter kit that calls itself "type-safe" should have zero gaps in this chain. Let me walk through how the major approaches stack up. ## Approach 1: tRPC (The T3 Stack) The T3 Stack (Next.js + tRPC + Prisma + Tailwind) popularized the idea of end-to-end type safety in the TypeScript ecosystem. tRPC's core insight was brilliant: share TypeScript types directly between client and server, with no code generation and no schema files. **Where it excels:** - Change a tRPC procedure's return type and every caller gets a type error immediately. - The client is fully typed with auto-completion. - Zero code generation for the API layer. **Where the chain breaks:** - **Prisma requires `prisma generate`**. Change your `.prisma` schema file, and your TypeScript types don't update until you run the generate command. This is a gap. Developers forget, CI pipelines miss it, and you get stale types that silently pass type-checking while being wrong at runtime. - **tRPC creates an internal API**. It is not accessible to external consumers like mobile apps, third-party webhooks, or any client not written in TypeScript. If you need a public API later, you are rebuilding. - **Locked to the tRPC ecosystem**. Your API is not REST, not GraphQL, not OpenAPI. It is tRPC. That is fine until you need interoperability. By 2026, the T3 Stack's original definition has fractured. React Server Components and Server Actions have eroded tRPC's monopoly on the "no API boundary" pitch, and alternatives like oRPC have emerged to address the interoperability gap. **Verdict**: Strong type safety from API to frontend. Weaker at the database layer because of Prisma's generation step. Not ideal if you ever need external API consumers. ## Approach 2: Next.js Server Actions Server Actions let you call server-side functions directly from client components. No API layer at all. In theory, this is the ultimate type safety story: your function signature _is_ your contract. **Where it excels:** - The simplest mental model. Call a function, get a result. - TypeScript infers the return type automatically. - No separate API to maintain. **Where the chain breaks:** - **TypeScript types are erased at runtime**. Server Actions are transmitted over the network as HTTP POST requests. The `string` parameter your TypeScript function expects? An attacker can send `{ malicious: true }` instead. You _must_ validate every argument with Zod or a similar library, which means you are writing validation schemas manually alongside your TypeScript types. - **No typed error handling**. Errors are generic. There is no type narrowing for different error cases. - **No external access**. Like tRPC, Server Actions are internal-only. No mobile app can call them. No webhook can trigger them. Libraries like [next-safe-action](https://next-safe-action.dev/) paper over these gaps with middleware patterns and Zod integration, but they are admitting the problem exists. The framework does not solve type safety on its own. **Verdict**: Great developer experience for simple cases. Runtime type safety requires manual effort. Not suitable as the sole API strategy for anything beyond a single web app. ## Approach 3: Manual Type Sharing This is what most starter kits actually ship: separate frontend and backend projects with a shared `types/` directory or package. ```typescript // shared/types.ts export interface User { id: string; name: string; email: string; } // backend/routes/users.ts app.get('/users/:id', async (req, res) => { const user = await db.query('SELECT * FROM users WHERE id = $1', [req.params.id]); res.json(user); // Is this actually a User? TypeScript trusts you. }); // frontend/components/Profile.tsx const user: User = await fetch('/api/users/123').then(r => r.json()); // TypeScript says this is a User. Reality may disagree. ``` **Where it breaks**: Everywhere. The shared type is a lie. Nothing enforces that the database query returns a `User`, that the API serializes it correctly, or that the frontend deserializes it properly. You have TypeScript syntax without TypeScript safety. Most of the popular starter kits in 2026 (ShipFast, many Next.js boilerplates) fall into this category. They use TypeScript, but the types are decorative. **Verdict**: Not type-safe. Just type-annotated. ## Approach 4: Eden Treaty (Eden Stack) This is the approach I chose for Eden Stack, and I think it delivers the tightest type safety chain available today. The key insight: every layer uses TypeScript inference, not code generation. Here is how the chain works: ### Layer 1: Drizzle (Database Schema to TypeScript) ```typescript // src/lib/db/schema.ts export const users = pgTable("users", { id: text("id").primaryKey(), email: varchar("email", { length: 255 }).notNull().unique(), name: text("name"), githubUsername: text("github_username"), createdAt: timestamp("created_at").notNull().defaultNow(), updatedAt: timestamp("updated_at").notNull().defaultNow(), }); ``` Drizzle infers TypeScript types directly from your schema definition. There is no `.prisma` file. No generation step. No `prisma generate` to forget. Save the file, and every query that touches this table is immediately type-checked against the new schema. Rename `githubUsername` to `githubHandle`? TypeScript flags every query that still references `githubUsername` the moment you save. ### Layer 2: Elysia (Typed API Routes) ```typescript // src/server/api.ts export const api = new Elysia({ prefix: "/api" }) .get("/me", async ({ request, set }) => { const session = await auth.api.getSession({ headers: request.headers, }); if (!session) { set.status = 401; return { error: "Unauthorized" }; } return { user: session.user }; }) .patch( "/me", async ({ request, body, set }) => { // body is typed from the schema below const [updatedUser] = await db .update(users) .set({ name: body.name, updatedAt: new Date() }) .where(eq(users.id, session.user.id)) .returning(); return { user: updatedUser }; }, { body: t.Object({ name: t.Optional(t.String({ minLength: 1, maxLength: 100 })), image: t.Optional(t.Union([t.String(), t.Null()])), }), } ); // This single line is what makes everything work export type Api = typeof api; ``` Elysia infers the return type of every route handler. The `Api` type export captures the entire shape of your API: every route, every parameter, every response type, every error case. No OpenAPI spec to maintain. No code generation. ### Layer 3: Eden Treaty (Typed Client) Eden Treaty consumes that `Api` type and produces a fully typed client: ```typescript import { treaty } from "@elysiajs/eden"; import type { Api } from "../server/api"; const api = treaty("http://localhost:3000"); // Fully typed: request body, response, and errors const { data, error } = await api.api.me.patch({ name: "Magnus", }); if (data) { console.log(data.user.name); // string | null (matches Drizzle schema) } ``` No code generation. No build step. Change the Drizzle schema, and the Eden Treaty client shows a type error. ### Layer 4: TanStack Start (Typed Routes) ```typescript // src/routes/_authenticated/dashboard.tsx export const Route = createFileRoute("/_authenticated/dashboard")({ loader: async () => { const { data } = await api.api.payments.status.get(); return { purchase: data?.purchase ?? null }; }, component: Dashboard, }); function Dashboard() { const { purchase } = Route.useLoaderData(); // purchase is fully typed, inferred from the Elysia route's return type, // which is inferred from the Drizzle query. } ``` TanStack Start infers loader return types, so your component receives typed data without any manual type annotations. The entire chain is unbroken inference. ### The Full Chain ``` Drizzle schema (TypeScript) ↓ inferred types, no generation Drizzle queries (typed results) ↓ returned from route handler Elysia routes (typed responses) ↓ export type Api = typeof api Eden Treaty client (typed calls) ↓ called in loader TanStack Start route (typed loader data) ↓ useLoaderData() React component (typed props) ``` Every arrow is TypeScript inference. No generation step anywhere. Rename a database column, and you get type errors in your React components within the same second. ## Other Notable Starters ### supastarter supastarter supports both Prisma and Drizzle, so the database layer can be strong. For the API layer, it uses tRPC or Server Actions depending on the framework (Next.js or Nuxt). This gives decent end-to-end type safety, particularly with the tRPC variant. The gap is the same as the T3 Stack: if you pick Prisma, you have a generation step. If you pick Server Actions, you need manual validation. ### MakerKit MakerKit focuses on Next.js with Supabase or Firebase for the backend. The type safety story depends on which database layer you choose. Supabase has its own type generation from your PostgreSQL schema, which works well but requires running `supabase gen types` after schema changes. It is better than no types, but still a generation step. ### oRPC oRPC deserves a mention as a newer alternative to tRPC. It provides the same end-to-end type safety but adds first-class OpenAPI support, meaning your typed API is also a documented REST API. If you need both internal type safety and external API consumers, oRPC is compelling. The trade-off: it is newer and has a smaller ecosystem. ### Hono + Zod OpenAPI Hono is an excellent framework with first-class TypeScript support. Combined with `@hono/zod-openapi`, you get typed routes and auto-generated OpenAPI docs. The type safety from API to client is solid, but it requires defining Zod schemas for every route manually. Drizzle + Elysia infers these from the schema and route handler return types, which is less work. ## The Comparison Table | Approach | DB to ORM | ORM to API | API to Client | Generation Steps | |----------|-----------|------------|---------------|-----------------| | T3 (tRPC + Prisma) | Generation required | Inferred | Inferred | 1 (prisma generate) | | T3 (tRPC + Drizzle) | Inferred | Inferred | Inferred | 0 | | Next.js Server Actions | Varies | N/A (direct) | N/A (direct) | Varies | | Manual type sharing | None | None | None | 0 (but no safety) | | Eden Stack (Elysia + Drizzle + Eden Treaty) | Inferred | Inferred | Inferred | 0 | | supastarter (tRPC + Drizzle) | Inferred | Inferred | Inferred | 0 | | Hono + Zod OpenAPI | Varies | Manual schemas | Generated/Inferred | 0-1 | ## Why This Matters in Practice Here is a concrete scenario. Your product manager asks you to add a `displayName` field to user profiles. In a truly type-safe stack, the workflow looks like this: 1. Add `displayName` to your Drizzle schema. 2. Run `bun run db:generate` to create the migration. 3. Save the file. 4. TypeScript immediately shows errors in every API route, every client call, and every component that needs to handle the new field. You never wonder "did I update the frontend types?" or "is the API returning this field?" The compiler tells you exactly what needs to change. In a stack with generation steps or manual types, step 4 either does not happen or happens after you remember to run a command. That gap is where bugs live. ## My Recommendation If you are choosing a TypeScript starter kit in 2026, here is my honest take: - **If you want the widest ecosystem**: T3 with Drizzle (swap Prisma for Drizzle to eliminate the generation step). - **If you are building a single Next.js app and nothing else**: Server Actions with next-safe-action can work, but validate everything. - **If you want the tightest type safety chain with zero generation steps, REST semantics, and the ability to add mobile clients later**: Eden Stack. The Drizzle to Elysia to Eden Treaty to TanStack Start chain is, as far as I know, the most complete unbroken inference chain available in a production starter kit. I am biased. I built Eden Stack. But I built it specifically because I wanted this property: change the database, see the error in the UI. Every layer earns its place in the stack by maintaining that chain. --- _Choosing a stack is always about tradeoffs. If type safety is not your top priority, simpler options exist. But if you have ever spent hours debugging a type mismatch that TypeScript should have caught, you know why this matters._ --- ### Best SaaS Boilerplate in 2026: A Developer's Honest Guide *Published: 2026-04-03* Comparing the top SaaS starter kits to help you pick the right foundation for your next project # Best SaaS Boilerplate in 2026: A Developer's Honest Guide **Full disclosure: I built Eden Stack. I'll try to be fair, but you should know my bias.** Every SaaS founder faces the same question: do I wire up auth, payments, email, and a database from scratch, or do I buy a boilerplate that has already done it? The answer, for most people, is obvious. The 40-80 hours you spend on plumbing is time you could spend building the thing that makes your product different. The boilerplate market has matured significantly. There are now dozens of options across every major framework, from free scaffolds to premium starter kits. I have spent months researching, building, and competing in this space. This guide covers the ones that actually matter. ## The Comparison Table Before diving into each option, here is the high-level view: | Boilerplate | Framework | Price | Auth | Payments | Background Jobs | Type Safety | AI Features | Best For | |---|---|---|---|---|---|---|---|---| | **Eden Stack** | TanStack Start + Elysia | $199 ($99 early bird) | Better Auth | Stripe | Inngest | End-to-end (Eden Treaty) | 40+ Claude skills, RAG | AI-native, type-safe SaaS | | **ShipFast** | Next.js | $199-$299 | NextAuth/Clerk | Stripe, Lemon Squeezy | No | Partial | Basic | Rapid MVP validation | | **MakerKit** | Next.js 16 | $299+ | Supabase Auth | Stripe, Lemon Squeezy, Paddle | No | Good | Basic | B2B with complex billing | | **SupaStarter** | Next.js / Nuxt | $299-$399 | Better Auth | Stripe, Lemon Squeezy, Polar, Creem, Dodo | Yes | Good | Basic | Multi-framework teams | | **Create T3 App** | Next.js | Free | NextAuth (opt-in) | None | None | Excellent (tRPC) | None | Learning, prototypes | | **Wasp (Open SaaS)** | React + Node.js | Free | Built-in | Stripe, Polar | Yes | Good (RPC) | Agent-ready | Budget-conscious builders | | **SaaSBold** | Next.js | $99+ | Auth.js | Stripe | No | Partial | OpenAI integration | Budget-friendly starter | | **Shipixen** | Next.js | $149-$180 | None | None | None | Standard | None | Content sites, landing pages | ## 1. Eden Stack **Stack:** TanStack Start, Elysia, Eden Treaty, Neon PostgreSQL, Drizzle, Better Auth, Inngest, Stripe, Resend, PostHog, Sentry **Price:** $199 one-time ($99 with early bird discount) **Best for:** Technical founders building production-grade, AI-native SaaS products This is my project, so take this section with a grain of salt. I built Eden Stack because I wanted a boilerplate that treated AI-assisted development as a first-class concern, not an afterthought. **Key strengths:** - **End-to-end type safety.** Eden Treaty gives you type-safe API calls from database to UI without code generation. Change a response shape on the server, and TypeScript catches the mismatch on the client instantly. - **AI-native development.** 40+ Claude skills encode best practices for every integration. When an AI agent works on your codebase, it follows the same patterns you would. - **Production infrastructure.** Background jobs with Inngest, error tracking with Sentry, analytics with PostHog, transactional email with Resend. These are not stubs; they are wired, tested, and documented. - **Deployment flexibility.** TanStack Start runs anywhere: Vercel, AWS, your own server. No vendor lock-in. **Key weaknesses:** - **Smaller community.** ShipFast has 8,000+ users. Eden Stack is newer and has far fewer. - **Steeper learning curve.** TanStack Start + Elysia is a less common stack. If you are coming from Next.js, there is a learning curve. - **No mobile app (yet).** Unlike some competitors, there is no React Native or Expo integration included at the time of writing. **My honest take:** If you are a technical founder who values type safety and wants AI to accelerate your development, Eden Stack is (obviously) my recommendation. If you need the largest possible community and ecosystem, look at the Next.js options below. ## 2. ShipFast **Stack:** Next.js (App Router), Prisma/MongoDB/Supabase, Clerk, Stripe, Tailwind, Resend **Price:** $199 (Starter), $249 (All-in with Discord), $299 (Bundle with course) **Best for:** Solo founders and indie hackers who want the fastest path to a launched product ShipFast, created by Marc Lou, is the most popular SaaS boilerplate in the indie hacker community, and it earned that position. With 8,100+ active users and a thriving Discord of 5,000+ builders, most edge cases and integration questions have already been solved by someone in the community. **Key strengths:** - **Massive community.** The Discord alone is worth the price of admission. You will rarely encounter a problem nobody has solved before. - **Battle-tested.** Thousands of production apps have been built with ShipFast. The rough edges have been sanded down over years. - **Conversion-optimized.** The included landing page templates are genuinely good at converting visitors. Marc knows marketing. - **Course included.** The $299 bundle includes CodeFast, a 12+ hour video course on building with the stack. **Key weaknesses:** - **No background jobs.** If you need cron tasks, webhook processing, or durable workflows, you are on your own. - **Partial type safety.** The stack does not provide end-to-end type inference like tRPC or Eden Treaty. - **Simple architecture.** This is a feature for MVPs but a limitation for complex products. You may outgrow the patterns as your app scales. - **MongoDB default.** While Supabase (PostgreSQL) is supported, the primary path uses MongoDB, which is a polarizing choice for SaaS. **My honest take:** ShipFast is the "default" choice for a reason. If you are a non-technical or early-stage founder who just needs to validate an idea, it is hard to beat. The community support alone gives you a safety net that smaller boilerplates cannot match. ## 3. MakerKit **Stack:** Next.js 16, React 19, Supabase/Drizzle/Prisma, Shadcn UI, Tailwind CSS 4, TypeScript 5 **Price:** $299 (Pro, individual), higher tiers for teams (up to 5 developers) **Best for:** B2B SaaS products with complex billing and multi-tenancy requirements MakerKit stands out for having the most sophisticated billing system of any SaaS boilerplate. It treats billing as a product system with seats, metered usage, complex pricing, and a provider gateway abstraction. If your SaaS needs per-seat pricing, usage-based billing, or the ability to switch payment providers, MakerKit handles this out of the box. **Key strengths:** - **Advanced billing.** Per-seat, metered, flat-rate, one-time, or hybrid pricing. Supports Stripe, Lemon Squeezy, and Paddle through a provider gateway abstraction. - **Admin dashboard.** Monitor users, organizations, subscriptions, and revenue from one dashboard. Impersonate users, ban or delete accounts without touching the database. - **Active maintenance.** Updated daily with new features, bug fixes, and improvements. - **Database flexibility.** Choose between Supabase, Drizzle, or Prisma depending on your preference. **Key weaknesses:** - **Per-developer licensing.** The license is per-developer, not per-project. If you are a team of three, you need the Team license, which costs more. - **Next.js only.** If you want to use a different framework, MakerKit is not an option. - **Higher price point.** At $299+ per developer, it is one of the more expensive options. - **No background jobs.** Like ShipFast, there is no built-in job queue or workflow engine. **My honest take:** If you are building a B2B product where billing complexity is a core concern, MakerKit is probably the best choice. The billing system alone would take weeks to build from scratch. ## 4. SupaStarter **Stack:** Next.js or Nuxt, Better Auth, Stripe/Lemon Squeezy/Polar/Creem/Dodo, Tailwind **Price:** $299-$399 one-time (per framework) **Best for:** Teams that want framework choice and maximum payment provider flexibility SupaStarter is the most framework-flexible paid boilerplate. You can choose between Next.js and Nuxt, and both versions have full feature parity after a ground-up rewrite of the Nuxt version. With five payment providers supported, it also gives you the most flexibility on the payments side. **Key strengths:** - **Framework choice.** Next.js or Nuxt, both fully featured. Useful if your team has strong framework preferences. - **Five payment providers.** Stripe, Lemon Squeezy, Polar, Creem, and Dodo Payments. No other boilerplate matches this breadth. - **Better Auth integration.** Passkeys, WebAuthn, 2FA, magic links, and social login with account linking. - **Internationalization.** Built-in i18n support for multi-language applications. **Key weaknesses:** - **Two separate purchases.** If you want both Next.js and Nuxt, you pay separately for each. - **Smaller community.** Around 600+ developers, compared to ShipFast's 8,000+. - **Higher total cost.** At $299-$399 per framework, the total investment can add up quickly. **My honest take:** If you need Nuxt support or want the widest selection of payment providers, SupaStarter is the clear winner. The dual-framework approach is genuinely unique in this space. ## 5. Create T3 App **Stack:** Next.js, tRPC, Prisma, NextAuth, Tailwind (all optional) **Price:** Free **Best for:** Developers learning full-stack TypeScript, or starting a project where they want full control Create T3 App is not a boilerplate in the traditional sense. It is a scaffolding tool that lets you pick the pieces you want (tRPC, Prisma, NextAuth, Tailwind) and generates a clean starting point. Once it scaffolds your app, it is entirely yours. **Key strengths:** - **Free and open source.** No cost, no license restrictions. - **Excellent type safety.** tRPC provides end-to-end type inference that rivals any paid boilerplate. - **Modular.** You only include what you need. No bloat. - **Large community.** Backed by Theo and a passionate developer community. **Key weaknesses:** - **Scaffold, not a product.** You get a starting point, not a finished foundation. No payments, no email, no landing page, no admin dashboard. - **Significant assembly required.** You will spend days or weeks wiring up the integrations that paid boilerplates include out of the box. - **Next.js only.** Tied to the Next.js ecosystem. - **No ongoing updates.** Once scaffolded, you are responsible for keeping dependencies current. **My honest take:** Create T3 App is excellent for learning and for developers who genuinely enjoy wiring things up themselves. If you value understanding every line of code in your project, start here. But if time-to-market matters, the assembly cost is real. ## 6. Wasp (Open SaaS) **Stack:** React, Node.js, Prisma, Stripe/Polar, Shadcn UI **Price:** Free and open source **Best for:** Developers who want a free, full-featured SaaS starter with a real framework behind it Wasp is the most interesting free option. It is not just a boilerplate; it is a full-stack framework (think "Laravel for JavaScript") with its own compiler. Open SaaS is their free SaaS template built on top of it, and it is surprisingly complete for something that costs nothing. **Key strengths:** - **Completely free.** No payment, no license. Open source with 15,000+ GitHub stars. - **Full-featured.** Auth (email, Google, GitHub, Slack, Microsoft), payments, email, background jobs, file upload, landing page. This covers more ground than some paid options. - **AI-ready.** Ships with a tailored AGENTS.md, Claude skills, and a Claude Code plugin. The Wasp team clearly understands that AI-assisted development is the future. - **Framework benefits.** Because Wasp is a framework (not just a template), it provides automatic type safety, a built-in RPC layer, and deployment tooling. **Key weaknesses:** - **Framework lock-in.** You are adopting the Wasp framework, not just a template. If Wasp development slows down, you cannot easily eject. - **Smaller ecosystem.** Wasp's ecosystem is growing but still small compared to Next.js. - **Learning curve.** Wasp has its own DSL (domain-specific language) on top of React and Node.js. That is another thing to learn. - **Less battle-tested.** Fewer production apps built with Wasp compared to Next.js-based options. **My honest take:** Wasp is the free option I respect the most. The Open SaaS template is genuinely impressive, and the framework approach solves real problems. If your budget is zero and you are comfortable adopting a newer framework, this is where I would start. ## 7. SaaSBold **Stack:** Next.js, Auth.js, Prisma/Drizzle, Stripe, Resend, Tailwind **Price:** Starting at $99 one-time **Best for:** Budget-conscious developers who want a basic but solid foundation SaaSBold hits the sweet spot for developers who want a paid boilerplate but do not want to spend $200+. Starting at $99, it includes auth, payments, a pre-built admin dashboard, and email, which covers the essentials. **Key strengths:** - **Affordable.** The lowest entry price of any paid option on this list. - **Figma source included.** Useful if you want to customize the design before writing code. - **Drizzle and Prisma options.** Choose your preferred ORM. - **OpenAI integration.** Basic AI features included out of the box. **Key weaknesses:** - **Less polished.** The code quality and documentation are not at the level of MakerKit or SupaStarter. - **Limited community.** Less community support compared to the larger players. - **No background jobs.** Same limitation as ShipFast and MakerKit. - **Fewer integrations.** The integration depth is shallower than premium alternatives. **My honest take:** SaaSBold is a solid budget option. If you are price-sensitive and need more than Create T3 App but cannot justify $200+, it gets the job done. ## 8. Shipixen **Stack:** Next.js 14, TypeScript, Tailwind, Shadcn UI, MDX **Price:** $149-$180 one-time **Best for:** Content-driven products, blogs, and marketing sites Shipixen is different from everything else on this list. It is a boilerplate generator focused on content sites and landing pages, not full SaaS applications. It ships with 63+ themes, 300+ usage examples, and 27+ landing page components, but it does not include payment integration. **Key strengths:** - **Content-first.** MDX-powered blogs, SEO optimization, and beautiful landing page components. - **Theme variety.** 63+ themes and extensive component library. - **One-click deployment.** Deploy to Vercel or Netlify instantly. - **Design quality.** The generated output looks polished without much customization. **Key weaknesses:** - **No payments.** You will need to add Stripe or another payment provider yourself. - **No auth.** Authentication is not included. - **Not really SaaS.** If you need a full SaaS foundation, Shipixen is the wrong tool. - **Older Next.js version.** Built on Next.js 14, not the latest. **My honest take:** Shipixen is excellent at what it does, but it is a landing page and blog generator, not a SaaS boilerplate. Include it in your consideration only if content is your primary concern and you plan to add SaaS features separately. ## How to Choose: A Decision Framework The "best" boilerplate depends entirely on your situation. Here is how I would think about it: ### By Budget - **$0:** Wasp (Open SaaS) if you want the most complete free option. Create T3 App if you want maximum control. - **Under $100:** SaaSBold for a basic paid foundation. Eden Stack at the early bird price if you want a premium option at a discount. - **$100-$200:** ShipFast for community and battle-tested patterns. Eden Stack at full price for type safety and AI-native development. - **$200-$400:** MakerKit for B2B billing complexity. SupaStarter for framework flexibility. ### By Technical Skill - **Beginner:** ShipFast. The community will carry you through the rough patches. - **Intermediate:** MakerKit or SupaStarter. Well-documented, production patterns without too much complexity. - **Advanced:** Eden Stack or Create T3 App. You will appreciate the type safety and architectural decisions (or want to make your own). ### By Project Scope - **Weekend project or MVP:** ShipFast or Wasp. Get to market fast, validate the idea. - **Funded startup:** MakerKit, SupaStarter, or Eden Stack. You need a foundation that scales. - **Content site with SaaS elements:** Shipixen for the content side, add payments separately. - **AI-native product:** Eden Stack. The Claude skills and agent-ready architecture are purpose-built for this. ### By Framework Preference - **Next.js:** ShipFast, MakerKit, SupaStarter, SaaSBold, Create T3 App - **Nuxt:** SupaStarter (the only premium option with Nuxt support) - **TanStack Start:** Eden Stack - **Wasp (React + Node.js):** Open SaaS ## The Bottom Line There is no single "best" SaaS boilerplate. There is only the best one for your specific situation. If I were starting a new SaaS today and had no bias, I would narrow the decision down to three questions: 1. **What is my budget?** If zero, Wasp. If non-zero, keep reading. 2. **What is my primary concern?** If speed-to-market, ShipFast. If billing complexity, MakerKit. If type safety and AI, Eden Stack. If framework choice, SupaStarter. 3. **How technical am I?** The more technical you are, the more you will appreciate opinionated architectural decisions. The less technical you are, the more you need community support. I built Eden Stack because I wanted a boilerplate that treated type safety and AI-native development as core features, not nice-to-haves. That is my bias. But every option on this list solves the fundamental problem: getting you past the plumbing and into the work that actually matters. Pick one and start building. The worst decision is no decision. --- ### Best TanStack Start Starter Kit in 2026 *Published: 2026-04-03* A guide to TanStack Start templates and why the ecosystem is ready for production # Best TanStack Start Starter Kit in 2026 TanStack Start hit v1.0 in late 2025, and the ecosystem has been growing fast since. React survey data from early 2026 shows 15% adoption among React developers, with 50% expressing interest among those who have tried it or heard about it. The broader TanStack ecosystem has crossed 4 billion downloads and 112,000 GitHub stars. The framework is production-ready. The question is no longer "should I use TanStack Start?" but "which template gets me shipping fastest?" I've spent months building and maintaining [Eden Stack](https://eden-stack.com), so I have opinions here. But I'll cover the full landscape honestly, starting with the official examples and working through community templates. ## Official TanStack Start Examples The TanStack team maintains a set of example projects inside the [TanStack/router](https://github.com/TanStack/router) repository. These are reference implementations, not production starters. They show you how specific integrations work in isolation. The current examples include: - **start-basic**: Minimal setup with file-based routing and server functions - **start-basic-auth**: DIY authentication patterns - **start-clerk-basic**: Clerk authentication integration - **start-supabase-basic**: Supabase auth and data - **start-basic-react-query**: TanStack Query integration - **start-trellaux**: A Trello-style demo (also available with Convex) - **start-basic-cloudflare**: Cloudflare Workers deployment You can scaffold any of these with the official CLI: ```bash npx @tanstack/cli@latest create ``` Or clone a specific example: ```bash npx gitpick TanStack/router/tree/main/examples/react/start-basic start-basic ``` These are great for learning the framework. They are not great for building a real product. They lack payments, email, background jobs, analytics, error tracking, and the dozens of other integrations a production app needs. That is by design: they exist to teach patterns, not to be scaffolds for SaaS products. ## Community Templates and Starter Kits The TanStack Start template ecosystem has grown significantly. Here is what is out there. ### Free / Open Source **[React Tanstarter](https://github.com/dotnize/react-tanstarter)** is probably the most popular free template. It is a minimal TanStack Start starter with Better Auth, Drizzle ORM (PostgreSQL), shadcn/ui, and React 19 with React Compiler support. Clean, well-maintained, and a solid starting point if you want to add integrations yourself. **[Convex TanStack SaaS Starter](https://www.convex.dev/templates/convex-saas)** is a production-ready template built around the Convex real-time backend. It includes Stripe payments, email and social auth, Resend for email, i18n, file uploads, and a theming system. Good choice if you are already committed to the Convex ecosystem. **[PaceKit](https://github.com/pacekit/tanstack-starter)** positions itself as an enterprise-grade starter kit. It includes Better Auth, a responsive dashboard layout, and decoupled modules for auth, payments, email, database, AI, and documentation. The architecture is clean, with a focus on scalability. ### Paid Starter Kits **[TanPlate](https://www.tanplate.com/)** is a paid boilerplate featuring TanStack Start, Better Auth, Stripe, Polar, Drizzle, and Resend. It also includes AI integrations (OpenAI, Anthropic, Gemini) and audio transcription with Whisper. Priced as a one-time purchase. **[TanStack StartER](https://tanstackstarter.app/)** offers flexibility in tool choices: Clerk, Supabase, or Better Auth for authentication; Stripe, Polar, or Lemon Squeezy for payments; multiple database and email options. It targets multi-cloud deployment across Cloudflare, Vercel, Railway, and self-hosted setups. **[TanStarter](https://tanstarter.dev/)** is optimized for Cloudflare Workers deployment. It includes AI features, auth, database, storage, blog, email, newsletter, payments, and a dashboard. A good pick if Cloudflare is your deployment target. **[Saas UI / Saas.js](https://www.saas-js.com/)** provides a TanStack Start kit with workspace management, multi-tenant support, per-seat and usage-based billing via Stripe, Better Auth, Drizzle + PostgreSQL, and tRPC for the API layer. It is particularly strong on billing flexibility. **[TanStack Starter Kit](https://tanstackstarterkit.com/)** is a multi-tenant SaaS boilerplate with Better Auth, role-based access control, and a private Discord community for support. ## Eden Stack: The Full-Stack Foundation [Eden Stack](https://eden-stack.com) is the template I built, and it takes a different approach from the rest. Most TanStack Start templates focus on the web layer: routing, auth, maybe payments. Eden Stack is a complete application foundation spanning seven domains with 60+ primitives, all designed for agentic development. ### What makes it different **End-to-end type safety without code generation.** TanStack Start handles the routing. Elysia + Eden Treaty handles the API. Together, they give you compile-time type safety from your database schema through your API endpoints to your React components. Change a field in Drizzle, and TypeScript immediately tells you everywhere that needs updating. **Background jobs as a first-class concern.** Most templates punt on this. Eden Stack includes Inngest for durable execution: event-driven workflows, step-level retries, cron jobs, and reliable webhook processing. This is critical for production apps that do anything asynchronous. **AI-native from the ground up.** Eden Stack includes a RAG pipeline with pgvector, streaming chat UI, agent networks, and the infrastructure to build AI features into your product. This is not a bolted-on chatbot. It is a production pattern for AI-powered applications. **Mobile via Expo.** A first-class React Native app that shares auth, types, and API contracts with the web app. Ship to the App Store and Play Store alongside your web product. **40+ Claude skills.** This is the part that really separates Eden Stack from everything else. The codebase ships with Claude skills that encode institutional knowledge about every integration: how Drizzle connects to Neon, how Better Auth mounts in Elysia, how Stripe webhooks flow through Inngest, how to create email templates with React Email. When you (or Claude) build a new feature, these skills ensure it follows the established patterns. ### The full feature set | Domain | What you get | |---|---| | **Web** | TanStack Start, file-based routing, SSR, SEO, OG images | | **API** | Elysia (Bun-native), Eden Treaty, type-safe endpoints | | **Database** | Drizzle ORM, Neon Serverless Postgres, migrations | | **Auth** | Better Auth, GitHub OAuth, session management | | **Payments** | Stripe checkout, subscriptions, webhooks | | **Email** | Resend + React Email templates | | **Jobs** | Inngest durable execution, cron, event-driven workflows | | **AI** | RAG pipeline, pgvector, streaming chat, agent networks | | **Mobile** | Expo (iOS + Android), shared types and auth | | **Analytics** | PostHog event tracking, feature flags | | **Observability** | Sentry error tracking, source maps | | **Video** | Remotion + ElevenLabs AI voiceover | | **Content** | MDX blog with content collections | | **Agentic** | 40+ Claude skills, MCP servers | You can get started in minutes: ```bash bunx gitpick magnusrodseth/eden-stack my-app cd my-app bun install bun dev ``` And if you do not need all of it? [Own your code, control your complexity.](/blog/own-your-code-control-your-complexity) Tell Claude what to remove, and it will clean up the integrations you do not need. The architecture is designed for subtraction as much as addition. ## Why TanStack Start Over Next.js? I wrote a [detailed post on this](/blog/why-tanstack-start-over-nextjs), but the short version: 1. **Deployment flexibility.** TanStack Start runs on Node, Bun, Deno, Cloudflare Workers, AWS Lambda, and anywhere else. No vendor lock-in. 2. **Type-safe routing.** Routes, loaders, search params, path params: everything is inferred and validated by TypeScript at compile time. 3. **Simpler mental model.** Full-document SSR with full hydration. No server/client boundary confusion, no React Server Components complexity. 4. **Performance.** Benchmarks from March 2026 show TanStack Start delivering 5.5x throughput improvements over Next.js, with 13ms average latency at 1,000 requests per second. Next.js is still excellent for content-heavy sites on Vercel. But for SaaS products that need to run anywhere with full type safety, TanStack Start is the better foundation. ## The Honest Tradeoff: Ecosystem Size Let me be direct about the real downside. The TanStack Start ecosystem is smaller than the Next.js ecosystem. Fewer Stack Overflow answers. Fewer blog posts. Fewer tutorials. This is the tradeoff you make as an early adopter of any technology. And it is a real cost. When you hit a strange edge case at 2am, having a large corpus of community solutions matters. But three things compensate for this in 2026: **AI coding tools have changed the equation.** Claude, Cursor, and other AI agents do not just rely on pre-trained knowledge. They actively read documentation while working. The quality of TanStack's docs matters more than the quantity of community blog posts. And TanStack's documentation is excellent: fresh, well-organized, and designed for both human and machine consumption. **The official docs are genuinely great.** Tanner Linsley and the TanStack team have invested heavily in documentation. The patterns are explicit, the examples are clear, and the API surface is well-documented. Compare this to the early days of Next.js App Router, where the community was collectively trying to figure out which patterns actually worked. **The community is growing fast.** The 15% adoption rate among React developers, combined with 50% interest, means TanStack Start is following the same growth curve Vite had in 2021-2022. The ecosystem will catch up. Getting in now means you are building expertise while most developers are still evaluating. ## Picking the Right Template Here is my honest recommendation based on what you need: **If you want to learn TanStack Start:** Use the [official examples](https://tanstack.com/start/latest/docs/framework/react/examples/start-basic). They are minimal, focused, and teach the core concepts without distractions. **If you want a minimal starting point:** Use [React Tanstarter](https://github.com/dotnize/react-tanstarter). It is free, open source, and gives you auth + database + UI without overwhelming you. **If you are building on Convex:** Use the [Convex TanStack SaaS Starter](https://www.convex.dev/templates/convex-saas). It is the best integration with Convex's real-time backend. **If you are deploying to Cloudflare:** Look at [TanStarter](https://tanstarter.dev/). It is purpose-built for Cloudflare Workers. **If you need multi-tenant billing flexibility:** [Saas UI](https://www.saas-js.com/) has strong workspace management and billing features. **If you are building a serious SaaS product and want the most complete foundation:** Use [Eden Stack](https://eden-stack.com). It is the only template that covers web, API, mobile, AI, background jobs, video creation, and agentic development in a single, cohesive codebase. And the 40+ Claude skills mean that building features on top of it is faster than any other option, because your AI assistant actually understands the architecture. ## The Opportunity The TanStack Start template ecosystem is still early. That is not a weakness. It is an opportunity. The framework is production-ready. The performance numbers are real. The type safety is genuinely better than the alternatives. And the ecosystem is growing fast enough that the "small community" concern has a shelf life. If you are the kind of developer who got into React early, who adopted Vite before everyone else, who tried Tailwind when people were still debating utility classes, then you already know what this moment feels like. The technology is solid. The momentum is building. The best time to start building on it is now. Pick a template that matches your needs, and start shipping. --- ### Should You Build From Scratch or Buy a SaaS Boilerplate? *Published: 2026-04-03* An honest framework for deciding whether a starter kit is worth it for your next project # Should You Build From Scratch or Buy a SaaS Boilerplate? I built and sell Eden Stack, so I obviously have a bias toward buying. But I've also built 7+ apps from scratch, and sometimes that was the right call. This post isn't a sales pitch. It's the decision framework I wish I had three years ago, when I spent six weeks wiring up auth, payments, and email before writing a single line of product code. Some of those builds taught me more than any boilerplate could. Others were a colossal waste of time. Let me help you figure out which camp your next project falls into. ## The Real Cost of Building From Scratch Most developers dramatically underestimate how long infrastructure takes. Not because they're bad at estimating, but because they're estimating the happy path. The real cost includes edge cases, security patches, testing, and the inevitable "why is this broken in production?" debugging sessions. Here's a realistic time breakdown for a production-grade SaaS foundation: | Component | Estimated Time | What's Actually Involved | |-----------|---------------|--------------------------| | **Authentication** | 3-5 days | OAuth providers, session management, email verification, password reset, CSRF protection, rate limiting | | **Payments** | 2-3 days | Stripe integration, webhook handling, subscription lifecycle, failed payment recovery, billing portal | | **Email** | 1-2 days | Transactional templates, delivery monitoring, unsubscribe handling, SPF/DKIM setup | | **Background Jobs** | 2-3 days | Job queue, retry logic, dead letter handling, monitoring, graceful shutdown | | **Analytics** | 1 day | Event tracking, user identification, page views, custom properties | | **Error Tracking** | Half a day | Source maps, error grouping, alerting, release tracking | | **Database Setup** | 1-2 days | Schema design, migrations, connection pooling, backups | | **CI/CD** | 1 day | Build pipeline, preview deployments, environment management | | **Type-Safe API Layer** | 2-3 days | Route definitions, validation, error handling, client generation | **Total: 2-3 weeks** before you write any product code. AI tools like Cursor and Claude Code have cut these timelines roughly in half compared to a few years ago, but it's still weeks of integration work rather than product work. And this estimate assumes things go smoothly. In practice, you'll hit at least a few of these: - An OAuth provider changes their API and your auth flow breaks - Stripe webhooks arrive out of order and your subscription state gets corrupted - Your background job processor silently drops events under load - A dependency update introduces a breaking change you don't notice until production Each of these is a 2-8 hour detour. They add up. ## When Building From Scratch IS the Right Call Here's where I break from the "always buy a boilerplate" crowd. There are genuinely good reasons to build from scratch. ### You're learning If you're building your first full-stack app, doing it from scratch is one of the best educational investments you can make. You'll understand auth at a level that no tutorial can teach. You'll know exactly why webhook idempotency matters because you'll debug the consequences of not having it. A boilerplate abstracts away the lessons. If learning is your primary goal, those lessons are the whole point. ### You have specific, unusual requirements If your app needs to run on-premise, handle HIPAA-compliant data flows, or integrate with a proprietary enterprise system, a general-purpose boilerplate might create more work than it saves. You'll spend time ripping out assumptions that don't match your constraints. ### Your team already has institutional knowledge If your team has built three SaaS products and has battle-tested internal libraries for auth, payments, and email, a boilerplate adds complexity without adding value. You'd be replacing known, trusted code with someone else's opinions. ### You want to contribute to open source Building infrastructure from scratch and open-sourcing the pieces is genuinely valuable work. Libraries like Lucia Auth, Hono, and Drizzle all started because someone decided the existing options weren't good enough. If you're building with the intent to share, the "wasted" time on infrastructure becomes the product itself. ### Your project is simple enough Not everything needs a full SaaS stack. If you're building a blog, a portfolio, or a simple CRUD app, the overhead of understanding and maintaining a boilerplate is worse than just writing the 200 lines of code you actually need. ## When Buying Makes Sense On the other hand, there are situations where building from scratch is actively harmful to your goals. ### You have time-to-market pressure If you're racing to validate an idea, every week spent on infrastructure is a week you're not learning from users. The market doesn't care how elegant your auth implementation is. It cares whether your product solves a real problem. ### You're a solo developer Solo devs face a brutal arithmetic: every hour you spend on infrastructure is an hour you can't spend on product, marketing, sales, or sleep. A boilerplate compresses months of foundational work into days of customization. ### You have a validated idea ready to build This is the sweet spot for boilerplates. You've already validated demand through a landing page, waitlist, or manual process. Now you need to build the real thing, and you need it yesterday. Starting from a production-ready foundation means your v1 ships with proper error tracking, analytics, and payment handling instead of "I'll add that later" (you won't). ### You've built this infrastructure before and hated it If you've already done the educational build and learned the lessons, doing it again is just tedium. There's no new insight in wiring up Stripe webhooks for the fourth time. ## The Middle Ground: Free Scaffolds vs. Paid Templates The choice isn't binary. There's a spectrum between "write everything yourself" and "buy a complete starter kit." ### Free Scaffolds Tools like **create-t3-app** and **Wasp** give you a solid starting point at no cost. **Pros:** - Zero financial risk - Community-maintained - Opinionated enough to get started, flexible enough to customize **Cons:** - You still wire up payments, email, background jobs, and analytics yourself - Less integrated; each piece is your responsibility to connect - Documentation quality varies - You're on your own for production hardening Free scaffolds are excellent for the "I know what I'm doing and just want to skip the boilerplate setup" developer. They give you the skeleton but not the muscles. ### Paid Templates Products like **Eden Stack**, **ShipFast**, and **MakerKit** give you a more complete starting point. **Pros:** - Pre-integrated stack (auth + payments + email + jobs + analytics working together) - Someone else has already debugged the integration edge cases - Documentation and support - Regular updates as dependencies evolve **Cons:** - Financial cost (typically $100-300+) - You inherit someone else's architectural opinions - Varying quality; some are genuinely excellent, others are glorified tutorials - Risk of abandonment if the maintainer moves on The value proposition of a paid template isn't the code itself. It's the hundreds of hours of integration testing, edge case handling, and "why does this break on Safari?" debugging that someone already did for you. ## What to Look for in a Boilerplate If you decide to buy, not all boilerplates are created equal. Here's what separates the good from the mediocre. ### Full source ownership This is non-negotiable. You should get the complete source code, with no hidden packages, no runtime dependencies on the boilerplate author's servers, and no subscription required to keep using the code. If a boilerplate ships as an npm package you install rather than source code you own, walk away. You need to be able to read, modify, and delete every line. ### Active maintenance Check the commit history. Is the author shipping updates? Are dependencies reasonably current? A boilerplate that was last updated eight months ago is a liability, not an asset. The JavaScript ecosystem moves fast, and security vulnerabilities in outdated dependencies are a real risk. ### Documentation quality Good documentation isn't just "how to install." It's "why this architectural decision was made" and "how to swap out this component for an alternative." You'll inevitably need to modify the boilerplate, and documentation is what makes that possible without reverse-engineering. ### AI-friendliness This is a newer criterion, but it matters more every month. A codebase designed for AI-assisted development has clear naming conventions, consistent patterns, and explicit architecture documentation that AI tools can reference. In practice, this means: - Claude skills or similar AI context files that explain the architecture - Consistent file structure that AI tools can navigate predictably - Type-safe APIs that give AI tools confidence about what's correct - Clear separation of concerns so AI can modify one layer without breaking another A boilerplate that's AI-friendly lets you move faster with tools like Claude Code, Cursor, or Windsurf. One that isn't will have you spending more time explaining context to your AI tools than writing code. ### Modern, composable architecture Beware of boilerplates that are tightly coupled monoliths. You should be able to remove integrations you don't need without the whole thing falling apart. If deleting the Stripe integration breaks the auth flow, the architecture has problems. ## The Hidden Cost of "Free" Here's something the "just use a free scaffold" crowd doesn't talk about enough: free has a cost, and it's measured in time. When you use a free scaffold or build from scratch, you're signing up for: - **Configuration time**: Connecting auth to your database, payments to your backend, email to your job queue. Each integration has its own quirks, environment variables, and edge cases. - **Debugging integration issues**: The auth library's session format doesn't match what the payment webhook expects. The email service rate-limits you during testing. The job queue silently drops events when the connection pool is exhausted. - **Keeping up with security updates**: Every dependency you install is a dependency you maintain. Auth libraries release security patches. Payment APIs deprecate endpoints. You need to stay on top of all of it. - **No single source of truth**: When you assemble your own stack, there's no canonical "this is how these pieces work together" reference. Every developer on the team builds a slightly different mental model. None of this is impossible to handle. But it's real work, and it compounds over time. The question isn't whether you _can_ do it. The question is whether it's the best use of your limited hours. ## The Time Question There's an insight I keep coming back to: people overestimate what they can accomplish in one year, but severely underestimate what they can accomplish in five years. The boilerplate question is really about how you spend your limited time. If you spend six weeks building infrastructure, that's six weeks you didn't spend on product. Multiply that across the three or four ideas you'll try over the next few years, and you've spent nearly six months on plumbing. Some of that time was educational. Some of it was just repetitive. A boilerplate compresses those six weeks into a few days of setup and customization. That leaves you five extra weeks to build features, talk to users, and figure out if your idea has legs. If it doesn't, you pivot faster. If it does, you scale on a solid foundation. But here's the thing: if you're early in your career and the learning _is_ the goal, those six weeks of infrastructure work might be the most valuable six weeks of your year. Context matters. ## My Framework Here's the decision tree I'd use: 1. **Is this primarily a learning project?** Build from scratch. The struggle is the education. 2. **Do you have unusual technical constraints?** Build from scratch, or heavily customize a boilerplate that's close to what you need. 3. **Are you racing to validate an idea?** Buy a boilerplate. Every week matters. 4. **Are you a solo dev building a real product?** Buy a boilerplate. Your time is your most scarce resource. 5. **Does your team already have proven internal tooling?** Use what you have. A boilerplate would just be noise. 6. **Is this your second or third SaaS?** Buy a boilerplate. You've already learned the lessons. There's no universally right answer. But there _is_ a right answer for your specific situation, and it depends on what you're optimizing for: learning, speed, control, or some combination of all three. ## Final Thought The best codebase isn't the one with the most elegant architecture. It's the one that lets you ship a product people want to use. Whether that starts from scratch or from a boilerplate is a detail. What matters is that you're spending your time on the work that only you can do: understanding your users and building something they'll pay for. Everything else is infrastructure. And infrastructure, one way or another, should be a solved problem. --- ### Deploy to Production in 5 Minutes *Published: 2025-01-25* Go from local development to a live production app with Vercel, Railway, and Neon # Deploy to Production in 5 Minutes Eden Stack is designed for fast deployment. The web app goes to Vercel, the API goes to Railway, and the database is already on Neon. Let's get you live. ## Prerequisites Before you start: - [ ] Neon database created (you should have this from development) - [ ] GitHub repo with your code pushed - [ ] Vercel account (free tier works) - [ ] Railway account (free tier works) ## Minute 0-2: Deploy the API to Railway ### Step 1: Install Railway CLI ```bash npm install -g @railway/cli railway login ``` ### Step 2: Initialize and Deploy ```bash cd apps/api railway init # Select "Create new project" # Name it: my-app-api railway up ``` ### Step 3: Set Environment Variables ```bash railway variables set DATABASE_URL="your-neon-connection-string" railway variables set BETTER_AUTH_SECRET="your-secret" railway variables set BETTER_AUTH_URL="https://your-app-api.railway.app" railway variables set NODE_ENV="production" # Add any other secrets you need railway variables set STRIPE_SECRET_KEY="sk_live_..." railway variables set STRIPE_WEBHOOK_SECRET="whsec_..." railway variables set RESEND_API_KEY="re_..." railway variables set OPENAI_API_KEY="sk-..." ``` ### Step 4: Generate Domain ```bash railway domain # Copy the generated URL (e.g., my-app-api-production.railway.app) ``` Your API is now live! Test it: ```bash curl https://my-app-api-production.railway.app/health # Should return: {"status":"ok","timestamp":"..."} ``` ## Minute 2-4: Deploy the Web App to Vercel ### Step 1: Import Project 1. Go to [vercel.com/new](https://vercel.com/new) 2. Import your GitHub repository 3. Set the root directory to `apps/web` ### Step 2: Configure Environment Variables Add these in Vercel's dashboard: | Variable | Value | |----------|-------| | `VITE_API_URL` | `https://my-app-api-production.railway.app` | | `BETTER_AUTH_URL` | `https://my-app.vercel.app` | ### Step 3: Deploy Click **Deploy**. Vercel will build and deploy automatically. Your web app is now live at `https://my-app.vercel.app`! ## Minute 4-5: Connect the Pieces ### Update CORS on Railway Your API needs to accept requests from your Vercel domain: ```bash railway variables set CORS_ORIGIN="https://my-app.vercel.app" railway up # Redeploy with new config ``` ### Update Auth URLs If using OAuth (Google, etc.), update callback URLs in your provider's dashboard: | Provider | Callback URL | |----------|--------------| | Google | `https://my-app-api-production.railway.app/api/auth/callback/google` | ### Verify Everything Works 1. Visit your Vercel URL 2. Try logging in 3. Create some data 4. Check Railway logs for any errors ```bash railway logs ``` ## Quick Reference: All Commands ```bash # Deploy API cd apps/api railway up # Deploy Web (push to main branch triggers Vercel) git push origin main # View logs railway logs # Check status railway status ``` ## Environment Variables Checklist ### Railway (API) | Variable | Required | Notes | |----------|----------|-------| | `DATABASE_URL` | Yes | Neon connection string | | `BETTER_AUTH_SECRET` | Yes | 32+ char random string | | `BETTER_AUTH_URL` | Yes | Your Railway URL | | `NODE_ENV` | Yes | Set to `production` | | `CORS_ORIGIN` | Yes | Your Vercel URL | | `STRIPE_SECRET_KEY` | If using payments | Live key | | `STRIPE_WEBHOOK_SECRET` | If using payments | Webhook secret | | `RESEND_API_KEY` | If using email | | | `INNGEST_EVENT_KEY` | If using background jobs | | | `OPENAI_API_KEY` | If using AI | | | `ANTHROPIC_API_KEY` | If using agents | | ### Vercel (Web) | Variable | Required | Notes | |----------|----------|-------| | `VITE_API_URL` | Yes | Your Railway URL | | `BETTER_AUTH_URL` | Yes | Your Vercel URL | ## Troubleshooting ### CORS Errors If you see CORS errors in the browser console: 1. Verify `CORS_ORIGIN` is set correctly on Railway 2. Ensure the URL doesn't have a trailing slash 3. Redeploy: `railway up` ### Auth Not Working 1. Check `BETTER_AUTH_URL` matches your actual URL (no trailing slash) 2. Verify `BETTER_AUTH_SECRET` is the same in both environments 3. Check Railway logs for auth errors ### Database Connection Errors 1. Verify `DATABASE_URL` is correct 2. Ensure it ends with `?sslmode=require` 3. Check if Neon project is active (not suspended) ### Build Failures ```bash # Check build logs railway logs --build # Or on Vercel, check the deployment logs in the dashboard ``` ## Automatic Deployments ### Railway Railway auto-deploys when you push to your connected branch: ```bash # In apps/api railway link # Connect to your project # Now every push deploys automatically git push origin main ``` ### Vercel Vercel deploys automatically on push by default. To disable: 1. Go to Project Settings → Git 2. Toggle off "Auto Deploy" ## Cost Estimate For a small-to-medium app: | Service | Free Tier | Paid Estimate | |---------|-----------|---------------| | **Neon** | 0.5 GB storage, 190 compute hours | $19/mo for Pro | | **Railway** | $5 credit/month | ~$5-20/mo | | **Vercel** | 100 GB bandwidth | ~$0-20/mo | | **Total** | $0-5/mo | ~$25-60/mo | ## Custom Domain ### Vercel 1. Go to Project Settings → Domains 2. Add your domain 3. Update DNS as instructed ### Railway ```bash railway domain --set yourdomain.com ``` Then add the CNAME record to your DNS. ## Next Steps - Set up monitoring with [Sentry](https://sentry.io) - see `@eden/observability` package - Add analytics with [PostHog](https://posthog.com) - see `@eden/analytics` package - Configure [Stripe webhooks](/docs/stripe-payments) for production - Set up [Inngest](/docs/background-jobs) in production Your app is live! Check out the [Deploy to Vercel](/docs/deploy-to-vercel) and [Deploy API](/docs/deploy-api) docs for more advanced configuration. --- ### Create T3 App vs Eden Stack: Free Scaffold or Production Foundation? *Published: 2026-04-03* When a free CLI scaffold is enough, and when you need a complete production starter kit # Create T3 App vs Eden Stack: Free Scaffold or Production Foundation? This comparison is different from the ones I usually write. ShipFast, Makerkit, and other paid starter kits compete in the same category as Eden Stack. Create T3 App does not. It's a free, open-source CLI that gives you a starting point. Eden Stack is a production-ready foundation that gives you a finished architecture. They solve different problems. And I think that distinction matters more than any feature table. ## What Create T3 App Actually Is [Create T3 App](https://create.t3.gg/) is the most popular scaffold in the TypeScript full-stack ecosystem, with nearly 29,000 GitHub stars and a massive community behind it. Built by Theo Browne and the T3 OSS team, the CLI generates a modular Next.js project where you pick and choose your pieces: - **Next.js** as the framework - **tRPC** for type-safe API routes - **Prisma** or **Drizzle** as your ORM - **NextAuth.js** for authentication - **Tailwind CSS** for styling You run a single command, answer a few prompts, and get a clean project with your selected tools wired together. It's elegant. It's free. And it works. The project's philosophy is explicit about its boundaries: Create T3 App is **not an all-inclusive template**. It solves the "how do I set up these tools together correctly?" problem. It deliberately does not solve the "what else do I need for a production SaaS?" problem. The team expects you to bring your own solutions for everything beyond the core scaffold. ## What Eden Stack Actually Is Eden Stack is a premium, production-ready starter kit. When you purchase it, you get a fully working application with 60+ primitives across 7 domains, all pre-integrated and tested against each other. It includes the database, the API layer, authentication, payments, email, background jobs, analytics, error tracking, AI capabilities, video creation, and a mobile app. It also ships with 40+ Claude skills that teach AI agents how the entire architecture fits together. You don't assemble anything. You start removing what you don't need. ## The Core Distinction: Scaffold vs. Foundation This is the most important thing to understand about these two projects. **Create T3 App gives you a skeleton.** It's the starting line. The CLI generates maybe 10-15 files with the right configuration and a basic example of how each tool connects to the others. From there, you build everything yourself: your database schema, your API routes, your auth flows, your payment integration, your email system, your deployment pipeline. **Eden Stack gives you a working product.** It's the 90% mark. You start with a complete application that already handles auth flows, Stripe checkout, transactional emails, background job processing, analytics tracking, and error monitoring. From there, you customize it to match your specific product. The work that separates a T3 scaffold from a production SaaS is substantial. After running `create-t3-app`, you still need to: 1. **Add payment processing.** Set up Stripe, build checkout flows, handle webhooks, manage subscription states, wire up customer portals. 2. **Add transactional email.** Pick a provider, build templates, handle delivery, set up domain verification. 3. **Add background jobs.** Choose a queue system, implement retry logic, handle failures gracefully, build monitoring. 4. **Add analytics.** Instrument events, set up funnels, configure server-side tracking, implement feature flags. 5. **Add error tracking.** Integrate Sentry or similar, configure source maps, set up alerts, build error boundaries. 6. **Add deployment infrastructure.** Configure CI/CD, set up environment management, handle database migrations in production. 7. **Add AI capabilities.** If your product needs them: RAG pipelines, vector storage, streaming chat, agent patterns. 8. **Add mobile apps.** If your product needs them: Expo setup, shared types, auth token management, push notifications. Each of these is a multi-day project, and each introduces integration complexity that compounds. Getting Stripe webhooks to reliably trigger Inngest functions that send Resend emails while tracking events in PostHog is not trivial, even when each individual tool has good documentation. Eden Stack ships with all of this already working. That's the value proposition. ## Framework Choices The framework difference is worth discussing on its own. **Create T3 App is built on Next.js.** This is both its greatest strength and a meaningful constraint. Next.js has the largest ecosystem, the most tutorials, the most StackOverflow answers. If you hit a problem, someone has probably solved it before. Vercel's investment in the framework means it will be well-maintained for the foreseeable future. **Eden Stack is built on TanStack Start + Elysia.** This is a deliberate choice. TanStack Start compiles to standard JavaScript that runs anywhere: Node, Bun, Deno, Cloudflare, AWS, Azure. There's no implicit coupling to a specific hosting provider. Elysia, running on Bun, provides a standalone API server with native Eden Treaty integration for end-to-end type safety without code generation. I wrote a [separate post](/blog/why-tanstack-start-over-nextjs) about why I chose TanStack Start over Next.js. The short version: deployment flexibility, genuine type safety at the route level, and independence from any single platform's roadmap. ## Type Safety Approaches Both projects value type safety, but they achieve it differently. **T3's approach: tRPC.** tRPC is genuinely innovative. It gives you type-safe API calls between your Next.js frontend and backend without writing any API contracts or generating code. You define a router, and the client knows the types. It works well, and Theo's community has built extensive tooling around it. The tradeoff is that tRPC is tightly coupled to the Next.js request/response model. If you want to expose your API to a mobile app, a CLI tool, or a third-party integration, you need additional work to create a REST or GraphQL layer alongside tRPC. **Eden Stack's approach: Elysia + Eden Treaty.** Elysia's type system infers types from route definitions, and Eden Treaty provides a type-safe client that mirrors the API structure. The result is similar to tRPC in practice (you get autocomplete and type checking across the client/server boundary), but the API is also a standard HTTP server. Any HTTP client can call it. Mobile apps, external services, and webhook providers all work without an adapter layer. Both approaches are valid. If you're building a web-only product and never need external API consumers, tRPC is excellent. If you need your API to serve multiple clients, Eden Treaty gives you type safety without sacrificing HTTP compatibility. ## The Learning Argument Here's where I want to be genuinely honest: **Create T3 App is a better learning tool than Eden Stack.** When you scaffold a T3 project, you understand every file. There are maybe 15 files, each doing one clear thing. You wrote the schema. You wrote the API routes. You understand exactly how data flows from the database to the UI because you built the entire pipeline yourself. Eden Stack is the opposite experience. You start with a working application that has thousands of lines of code across dozens of integrations. Even with Claude skills that explain the architecture, there's an inherent orientation period where you're navigating someone else's decisions before you start making your own. Theo's YouTube channel (with nearly 500,000 subscribers) and the T3 community Discord are extraordinary educational resources. If you're learning full-stack TypeScript development, the T3 ecosystem will teach you more than any starter kit. The question is: **are you here to learn, or are you here to ship?** If you're building a side project to understand how Prisma and tRPC work together, use Create T3 App. You'll learn more, and it's free. If you're building a SaaS product and your competitive advantage is your product, not your infrastructure, Eden Stack will save you weeks of integration work that has nothing to do with your core business logic. ## Community vs. Architecture **T3 has the larger community.** 29,000 GitHub stars. A Discord server with tens of thousands of members. Hundreds of tutorials, blog posts, and YouTube videos. If you get stuck, someone has probably written about your exact problem. This community moat is real, and it's a significant advantage. **Eden Stack has the deeper architecture.** 40+ Claude skills that encode institutional knowledge about every integration pattern. Decision documents explaining why each tool was chosen. A codebase designed for agentic development, where AI agents can navigate, understand, and modify the architecture with precision. The community is smaller, but the documentation density per integration is higher. These are different kinds of support. T3's community support scales through people. Eden Stack's architectural support scales through AI. ## The Price Question Create T3 App is free. Eden Stack is not. That matters, and I won't pretend it doesn't. If you're a student, a hobbyist, or someone exploring full-stack development, the price of Eden Stack is hard to justify. Create T3 App gives you a great starting point, and the learning you'll do by building the rest yourself is genuinely valuable. If you're a professional developer or a founder with a product to ship, the calculation changes. The integrations Eden Stack includes would take 2-4 weeks to build from a T3 scaffold, depending on your experience and how many you need. If your time is worth more than the price of Eden Stack divided by those weeks, the math works out. This isn't a universal truth. Some developers genuinely enjoy building infrastructure, and the work of integrating Stripe and Inngest and Resend is part of what makes the project satisfying. If that's you, start with T3 and build it yourself. You'll end up with something you understand deeply. ## Feature Comparison | Dimension | Create T3 App | Eden Stack | |-----------|--------------|------------| | **Price** | Free | Paid | | **Type** | CLI scaffold | Production-ready template | | **Framework** | Next.js | TanStack Start | | **API Layer** | tRPC | Elysia + Eden Treaty | | **ORM** | Prisma or Drizzle | Drizzle | | **Auth** | NextAuth.js | Better Auth | | **Styling** | Tailwind CSS | Tailwind CSS | | **Payments** | Not included | Stripe (pre-integrated) | | **Email** | Not included | Resend + React Email | | **Background Jobs** | Not included | Inngest | | **Analytics** | Not included | PostHog | | **Error Tracking** | Not included | Sentry | | **AI Capabilities** | Not included | RAG, agents, chat UI | | **Mobile App** | Not included | Expo (iOS + Android) | | **Video Creation** | Not included | Remotion + ElevenLabs | | **AI Dev Support** | Not included | 40+ Claude skills | | **Community Size** | ~29K GitHub stars | Smaller, growing | | **Deployment** | Vercel-optimized | Platform-agnostic | ## When to Choose Create T3 App 1. **You're learning full-stack TypeScript.** The T3 scaffold plus Theo's educational content is the best on-ramp in the ecosystem. 2. **You want to understand every line.** Starting from a minimal scaffold means nothing is a mystery. You built it, you own it intellectually. 3. **Your project is straightforward.** If you need a web app with auth and a database, and you don't need payments, email, or background jobs, T3 gives you exactly enough. 4. **You're budget-conscious.** Free is free. The time investment to add integrations later is real, but it's spread over time rather than upfront. 5. **You prefer Next.js.** If your team already knows Next.js, or you want the massive ecosystem that comes with it, T3 is the best way to start a Next.js project. ## When to Choose Eden Stack 1. **You're building a SaaS product.** If you know you'll need payments, email, and background jobs eventually, starting with them already integrated saves compounding integration work. 2. **You value time over money.** The integrations in Eden Stack represent weeks of work. If your time is better spent on product features, the trade is worth it. 3. **You want AI-native development.** The 40+ Claude skills mean AI agents can navigate, modify, and extend your codebase with architectural awareness that generic AI coding tools can't match. 4. **You need mobile.** A first-class Expo app with shared types and auth is included. Building this from a T3 scaffold is a significant project on its own. 5. **You want deployment flexibility.** TanStack Start runs anywhere. No implicit hosting provider dependency. 6. **You want end-to-end type safety with HTTP compatibility.** Eden Treaty gives you the DX of tRPC with the flexibility of a standard API server. ## Conclusion Create T3 App and Eden Stack are not competitors. They're answers to different questions. T3 asks: "What's the best way to start a typesafe Next.js project?" Its answer is a clean scaffold with the right tools wired together correctly. It's free, it's well-documented, and Theo's community will help you when you get stuck. For many developers and many projects, it's exactly right. Eden Stack asks: "What's the best way to start a production SaaS?" Its answer is a complete foundation with the integrations already built, tested, and documented for both human and AI developers. It costs money, but it replaces weeks of integration work with hours of customization. If you're not sure which one you need, start with T3. It's free, the learning is valuable, and you can always upgrade to a more complete solution later when you know what your project actually requires. There's no shame in starting simple, and there's real wisdom in it. If you already know you're building something serious, and you've done the infrastructure dance before, Eden Stack lets you skip the parts that don't differentiate your product and focus on the parts that do. --- ### MakerKit vs Eden Stack: Which SaaS Boilerplate Fits Your Project? *Published: 2026-04-03* A detailed comparison of two production-ready starter kits with different philosophies # MakerKit vs Eden Stack: Which SaaS Boilerplate Fits Your Project? **MakerKit** is one of the most established SaaS starter kits on the market. It has been around since 2022, supports multiple tech stacks, and has powered hundreds of production applications. It is a serious contender, and I want to give it a fair comparison. **Eden Stack** is what I built as an alternative. It makes a set of deliberate tradeoffs: fewer choices, deeper integrations, and an AI-native development experience from day one. This post walks through how the two compare. I will be honest about where MakerKit wins and where I think Eden Stack offers something better. ## The Quick Overview ### MakerKit: The Flexible Veteran MakerKit, created by Giancarlo Buomprisco, is a mature SaaS boilerplate with multiple stack variants. You can choose between Supabase, Drizzle + Better Auth, or Prisma 7 + Better Auth for your data layer, and between Next.js 16 or React Router 7 as your framework. It ships with deep multi-tenancy support, an admin dashboard, three payment providers, and internationalization out of the box. At $299-$349 for the Pro tier (depending on the stack), it targets teams that want flexibility and B2B features. ### Eden Stack: The Opinionated AI-Native Kit Eden Stack is a single, opinionated stack: TanStack Start, Elysia, Eden Treaty, Neon PostgreSQL, and Drizzle. Instead of offering multiple paths, it goes deep on one. It includes 40+ Claude skills for agentic development, Inngest background jobs, PostHog analytics, and Sentry error tracking. At $99, it is the most affordable option in its class, designed for technical founders who want to build with AI assistance from the start. ## Philosophy: Flexibility vs. Focus This is the fundamental difference between these two kits, and it shapes every other tradeoff. **MakerKit** gives you options. Three ORM/database combinations, two frameworks, three payment providers, and a plugin system for extending functionality. This is genuinely powerful if you have strong preferences about your stack or need to match an existing team's expertise. The downside is that maintaining three stack variants means spreading effort across multiple codebases. **Eden Stack** gives you one path. TanStack Start for the frontend, Elysia for the API, Drizzle with Neon for the database, Stripe for payments. Every integration is tested against every other integration. The 40+ Claude skills encode knowledge about how these specific tools work together. The tradeoff is obvious: if you strongly prefer Next.js or Prisma, Eden Stack is not the right fit. ## Feature Comparison | Dimension | MakerKit | Eden Stack | |-----------|----------|------------| | **Price** | $299-$349 (Pro) / $599-$649 (Teams) | $99 | | **Framework** | Next.js 16 or React Router 7 | TanStack Start | | **API Layer** | tRPC / Server Actions | Elysia + Eden Treaty | | **Database** | Supabase, Drizzle, or Prisma 7 | Drizzle + Neon PostgreSQL | | **Auth** | Supabase Auth or Better Auth | Better Auth | | **Payments** | Stripe, Lemon Squeezy, Paddle | Stripe | | **Multi-tenancy** | Deep (orgs, RBAC, invitations) | Yes (workspaces, roles, invitations) | | **Admin Dashboard** | Yes (with user impersonation) | No | | **File Storage** | Not included | Cloudflare R2 (pre-configured) | | **i18n** | Built-in | Opt-in via Claude skills | | **Background Jobs** | Not included | Inngest (durable workflows) | | **Analytics** | Pluggable (PostHog, GA, Umami) | PostHog (pre-configured) | | **Error Tracking** | Plugin available (Honeybadger) | Sentry (pre-configured) | | **Type Safety** | Good (tRPC) | End-to-end (Eden Treaty) | | **AI Dev Support** | MCP server + cursor rules | 40+ Claude skills + MCPs | | **Email** | React Email | React Email + Resend | | **UI Components** | shadcn/ui + Figma kit | shadcn/ui | | **Documentation** | 400+ pages | Comprehensive docs + skills | | **Blog/CMS** | Markdoc | MDX (Content Collections) | ## Where MakerKit Wins I want to be straightforward about this. MakerKit has clear advantages in several areas. ### Multi-tenancy and B2B Features Both templates include multi-tenancy. Eden Stack ships workspaces with roles (owner/admin/member), invitations, and a workspace switcher via Better Auth's organization plugin. MakerKit goes deeper: more granular RBAC, per-seat billing tied to organizations, an admin dashboard with user impersonation, and years of iteration on B2B edge cases. If you need deep multi-tenancy with seat-based billing and admin tooling, MakerKit's implementation is more mature. ### Stack Flexibility Some teams have strong opinions about their tools, and MakerKit respects that. If your team already knows Next.js and Prisma, you can start with a familiar stack. If you prefer Supabase for its real-time features and managed auth, that option exists. Eden Stack only offers one path. ### Payment Provider Options MakerKit supports Stripe, Lemon Squeezy, and Paddle. This matters if you sell to international markets where Paddle handles VAT/sales tax as a Merchant of Record, or if you prefer Lemon Squeezy's simpler pricing model. Eden Stack only supports Stripe. ### Internationalization Built-in i18n is table stakes for products targeting non-English markets. MakerKit includes it. Eden Stack does not. ### Admin Dashboard The super admin panel with user impersonation is genuinely useful for customer support. Being able to see exactly what a user sees when they report a bug saves real debugging time. ## Where Eden Stack Wins ### Price Eden Stack costs $99. MakerKit's Pro tier ranges from $299 to $349 depending on the stack variant, and the Teams tier goes up to $649. That is 3-6x more expensive. For solo founders and early-stage projects, this difference is meaningful. ### Background Jobs This is a significant gap in MakerKit's offering. Modern SaaS applications need durable background processing for tasks like sending emails after signup, processing webhook events reliably, syncing data with third-party APIs, and running scheduled maintenance. Eden Stack includes Inngest with pre-built patterns for all of these. With MakerKit, you need to build or integrate this yourself. ### AI-Native Development Eden Stack ships with 40+ Claude skills that encode institutional knowledge about how the stack works. These are not just documentation. They are structured instructions that help AI agents (Claude Code, Cursor, Codex) write correct code for your specific stack. MakerKit has added MCP server support and cursor rules more recently, but the depth is not comparable. Eden Stack's skills cover everything from database migrations to Stripe webhook handling to email template creation. ### End-to-End Type Safety Eden Treaty provides compile-time type safety from your Elysia API routes all the way to your frontend components. Change an API response shape, and TypeScript immediately tells you every place in your frontend that needs updating. MakerKit offers good type safety through tRPC, but Eden Treaty's approach of deriving client types directly from the server definition eliminates an entire class of runtime errors. ### Observability Out of the Box Eden Stack comes with PostHog analytics and Sentry error tracking pre-configured and integrated. You get event tracking, feature flags, session replay, error boundaries, and performance monitoring from day one. MakerKit offers pluggable analytics (you can connect PostHog, Google Analytics, or Umami) and has a Honeybadger plugin, but the integrations are shallower. Eden Stack's approach means you never ship a feature without observability. ### Simplicity Through Opinionation Having one stack means every decision is already made. There is no "which database adapter should I use?" or "should I pick Next.js or React Router?" moment. The 40+ Claude skills all target the same stack, so AI assistance is more precise. The documentation covers one path deeply rather than three paths broadly. For solo developers and small teams, this reduction in decision fatigue is valuable. ## When to Choose MakerKit MakerKit is the right choice if: 1. **You are building a B2B product with teams and organizations.** The multi-tenancy, RBAC, and invitation system are mature and battle-tested. 2. **Your team already knows Next.js.** Starting with a familiar framework eliminates ramp-up time. 3. **You need multiple payment providers.** Paddle or Lemon Squeezy support can be critical for international sales. 4. **You need i18n from day one.** Built-in internationalization saves significant effort. 5. **You want stack flexibility.** Being able to choose between Supabase, Drizzle, and Prisma is genuinely useful if you have preferences. ## When to Choose Eden Stack Eden Stack is the right choice if: 1. **You are a solo technical founder or small team.** The $99 price point, single opinionated stack, and deep AI support maximize your velocity. 2. **You use AI to write code.** The 40+ Claude skills make agentic development dramatically more effective than working with a generic boilerplate. 3. **You need background jobs.** Inngest support for durable workflows, webhook processing, and cron jobs is built in, not bolted on. 4. **You value end-to-end type safety.** Eden Treaty's compile-time guarantees from API to frontend catch errors before they reach production. 5. **You want observability from day one.** Pre-configured PostHog and Sentry mean you ship with analytics and error tracking, not without them. 6. **You want a modern, non-Next.js stack.** TanStack Start + Elysia is a genuinely different architecture that avoids the complexity of React Server Components. ## A Note on Maintenance One thing worth considering: MakerKit maintains three separate stack variants across two frameworks. That is a lot of surface area for a solo maintainer. Eden Stack maintains one stack. This means updates, bug fixes, and new features land faster and are tested more thoroughly against the specific set of tools you are using. Neither approach is inherently better, but it is a tradeoff worth understanding. ## Conclusion MakerKit and Eden Stack solve the same fundamental problem (getting your SaaS to market faster) but make very different bets. **MakerKit bets on flexibility and B2B readiness.** It gives you choices, deep multi-tenancy, and a proven track record across hundreds of production apps. If you are building a team-oriented product and want the safety of a mature, established boilerplate, MakerKit delivers. **Eden Stack bets on focus, AI-native development, and operational depth.** It picks one stack and goes deep, with background jobs, observability, and 40+ Claude skills that make AI-assisted development genuinely effective. If you are a technical founder who wants to move fast with AI and ship a product that works reliably from day one, Eden Stack is built for that. Both are legitimate choices. The right one depends on what you are building and how you like to work. --- ### SupaStarter vs Eden Stack: Choosing Your SaaS Foundation *Published: 2026-04-03* Comparing two modern SaaS boilerplates with different approaches to full-stack development # SupaStarter vs Eden Stack: Choosing Your SaaS Foundation If you're shopping for a SaaS starter kit in 2026, **SupaStarter** is one of the most polished options available. It's been around longer than Eden Stack, it supports multiple frameworks, and it's earned the trust of over 1,200 developers. That's not nothing. **Eden Stack** is the kit I built. It takes a narrower, more opinionated approach: one stack, deep AI integration, and a focus on end-to-end type safety. This comparison is my honest attempt to help you figure out which one fits your situation. I'm biased toward my own product, of course. But I'll be straightforward about where SupaStarter does things better. ## The Quick Overview ### SupaStarter: The Flexible Foundation SupaStarter is a mature, feature-rich boilerplate that supports **Next.js, Nuxt, and SvelteKit**. It uses a Turborepo monorepo with separate apps for marketing, the SaaS product, docs, and email previews. The API layer runs on Hono with oRPC for type-safe communication, and auth is handled by Better Auth. Its standout quality is **breadth**. Five payment providers. Multiple ORM choices (Prisma or Drizzle). Multiple database providers. i18n out of the box. Multi-tenancy with organizations. If you want options, SupaStarter gives you options. ### Eden Stack: The Opinionated Engine Eden Stack is a single-stack boilerplate built on **TanStack Start, Elysia, and Eden Treaty**. It trades flexibility for depth. There's one API framework, one ORM, one database, one payment provider. But every piece is wired together with end-to-end type safety, 40+ Claude skills for AI-assisted development, and built-in observability via PostHog and Sentry. Its standout quality is **cohesion**. Every integration is designed to work together as a single system, with AI agents that understand the entire architecture. ## Philosophy: Flexibility vs. Focus This is the fundamental tradeoff between the two kits. **SupaStarter** gives you choices. Want Prisma? Drizzle? PostgreSQL? MySQL? Next.js? Nuxt? SvelteKit? It supports all of them. This is genuinely valuable if you have strong preferences about your stack, or if you're building for a team that already knows Nuxt or SvelteKit. The flexibility means more developers can use it without learning a new framework. **Eden Stack** makes choices for you. TanStack Start. Elysia. Drizzle. Neon. Stripe. That's the stack. The benefit is that every skill, every pattern, every piece of documentation assumes this exact combination. When an AI agent builds a feature for you, it knows exactly how your API talks to your database, how your auth middleware works, and how your webhooks flow into background jobs. There's no ambiguity. Neither approach is wrong. It depends on whether you value optionality or integration depth. ## Feature Comparison | Dimension | SupaStarter | Eden Stack | |-----------|-------------|------------| | **Price** | $349 / $799 / $1,499 | $99 one-time | | **Frameworks** | Next.js, Nuxt, SvelteKit | TanStack Start | | **API Layer** | Hono + oRPC | Elysia + Eden Treaty | | **Type Safety** | oRPC (strong) | Eden Treaty (end-to-end) | | **Auth** | Better Auth | Better Auth | | **ORM** | Prisma or Drizzle | Drizzle | | **Database** | PostgreSQL, MySQL, SQLite | Neon PostgreSQL | | **Payments** | Stripe, Lemon Squeezy, Polar, Creem, Dodo | Stripe | | **Multi-tenancy** | Yes (organizations) | Yes (workspaces, roles, invitations) | | **i18n** | Yes | Opt-in via Claude skills | | **Background Jobs** | trigger.dev + QStash | Inngest | | **File Storage** | S3-compatible | Cloudflare R2 (pre-configured) | | **Analytics** | Multiple providers | PostHog (included) | | **Error Tracking** | Sentry | Sentry | | **Email** | React Email | React Email + Resend | | **AI Agent Support** | AGENTS.md + structured codebase | 40+ Claude skills + MCP servers | | **Blog/CMS** | Built-in | MDX with Content Collections | | **Admin Dashboard** | Yes | No | | **Docker/Self-hosting** | Yes | Vercel-optimized | | **Architecture** | Turborepo monorepo (multi-app) | Single project (flat) | | **Developer Seats** | 1 / 5 / 10 (by tier) | Unlimited | ## Where SupaStarter Wins I want to be direct about this. There are several areas where SupaStarter is the stronger choice. **Multi-framework support.** If your team knows Nuxt or SvelteKit, Eden Stack simply doesn't support those. SupaStarter lets you pick the framework your team already knows. **Multi-tenancy depth.** Both ship with multi-tenancy. Eden Stack includes workspaces, roles (owner/admin/member), and invitations via Better Auth's organization plugin. SupaStarter's implementation goes further with more granular permissions and a polished admin panel for managing organizations. **Internationalization.** If you're targeting a global audience and need your app in multiple languages from day one, SupaStarter has i18n built in. Eden Stack treats i18n as opt-in: a Claude skill can set up i18next with locale detection and string extraction, but it's not there by default. **Payment provider variety.** Five payment providers versus one. If you need Lemon Squeezy for EU-friendly merchant of record, or Polar for open-source monetization, SupaStarter has you covered. **Admin dashboard.** SupaStarter ships a full admin UI. That's real time saved if you need internal tooling on day one. **Self-hosting with Docker.** If Vercel isn't an option for you, SupaStarter's Docker support makes deployment more flexible. **Self-hosting with Docker.** If Vercel isn't an option for you, SupaStarter's Docker support makes deployment more flexible. ## Where Eden Stack Wins **Price.** $99 versus $349 (minimum). And Eden Stack has no seat limits. For a bootstrapped solo founder, that difference matters. **End-to-end type safety with Eden Treaty.** Both kits have type-safe APIs, but Eden Treaty's approach means your client code, your API, and your database schema form a single type chain. Change a column in Drizzle and TypeScript immediately tells you which API routes and frontend components need updating. It's a different level of confidence during refactors. **Deep AI-native development.** This is Eden Stack's core differentiator. The 40+ Claude skills aren't just documentation. They're executable knowledge that AI agents use to build features correctly. When Claude Code works on your Eden Stack project, it knows how to wire up a Stripe webhook through Inngest, create an email template with Resend, add PostHog tracking, and handle the database migration. SupaStarter includes an AGENTS.md file and a structured codebase, which is a solid start. But the depth of Eden Stack's agentic support is in a different category. **Inngest for background jobs.** Inngest provides durable, retryable workflows with step functions and built-in observability. It's a more robust solution than trigger.dev + QStash for complex background processing. **Built-in observability stack.** PostHog for analytics and feature flags, plus Sentry for error tracking, are wired in from the start. Not just supported, but configured and integrated into the auth flow, API middleware, and deployment pipeline. **Single coherent architecture.** Because Eden Stack makes all the choices for you, there's zero decision fatigue. You don't need to evaluate Prisma vs. Drizzle, or Next.js vs. Nuxt. You open the project and start building. Every blog post, skill, and code pattern assumes the same stack. ## When to Choose SupaStarter SupaStarter is the right call if: 1. **Your team uses Nuxt or SvelteKit.** Eden Stack only supports TanStack Start. If your team has existing expertise in another framework, don't fight it. 2. **You need multi-tenancy on day one.** Building a B2B product with organizations and team management? SupaStarter ships this. Building it from scratch is weeks of work. 3. **You need i18n.** If your product launches in multiple languages, having translations built into the routing and component layer saves significant effort. 4. **You want maximum deployment flexibility.** Docker Compose, self-hosting, multiple database providers. SupaStarter gives you more options for where and how you run your app. 5. **You need multiple payment providers.** Lemon Squeezy, Polar, Creem, and Dodo alongside Stripe. If you have a specific reason to avoid Stripe, SupaStarter supports alternatives. ## When to Choose Eden Stack Eden Stack is the right call if: 1. **You're a solo technical founder on a budget.** $99, no seat limits, and a stack that's designed to be extended by AI agents. You get leverage without spending $349+. 2. **You want AI agents to build features for you.** The 40+ Claude skills mean that AI-assisted development isn't an afterthought. It's the primary workflow. If you're already using Claude Code or plan to, Eden Stack is built for that. 3. **You value type safety above all else.** Eden Treaty's end-to-end type chain from database to frontend is the tightest type safety I've seen in a starter kit. 4. **You need durable background jobs.** Inngest's step functions, retries, and fan-out patterns handle complex workflows that simpler job queues can't. 5. **You want observability from the start.** PostHog analytics and Sentry error tracking are pre-configured, not just listed as supported integrations. 6. **You prefer one opinionated stack over many options.** If decision fatigue is your enemy, Eden Stack eliminates it. ## Conclusion SupaStarter and Eden Stack are both serious tools built by developers who care about the craft. They solve the same core problem, but they solve it for different people. **Choose SupaStarter** if you need flexibility: multiple frameworks, multiple payment providers, multi-tenancy, i18n, and the freedom to self-host. It's a mature product with a broad feature set and a proven track record. **Choose Eden Stack** if you need depth: end-to-end type safety, AI-native development with 40+ Claude skills, built-in observability, and a single opinionated stack that eliminates decision fatigue. At $99, it's also the most affordable way to start. The honest truth is that both kits will get you to launch faster than building from scratch. Pick the one that matches how you work, and go build something. --- ### Wasp vs Eden Stack: Framework or Template? *Published: 2026-04-03* Comparing an open-source full-stack framework with a production-ready code template # Wasp vs Eden Stack: Framework or Template? Wasp is one of the most interesting projects in the JavaScript ecosystem right now. It has 18,000+ GitHub stars, a YC pedigree, an active Discord community of 4,000+ developers, and a genuinely novel approach to full-stack development. If you're evaluating tools for your next SaaS project, you've probably come across it. Eden Stack takes a fundamentally different approach to the same problem. This post breaks down what those differences actually mean for you as a builder. I built Eden Stack, so I'm biased. I'll be upfront about that while trying to give Wasp the credit it deserves. ## Two Philosophies, One Goal Both Wasp and Eden Stack want to help you ship a production-ready web application faster. They just disagree on *how*. ### Wasp: The Framework Wasp calls itself "a Rails-like framework for React, Node.js, and Prisma." It uses a custom DSL (domain-specific language) in a `.wasp` configuration file to describe your application's structure: routes, pages, auth, database models, server operations, and background jobs. The Wasp compiler then generates a complete React + Node.js + Prisma codebase from that configuration. Here's what a Wasp file looks like: ```wasp app myApp { wapisp: "^0.22.0", title: "My SaaS", auth: { userEntity: User, methods: { email: {} } } } route DashboardRoute { path: "/dashboard", to: DashboardPage } page DashboardPage { authRequired: true, component: import Dashboard from "@src/pages/Dashboard" } job emailDigest { executor: PgBoss, perform: { fn: import { sendDigest } from "@src/jobs/emailDigest" }, schedule: { cron: "0 8 * * *" } } ``` A few lines of DSL, and Wasp handles auth, routing, and job scheduling. That's genuinely powerful. ### Eden Stack: The Template Eden Stack gives you the full source code for a production-ready application built on TanStack Start, Elysia, Drizzle, and Neon. There's no DSL, no compiler, no framework layer between you and your code. You get a working application with 60+ primitives across auth, payments, email, background jobs, analytics, and error tracking, all wired together and ready to customize. The tradeoff is explicit: instead of abstracting complexity behind a DSL, Eden Stack exposes it as readable, modifiable code paired with 40+ Claude skills that help you understand and reshape it. ## Where Wasp Genuinely Shines I want to be honest about Wasp's strengths, because they're real. **It's free and open-source.** Wasp itself is MIT-licensed. Their SaaS starter, Open SaaS, is also completely free. For developers on a tight budget, this is a legitimate advantage. You can go from zero to a deployed SaaS without spending a dollar on tooling. **The DSL reduces boilerplate significantly.** Wasp claims their codebases are roughly 40% smaller than equivalent Next.js applications. I believe it. When auth, routing, and jobs are declarative config rather than imperative code, there's simply less to write. This also makes the codebase more legible for AI coding tools, which is a smart bet for the future. **Rapid prototyping is excellent.** Their AI tool, Mage, can generate a complete Wasp application from a natural language description. It's been used to scaffold over 30,000 apps. If you need to validate an idea in an afternoon, this workflow is hard to beat. **The community is strong.** 18,000+ stars, 4,000+ Discord members, active blog, regular launches. Wasp has built real momentum and a genuine developer community around the project. **Ejection is possible.** If you outgrow the framework, you can run `wasp build` and get the generated code. It's human-readable, and you can continue development without Wasp from that point. ## Where the Approaches Diverge ### Source Ownership This is the core tension, and it's worth sitting with. When you use Wasp, your application logic lives in two places: the `.wasp` configuration file and your TypeScript source files. The actual running application is generated by the compiler. You can inspect the generated code in `.wasp/out/`, and you can eject, but during active development, you're working through the abstraction layer. When you use Eden Stack, there is no abstraction layer. The code in your repository *is* the application. If you want to change how auth works, you edit the auth module. If you want to restructure the API, you restructure the API. There's no compiler between your intention and the running code. This matters most when you hit edge cases. Every framework eventually meets a requirement it wasn't designed for. With a template, you modify the code. With a framework, you work within its constraints or eject. ### Stack Choices | Layer | Wasp | Eden Stack | |-------|------|------------| | **Frontend** | React | React (TanStack Start) | | **Backend** | Node.js + Express | Bun + Elysia | | **ORM** | Prisma | Drizzle | | **Database** | PostgreSQL (any) | Neon PostgreSQL | | **Type Safety** | RPC (generated) | Eden Treaty (inferred) | | **Auth** | Built-in (framework) | Better Auth | | **Payments** | Stripe / Polar.sh | Stripe | | **Background Jobs** | PgBoss (built-in) | Inngest | | **Email** | Built-in | Resend + React Email | | **Analytics** | Plausible / Google | PostHog | | **Error Tracking** | Not included | Sentry | Wasp is locked into React + Node.js + Prisma for now. They've talked about supporting alternative stacks in the future, but the current version only generates code for that specific combination. If you prefer a different stack, you're out of luck. Eden Stack uses TanStack Start and Elysia, which are newer and less battle-tested than Express, but they offer significant advantages: Bun-native performance, end-to-end type inference through Eden Treaty (no code generation), and a modern API design that plays well with edge deployments. ### AI-Native Development Both projects take AI seriously, but in different ways. Wasp's approach is to make the codebase smaller and more declarative so AI tools can understand it more easily. Their 40% reduction in code size is a real advantage for AI context windows. Mage generates full applications from prompts. Open SaaS includes an AGENTS.md file and Claude Code plugin for AI-assisted development. Eden Stack's approach is to pair the full codebase with deep institutional knowledge encoded in 40+ Claude skills. These skills aren't just documentation. They're structured prompts that teach Claude how to implement features using the specific patterns in your codebase: how to add a new API route with Elysia, how to create a Drizzle migration, how to wire up a Stripe webhook through Inngest. The AI doesn't just understand the code; it understands the architecture. The difference: Wasp makes the code easier for AI to read. Eden Stack makes the architecture easier for AI to reason about and extend. ### Deployment and Infrastructure Wasp offers built-in deployment support for Fly.io and Railway through `wasp deploy`. You can also deploy anywhere by running `wasp build` and deploying the generated output yourself. Eden Stack deploys to Vercel with zero configuration. The TanStack Start + Nitro setup handles SSR, API routes, and static assets out of the box. If you prefer a different platform, the standard Node.js output works anywhere. ### Production Readiness Wasp provides the essential SaaS features: auth, payments, email, background jobs, file uploads, and a landing page. That's a solid foundation. Eden Stack goes further with production infrastructure: Sentry error tracking with source maps, PostHog analytics with feature flags, Inngest for durable background workflows with retries, and React Email templates for transactional emails. These aren't just integrations listed on a feature page. They're wired together in patterns that handle real production scenarios, like processing a Stripe webhook through Inngest so it retries on failure, then sending a confirmation email, then tracking the conversion in PostHog. ## When to Choose Wasp Wasp is the right choice if: 1. **Budget is your primary constraint.** Wasp and Open SaaS are completely free. If you're a student, hobbyist, or early-stage founder watching every dollar, this is significant. 2. **You want the smallest possible codebase.** The DSL approach genuinely reduces the amount of code you need to write and maintain. Less code means fewer bugs. 3. **You prefer convention over configuration.** If you like how Rails or Laravel work, where the framework makes decisions for you, Wasp's opinionated approach will feel natural. 4. **You need to validate an idea fast.** Mage can generate a working app from a description. Combined with the free pricing, you can go from idea to deployed prototype remarkably quickly. 5. **You're comfortable with React + Node.js + Prisma.** If that's already your preferred stack, Wasp adds a powerful abstraction layer on top of tools you already know. ## When to Choose Eden Stack Eden Stack is the right choice if: 1. **You want full source ownership from day one.** No DSL, no compiler, no framework layer. The code in your repo is the code that runs. You can read every line, modify any pattern, and swap any tool. 2. **You're building for production scale.** Sentry, PostHog, Inngest, and the integration patterns between them are designed for applications that need to be reliable, observable, and debuggable in production. 3. **You want a modern TypeScript stack.** TanStack Start, Elysia, Drizzle, and Bun represent the cutting edge of the TypeScript ecosystem. If you want to build on what's next rather than what's established, Eden Stack gets you there. 4. **You use AI agents to build features.** The 40+ Claude skills encode deep architectural knowledge that lets AI agents implement features correctly, not just generate code. This is a different level of AI-native development than "the codebase is small enough for AI to read." 5. **You need end-to-end type safety without code generation.** Eden Treaty infers types directly from your Elysia API definitions. Change a response type on the server, and TypeScript catches every affected client call instantly, with zero build steps. 6. **You want to customize everything.** Need to swap Neon for a self-hosted Postgres? Replace Better Auth with your own auth? Change the email provider? You edit the code. No waiting for framework support. ## The Honest Summary Wasp and Eden Stack solve the same problem from opposite directions. Wasp says: "Full-stack web development has too much boilerplate. Let us abstract it away with a smart compiler so you can focus on your business logic." Eden Stack says: "Full-stack web development has too much boilerplate. Here's a production-ready codebase with everything wired up, plus AI skills that help you understand and reshape it." If you value abstraction, community, and free tooling, Wasp is excellent. If you value source ownership, production infrastructure, and AI-native architecture, Eden Stack is built for you. Both are legitimate choices. Pick the one that matches how you think about building software. --- ### Multi-Platform Authentication with Better Auth and Expo *Published: 2025-01-25* Implementing shared authentication across web and mobile with Better Auth, handling cookies, secure storage, and OAuth flows # Multi-Platform Authentication with Better Auth and Expo Building authentication that works across web and mobile is tricky. Cookies behave differently, storage APIs vary, OAuth callbacks need different handling, and you want to avoid duplicating your auth logic. Eden Stack solves this with **Better Auth** + **Expo client plugin**. One auth configuration, two platforms, zero code duplication. ## The Challenge Web and mobile have fundamentally different auth primitives: | Aspect | Web | Mobile | |--------|-----|--------| | Session storage | Cookies (HTTP-only) | SecureStore | | OAuth callback | URL redirect | Deep link | | Origin | Known domains | Device-specific | | Token handling | Automatic (cookies) | Manual headers | Better Auth's Expo plugin bridges these differences. ## Server-Side Configuration The auth server handles both web and mobile clients from the same configuration: ```typescript // packages/auth/src/index.ts import { expo } from "@better-auth/expo"; import { db } from "@eden/db"; import * as schema from "@eden/db"; import { betterAuth, type BetterAuthPlugin } from "better-auth"; import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { emailOTP } from "better-auth/plugins"; // Fix for Expo's origin handling const expoOriginFix = (): BetterAuthPlugin => ({ id: "expo-origin-fix", onRequest: async (request) => { const expoOrigin = request.headers.get("expo-origin"); if (!expoOrigin) return; // Rewrite origin header for CORS const newHeaders = new Headers(request.headers); newHeaders.set("origin", expoOrigin); const newRequest = new Request(request.url, { method: request.method, headers: newHeaders, body: request.body, duplex: "half", } as RequestInit); return { request: newRequest }; }, }); export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "pg", usePlural: true, schema: { users: schema.users, sessions: schema.sessions, accounts: schema.accounts, verifications: schema.verifications, }, }), plugins: [ expoOriginFix(), expo({ disableOriginOverride: true }), emailOTP({ async sendVerificationOTP({ email, otp, type }) { await sendEmail({ to: email, subject: type === "sign-in" ? "Your login code" : "Verify your email", template: LoginCodeEmail({ otp, type }), }); }, otpLength: 6, expiresIn: 300, // 5 minutes }), ], // OAuth providers socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID ?? "", clientSecret: process.env.GOOGLE_CLIENT_SECRET ?? "", }, }, session: { expiresIn: 60 * 60 * 24 * 7, // 7 days updateAge: 60 * 60 * 24, // Refresh daily }, // Trust mobile deep link origins trustedOrigins: "production" === "development" ? (request) => { const origin = request?.headers.get("origin") ?? ""; const staticOrigins = [ "http://localhost:3000", "http://localhost:3001", "http://localhost:8081", "eden://", "exp://", ]; // Allow local network IPs for mobile dev const isDevOrigin = /^(http:\/\/(192\.168|10\.)\d+\.\d+:\d+|exp:\/\/|eden:\/\/)/.test(origin); if (isDevOrigin && origin) { return [...staticOrigins, origin]; } return staticOrigins; } : [process.env.BETTER_AUTH_URL ?? "http://localhost:3000"], account: { accountLinking: { enabled: true }, // Required for mobile OAuth - cookies don't persist in in-app browser skipStateCookieCheck: true, }, }); ``` Key points: 1. **`expo()` plugin**: Adds mobile-specific endpoints and session handling 2. **`expoOriginFix()`**: Rewrites `expo-origin` header to proper `origin` for CORS 3. **`trustedOrigins`**: Accepts deep link schemes (`eden://`, `exp://`) 4. **`skipStateCookieCheck`**: Bypasses OAuth state cookie for in-app browsers ## Mobile Client Setup The Expo client stores sessions in SecureStore instead of cookies: ```typescript // apps/mobile/src/lib/auth.ts import { createAuthClient } from "better-auth/react"; import { expoClient } from "@better-auth/expo/client"; import { emailOTPClient } from "better-auth/client/plugins"; import * as SecureStore from "expo-secure-store"; const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3001"; export const authClient = createAuthClient({ baseURL: API_URL, plugins: [ expoClient({ scheme: "eden", // Your app's URL scheme storagePrefix: "eden", // Prefix for SecureStore keys storage: SecureStore, // Use Expo SecureStore }), emailOTPClient(), ], }); export const { signIn, signOut, useSession, getSession } = authClient; ``` The `expoClient` plugin: - Stores session tokens in encrypted SecureStore - Handles deep link OAuth callbacks - Attaches tokens to requests automatically ## API Client with Auth Headers For authenticated API calls, pass cookies from SecureStore: ```typescript // apps/mobile/src/lib/api.ts import { treaty } from "@elysiajs/eden"; import * as SecureStore from "expo-secure-store"; import type { App } from "@eden/api"; const API_URL = process.env.EXPO_PUBLIC_API_URL ?? "http://localhost:3001"; const COOKIE_KEY = "eden_cookie"; async function getAuthCookies(): Promise> { try { const cookiesJson = await SecureStore.getItemAsync(COOKIE_KEY); if (!cookiesJson) return {}; const cookiesObj = JSON.parse(cookiesJson); const cookieString = Object.entries(cookiesObj) .map(([name, cookie]: [string, any]) => `${name}=${cookie.value}`) .join("; "); return { Cookie: cookieString }; } catch { return {}; } } export const api = treaty(API_URL, { fetch: { credentials: "include", }, headers: async () => { return await getAuthCookies(); }, }); ``` ## Email OTP Flow The email OTP flow works identically on web and mobile: ```typescript // Mobile login screen import { authClient } from "../lib/auth"; function LoginScreen() { const [email, setEmail] = useState(""); const [code, setCode] = useState(""); const [step, setStep] = useState<"email" | "code">("email"); const requestCode = async () => { const result = await authClient.signIn.emailOtp({ email, callbackURL: "/", }); if (result.data?.success) { setStep("code"); } }; const verifyCode = async () => { const result = await authClient.signIn.emailOtp({ email, otp: code, }); if (result.data?.session) { // User is now logged in router.replace("/(tabs)/home"); } }; if (step === "email") { return ( ); } ``` ## Real-World Pattern: Shared API Client In Eden Stack, we structure the API client for sharing between web and mobile: ``` packages/ ├── api/ # Type export │ └── src/ │ └── index.ts # export type { App } apps/ ├── web/ │ └── src/lib/api.ts # Web client ├── mobile/ │ └── src/lib/api.ts # Mobile client ``` Both clients import the same type but configure differently: ```typescript // Web client export const api = treaty(import.meta.env.VITE_API_URL); // Mobile client with SecureStore cookies export const api = treaty(process.env.EXPO_PUBLIC_API_URL, { headers: async () => await getAuthCookies(), }); ``` ## Why This Beats the Alternatives | Feature | OpenAPI | GraphQL | tRPC | Eden Treaty | |---------|---------|---------|------|-------------| | Type generation | Required | Required | None | None | | Build step | Yes | Yes | No | No | | REST semantics | Yes | No | No | Yes | | Schema file | Yes | Yes | No | No | | Bundle size | Medium | Large | Small | Tiny | | Learning curve | Medium | High | Medium | Low | Eden Treaty gives you: - **REST semantics** — Standard HTTP methods, URLs, status codes - **Zero codegen** — Types flow through TypeScript's inference - **Tiny bundle** — Just a thin fetch wrapper - **Easy adoption** — If you know Elysia, you know Eden Treaty ## Common Gotchas ### 1. Type Updates Require TypeScript Restart When you change your API, your IDE might not immediately see the new types. Restart the TypeScript server: - VS Code: `Cmd+Shift+P` → "TypeScript: Restart TS Server" ### 2. Dynamic Route Segments Use bracket notation for dynamic segments: ```typescript // Route: /api/projects/:projectId/files/:fileId api.api.projects[projectId].files[fileId].get(); ``` ### 3. Query Parameters Pass query params as a second argument: ```typescript // Route: GET /api/projects?status=active&limit=10 api.api.projects.get({ query: { status: "active", limit: 10, }, }); ``` ## Wrapping Up Eden Treaty eliminates the entire category of "API type drift" bugs. Your backend defines the truth, and your clients automatically stay in sync—no generators, no schemas, no friction. The combination of Elysia + Eden Treaty is what makes Eden Stack's type safety actually *usable*, not just possible. Check out the [API Integration docs](/docs/api-integration) for more details on setting up your routes. --- ### Why Better Auth Over Lucia, Clerk, and Auth0 *Published: 2025-01-25* The case for owning your authentication while getting batteries-included features # Why Better Auth Over Lucia, Clerk, and Auth0 Authentication is the foundation of trust between your users and your application. Get it wrong, and nothing else matters. This makes the auth decision one of the most consequential choices in any stack. When choosing authentication for Eden Stack, I evaluated the spectrum: fully managed services (Clerk, Auth0), DIY libraries (Lucia), and the newer middle ground (Better Auth). Here's why Better Auth won — and why Eden Stack makes that choice even more compelling. ## The Authentication Spectrum Authentication solutions fall along a spectrum of control versus convenience: ``` DIY Library Managed Service |------------------------|------------------------| Lucia Better Auth Clerk, Auth0 (Full control) (Best of both) (Zero config) ``` Each position has legitimate tradeoffs. Let's examine them. ## Clerk & Auth0: The Managed Convenience Clerk has become the darling of the indie hacker community. Auth0 remains the enterprise standard. Both offer genuine value: **What managed services do well:** - Zero configuration — authenticate users in minutes - Pre-built UI components that look professional - Handles security updates automatically - Organization/team management out of the box - Compliance certifications (SOC2, etc.) If you're validating an idea this weekend and authentication is purely a checkbox, Clerk's free tier gets you there fast. That's real value. ### The Vendor Lock-In Reality But here's what happens at scale: **Clerk Pricing (as of 2025):** - Free: 10,000 monthly active users - Pro: $0.02/MAU beyond free tier - At 100,000 MAU: ~$1,800/month - At 1,000,000 MAU: ~$18,000/month **Auth0 Pricing:** - Free: 25,000 MAU - Enterprise: Custom pricing (typically $20,000+/year) These aren't unreasonable prices for enterprise SaaS. But for a startup template meant to scale from zero to successful business, locking in five-figure annual auth costs felt wrong. More importantly: **your users aren't really yours.** User data lives in Clerk's infrastructure. Session management is their implementation. If you ever need to migrate, you're facing a significant engineering project. ## Lucia: The DIY Purist's Choice On the other end sits Lucia — a minimal, framework-agnostic auth library. It's excellent for what it is: session management primitives that give you full control. ```typescript // Lucia: Build everything yourself import { Lucia } from 'lucia'; const lucia = new Lucia(adapter); // You implement everything: OAuth, email verification, // password reset, organizations, 2FA... ``` **What Lucia does well:** - Complete control over your auth implementation - No vendor lock-in whatsoever - Minimal footprint, educational value - Framework agnostic **The reality:** Implementing production-ready auth with Lucia means building: - Email/password flows with secure hashing - OAuth integration for each provider - Email verification flows - Password reset flows - Session management and rotation - Two-factor authentication - Organization/workspace management - Invite flows - Role-based access control That's weeks of development before you ship a single feature. For a template meant to accelerate development, that defeats the purpose. ## Better Auth: The Middle Ground Better Auth occupies a unique position: **ownership with batteries included.** ```typescript // Better Auth: Full features, your database import { betterAuth } from 'better-auth'; import { drizzleAdapter } from 'better-auth/adapters/drizzle'; import { db } from './db'; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: 'pg' }), emailAndPassword: { enabled: true }, socialProviders: { google: { clientId: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, }, }, plugins: [ organization(), // Teams & workspaces twoFactor(), // 2FA support admin(), // Admin capabilities ], }); ``` Notice what's happening: **everything runs in your infrastructure, using your database.** No external API calls for session validation. No user data leaving your servers. Full control, with features that would take weeks to build. ### Organizations and Workspaces This is where Better Auth truly shines for SaaS applications. The organization plugin provides: ```typescript // Create an organization await auth.api.createOrganization({ body: { name: 'Acme Corp', slug: 'acme', }, headers, }); // Invite members await auth.api.createInvitation({ body: { organizationId: org.id, email: 'teammate@example.com', role: 'member', }, headers, }); // Role-based access await auth.api.updateMemberRole({ body: { organizationId: org.id, userId: member.id, role: 'admin', }, headers, }); ``` Building organization management from scratch is a multi-week project. Invitations, roles, permissions, member management — all the details that seem simple until you implement them. Better Auth handles this with a single plugin. ### The Type-Safe API Better Auth provides an RPC-like TypeScript client that feels modern: ```typescript import { createAuthClient } from 'better-auth/client'; const authClient = createAuthClient(); // Fully typed API const { data: session } = await authClient.session.get(); const { data: orgs } = await authClient.organization.list(); ``` Combined with Elysia's type inference, you get end-to-end type safety for your entire auth flow. ## The Eden Stack Advantage Here's the key insight: **Better Auth's value multiplies when combined with a well-configured template.** Eden Stack provides: 1. **Pre-built UI components** — Login, register, password reset, organization management — all styled with your theme 2. **Database schema ready** — Drizzle migrations for all auth tables 3. **API integration complete** — Elysia routes mounted and configured 4. **Mobile support** — Expo auth flows that just work The main reason to reach for Clerk — "it comes with UI" — disappears when Eden Stack provides that UI with Better Auth underneath. ```typescript // Eden Stack: Pre-built auth pages // apps/web/src/routes/login.tsx — styled and ready // apps/web/src/routes/register.tsx — with validation // apps/web/src/routes/onboarding.tsx — organization setup // apps/mobile/app/(auth)/login.tsx — native mobile ``` You get Clerk's convenience with Better Auth's ownership. ## When to Choose What **Choose Clerk or Auth0 when:** - You're validating an idea and speed is everything - Enterprise compliance requirements demand their certifications - Your budget comfortably absorbs their pricing at scale - You genuinely don't want to think about auth ever **Choose Lucia when:** - You have specific requirements that don't fit standard patterns - Educational purposes — learning how auth really works - Very minimal applications where batteries-included is overkill **Choose Better Auth when:** - You want production-ready features without vendor lock-in - Organization/workspace management is needed - You're building a SaaS that needs to scale cost-effectively - You value owning your user data and auth infrastructure ## Why Eden Stack Uses Better Auth For a template designed to help developers build real SaaS businesses, the calculus was clear: 1. **No vendor lock-in** — Your users, your data, your infrastructure 2. **Batteries included** — Organizations, 2FA, OAuth all work out of the box 3. **Cost effective** — No per-user fees as you scale 4. **Type-safe** — Excellent TypeScript support that fits our philosophy 5. **UI included** — Eden Stack provides the components Clerk sells you Better Auth recently raised $5M from Peak XV and YC — validation that this approach resonates. The library is actively maintained, well-documented, and growing rapidly. Combined with the pre-built UI and configurations in Eden Stack, you get managed-service convenience with self-hosted freedom. That's the foundation every SaaS deserves. --- *This post reflects my opinions after building production applications with various authentication solutions. Clerk and Auth0 are excellent products — this isn't about them being bad, but about Better Auth being a better fit for Eden Stack's goals.* --- ### Why Bun Over Node.js *Published: 2026-04-03* The case for using Bun as your JavaScript runtime and package manager in production # Why Bun Over Node.js Node.js made server-side JavaScript possible. Before Node, the idea of running JavaScript outside the browser was a curiosity. Ryan Dahl changed that in 2009, and the ripple effects shaped the entire software industry. npm became the largest package registry in the world. Companies built their backends, their tooling, their entire platforms on Node. Without Node.js, the modern JavaScript ecosystem simply would not exist. But when I was choosing a runtime and package manager for Eden Stack, I chose Bun. Here's why. ## Speed That Actually Matters Let's start with the numbers, because they're hard to ignore. Bun launches in 8-15ms. Node.js takes 60-120ms. That's roughly a 6x difference in cold start time. For a single script invocation, you might not notice. But when you're running dev servers, executing test suites, or iterating through build steps dozens of times per day, those milliseconds compound into minutes. On HTTP throughput benchmarks, Bun handles around 52,000 requests per second compared to Node.js at 14,000. That's nearly 4x. Now, I should be honest here: these numbers come from synthetic benchmarks. Real-world applications with database queries, business logic, and network calls narrow the gap significantly. In production workloads, both runtimes deliver roughly similar throughput because the bottleneck is I/O, not the runtime itself. The speed you _feel_ as a developer, though, is real. Scripts start faster. Tests run faster. The feedback loop tightens. That's what matters day to day. ## Native TypeScript Execution This is the feature that sold me. With Node.js, running TypeScript has historically meant one of several things: a compile step with `tsc`, a wrapper like `ts-node`, or configuring a bundler. Node.js 22 introduced `--strip-types` for basic TypeScript support, but it strips types without full transformation support for features like enums and decorators. Bun runs `.ts`, `.tsx`, and `.jsx` files natively. No configuration. No extra tooling. No build step for development. You write TypeScript, you run it with `bun run`, and it works. ```bash # Node.js (traditional) npx tsc && node dist/index.js # Node.js 22 (experimental) node --strip-types index.ts # Bun bun run index.ts ``` For a stack like Eden that's TypeScript end-to-end, from Drizzle schemas to Elysia API routes to TanStack Start components, removing the compilation step from the development loop is a meaningful improvement. ## Bun as a Package Manager Bun isn't just a runtime. It's also a package manager, and a fast one. Installing a 50-dependency project takes Bun about 0.8 seconds. The same install takes npm roughly 14 seconds and pnpm around 4 seconds. For larger dependency trees, the gap widens further. A project with 800+ dependencies that takes npm over two minutes finishes in under five seconds with Bun. Why the difference? Bun is written in Zig, a compiled systems language. It makes roughly 165,000 system calls during a typical install compared to npm's 1,000,000+. It uses a global cache with hard links, so packages downloaded once are available instantly across all your projects. In CI pipelines, this adds up. A team running 50 pipeline runs per day can save over eight hours of compute time per month just from faster installs. That's real money and real developer time waiting for green checks. Bun's lockfile (`bun.lock`) also deserves mention. Since Bun 1.2, it defaults to a human-readable text format that plays nicely with code review and git diffs, while still parsing faster than JSON or YAML alternatives. ## The Compatibility Story Here's where I need to be straightforward, because this is Bun's biggest weakness. Bun achieves roughly 95% npm package compatibility. That sounds high, and for most projects it is. The standard libraries work. Express works. Most ORMs work. Popular tools like Drizzle, Elysia, and TanStack all run on Bun without issues. But that remaining 5% can bite you. The pain points: - **Native addons**: Packages that rely on `node-gyp` and N-API bindings sometimes fail. Popular native modules like `bcrypt`, `sharp`, and `better-sqlite3` work, but obscure or outdated native dependencies can break. - **Node.js internals**: Packages depending on V8-specific behavior, exact error message formats, or undocumented Node.js APIs may behave differently. Bun uses JavaScriptCore (Safari's engine) under the hood, not V8. - **Edge cases in core modules**: Some patterns in `vm`, `worker_threads`, `cluster`, and `child_process` behave differently or are only partially implemented. - **Docker workflows**: The official Node.js Docker images don't include Bun. You'll need Bun's official images or an extra install step in your Dockerfile. The Bun team is closing these gaps aggressively. Bun 1.2 was the biggest compatibility release yet, improving Windows support and `node:cluster`. But if your project depends on a specific native module without a pure JavaScript alternative, test carefully before committing. ## The Community Factor Node.js has been around since 2009. When something goes wrong, you'll find a Stack Overflow answer, a blog post, or a GitHub issue with a workaround. The debugging knowledge base is enormous. Bun's community is growing quickly but it's still younger. When you hit an edge case, you might be the first person to encounter it. The documentation is good and improving, but you won't always find someone who's solved your exact problem before. For teams comfortable reading source code and filing issues upstream, this is manageable. For teams that rely heavily on community-sourced solutions, it's a real consideration. ## When Node.js Still Makes Sense I'm not here to say Node.js is obsolete. It's the right choice in several scenarios: - **Mature production systems**: If you have a Node.js application running reliably in production, migrating to Bun for speed alone rarely justifies the risk. - **Heavy native module usage**: Projects depending on `canvas`, specialized image processing, or other packages where `node-gyp` is non-negotiable should stay on Node. - **Team familiarity**: Switching runtimes has real onboarding costs. If your team knows Node.js deeply and doesn't have pain points, the migration may not be worth it. - **Serverless edge cases**: Some benchmarks show Bun with longer cold starts than Node.js in specific serverless environments like AWS Lambda. If you're optimizing for serverless cold starts, benchmark your own workload before deciding. - **Enterprise compliance**: Some organizations require runtimes with specific certifications or long-term support guarantees. Node.js has a well-established LTS cycle. Bun doesn't yet. ## Why Eden Stack Uses Bun For a modern TypeScript starter kit, the calculus was clear: 1. **Developer experience**: Native TypeScript execution, faster startup, tighter feedback loops. 2. **Install speed**: Seconds instead of minutes, both locally and in CI. 3. **Unified tooling**: One tool for runtime, package management, and script execution. No separate `npm`, `npx`, or `ts-node` to manage. 4. **Ecosystem fit**: Every major dependency in Eden Stack (TanStack Start, Elysia, Drizzle, Better Auth, Stripe, Inngest) runs on Bun without issues. 5. **Forward momentum**: Bun's compatibility improves with every release, while its performance advantages remain structural. The honest truth is that for most web applications, the runtime choice matters less than people think. Both Node.js and Bun will serve your HTTP requests. Both will connect to your database. Both will run your business logic. The difference is in the developer experience around those tasks: how fast your tools respond, how little configuration you need, how tight your iteration loop feels. For Eden Stack, Bun makes that experience better. And for developers starting new TypeScript projects in 2026, I think it's the right default. --- *This post reflects my opinions after building production applications with both runtimes. Your mileage may vary, and technology decisions should be based on your specific requirements.* --- ### Why Drizzle Over Prisma *Published: 2025-01-25* The case for SQL-aware, TypeScript-first database access in modern applications # Why Drizzle Over Prisma The TypeScript ORM landscape has a clear incumbent: Prisma. With its schema-first approach and excellent developer experience, Prisma shaped how a generation of developers think about database access. But a challenger has emerged. Drizzle ORM takes a fundamentally different approach — and for Eden Stack, that approach won. Here's why. ## Two Philosophies of Database Access Prisma and Drizzle represent two distinct philosophies: **Prisma's philosophy:** "Developers shouldn't need to think in SQL. Give them a high-level abstraction, and we'll generate the optimal queries." **Drizzle's philosophy:** "If you know SQL, you know Drizzle. Stay close to the metal, with TypeScript safety on top." Neither philosophy is wrong. They optimize for different priorities. ## Prisma: The Abstraction Layer Prisma has earned its popularity. The developer experience is genuinely excellent: ```typescript // Prisma: Schema-first, abstracted queries // schema.prisma model User { id String @id @default(uuid()) email String @unique posts Post[] } model Post { id String @id @default(uuid()) title String author User @relation(fields: [authorId], references: [id]) authorId String } // Query const usersWithPosts = await prisma.user.findMany({ include: { posts: true }, }); ``` **What Prisma does well:** - Exceptional developer experience for common patterns - Schema-first design with automatic migrations - Powerful Prisma Studio for visual database exploration - Large ecosystem and community - Great documentation If you're building a straightforward CRUD application and want maximum abstraction from SQL, Prisma delivers. ### Where Prisma Struggles But Prisma's abstraction comes with costs: **1. Bundle Size and Cold Starts** Prisma requires a runtime query engine — a compiled binary that adds significant weight: | Metric | Prisma | Drizzle | |--------|--------|---------| | Bundle size | ~9MB+ | ~7.4KB | | Cold start impact | Significant | Negligible | | Dependencies | External binary | Zero runtime deps | For serverless deployments where cold starts matter, this difference is substantial. Every Lambda invocation, every edge function, every Cloudflare Worker pays this tax. **2. The N+1 Query Problem** Prisma's `include` syntax is convenient but can hide performance issues: ```typescript // This looks innocent const users = await prisma.user.findMany({ include: { posts: { include: { comments: true } } }, }); // But may generate multiple queries under the hood ``` Prisma has improved here, but the abstraction can make it harder to reason about what's actually hitting your database. **3. Code Generation Dependency** Prisma requires a generate step. Change your schema, run `prisma generate`, wait for codegen. It works, but it's friction — and it means your types exist in a generated file, not in your source code. ## Drizzle: SQL With Type Safety Drizzle takes the opposite approach: your schema IS TypeScript, your queries look like SQL, and there's no abstraction hiding what happens. ```typescript // Drizzle: TypeScript-first, SQL-aware import { pgTable, uuid, varchar, text } from 'drizzle-orm/pg-core'; export const users = pgTable('users', { id: uuid('id').defaultRandom().primaryKey(), email: varchar('email', { length: 255 }).unique().notNull(), }); export const posts = pgTable('posts', { id: uuid('id').defaultRandom().primaryKey(), title: varchar('title', { length: 255 }).notNull(), authorId: uuid('author_id').references(() => users.id).notNull(), }); // Query — looks like SQL, fully typed const usersWithPosts = await db .select() .from(users) .leftJoin(posts, eq(posts.authorId, users.id)); ``` ### Why "If You Know SQL, You Know Drizzle" Matters Here's the key insight: **SQL is a feature, not a bug.** SQL has been refined for 50 years. It's declarative, powerful, and universally understood. When you write a Drizzle query, you can predict exactly what SQL it generates — because the syntax maps directly. ```typescript // What you write const result = await db .select({ userName: users.name, postCount: count(posts.id), }) .from(users) .leftJoin(posts, eq(posts.authorId, users.id)) .groupBy(users.id) .having(gt(count(posts.id), 5)); // What runs (predictable) // SELECT users.name, COUNT(posts.id) // FROM users // LEFT JOIN posts ON posts.author_id = users.id // GROUP BY users.id // HAVING COUNT(posts.id) > 5 ``` For developers who know SQL, this is liberating. No guessing what the ORM will generate. No wondering why a query is slow. The translation is transparent. ### Performance Where It Counts Benchmarks consistently show Drizzle outperforming Prisma, especially in scenarios that matter for modern apps: | Benchmark | Drizzle | Prisma | |-----------|---------|--------| | Simple select | ~2-3x faster | Baseline | | Complex joins | ~2-4x faster | Baseline | | Cold start | ~10x faster | Baseline | | Bundle size | 7.4KB | ~9MB | The cold start advantage is particularly relevant for: - **Serverless functions** — Every Lambda, Vercel function, or edge handler benefits - **Edge deployments** — Cloudflare Workers, Deno Deploy, etc. - **Microservices** — Fast container startup times ### Type Safety Without Code Generation Drizzle's type inference works at compile time, without generating files: ```typescript // Your schema defines the types export const users = pgTable('users', { id: uuid('id').defaultRandom().primaryKey(), email: varchar('email', { length: 255 }).notNull(), role: varchar('role', { length: 50 }).$type<'admin' | 'user'>(), }); // Types are inferred type User = typeof users.$inferSelect; // { id: string; email: string; role: 'admin' | 'user' | null } type NewUser = typeof users.$inferInsert; // { id?: string; email: string; role?: 'admin' | 'user' | null } ``` No `prisma generate`. No watching for schema changes. Your TypeScript just works. ### Relational Queries When You Want Them Drizzle also offers a higher-level Queries API for when you want Prisma-style convenience: ```typescript // Drizzle Queries API — more abstract when needed const usersWithPosts = await db.query.users.findMany({ with: { posts: { with: { comments: true }, }, }, }); ``` Best of both worlds: SQL-like precision when you need control, relational convenience when you don't. ## The Provider-Agnostic Advantage Here's something often overlooked: **Drizzle makes your database choice a configuration detail.** ```typescript // Switch from Neon to local Postgres to AWS RDS // by changing one line import { drizzle } from 'drizzle-orm/neon-http'; // or import { drizzle } from 'drizzle-orm/postgres-js'; // or import { drizzle } from 'drizzle-orm/node-postgres'; ``` Your schema stays the same. Your queries stay the same. The infrastructure is abstracted at the driver level, not the query level. This matters when: - You want local Docker development with Neon production - You might migrate to a different PostgreSQL host - You need different drivers for different deployment targets ## When to Choose What **Choose Prisma when:** - Your team prefers maximum abstraction from SQL - You're building straightforward CRUD applications - Prisma Studio is valuable for your workflow - Bundle size and cold starts aren't concerns - You like schema-first development with separate files **Choose Drizzle when:** - You're comfortable with SQL and want that control - Serverless/edge performance matters - You prefer schema-as-code in TypeScript - You want minimal bundle size - Provider flexibility is important ## Why Eden Stack Uses Drizzle For a template designed around TypeScript excellence and deployment flexibility, Drizzle was the clear choice: 1. **TypeScript-native** — Schema defined in TypeScript, types inferred automatically 2. **Performance** — Fast queries, tiny bundle, serverless-optimized 3. **SQL transparency** — Know exactly what's hitting your database 4. **Provider flexibility** — Works with Neon, local Postgres, or any PostgreSQL host 5. **Modern approach** — Built for the serverless era, not adapted to it Combined with Neon for serverless PostgreSQL, Drizzle provides the database layer Eden Stack needs: type-safe, performant, and infinitely flexible. The result is a stack where your database access is as transparent as your API types — you always know what's happening, and TypeScript has your back. --- *This post reflects my opinions after building with both Prisma and Drizzle in production. Prisma is an excellent tool that has served the community well — this isn't about Prisma being bad, but about Drizzle being a better fit for Eden Stack's goals.* --- ### Why Elysia Over Express and Hono *Published: 2025-01-25* The case for Elysia as your TypeScript backend framework, and how Eden Treaty changes everything # Why Elysia Over Express and Hono When choosing a backend framework for Eden Stack, I evaluated the major TypeScript options: Express, Fastify, Hono, and Elysia. Each has its strengths, but Elysia won decisively. Here's why. ## The State of Express in 2025 Let's address the elephant in the room: **Express isn't dead.** After a decade in development, Express v5 finally shipped in October 2024, and v6 is actively being developed. The OpenJS Foundation has revitalized governance with a proper Technical Committee, and the project is moving again. But "not dead" isn't the same as "the right choice." Express is 15 years old. It was designed for a JavaScript world that no longer exists — before TypeScript became the standard, before async/await, before edge runtimes, before we expected type safety across the stack. You can make Express work with TypeScript, but it's bolted on, not baked in. The middleware model that made Express revolutionary in 2010 now feels dated. Request and response types are loose. Error handling is awkward. And while the community is massive, much of that accumulated knowledge is about working around limitations rather than building on strengths. Express is still fine for quick prototypes or maintaining legacy applications. But for a new production stack in 2025? There are better options. ## Hono: The Multi-Runtime Champion Hono deserves serious consideration. It's fast, lightweight, and runs everywhere — Cloudflare Workers, Deno, Bun, Node.js, AWS Lambda. If multi-runtime deployment is your primary concern, Hono is excellent. Built on Web Standards (WinterCG compliant), Hono feels modern. The API is clean, middleware is composable, and performance is outstanding. It even has RPC capabilities for type-safe client-server communication. So why not Hono? ## Elysia: End-to-End Type Safety Without Code Generation Here's where Elysia pulls ahead: **Eden Treaty.** Eden Treaty provides end-to-end type safety between your backend and frontend *without code generation*. You define your API in Elysia, and the types flow automatically to your client. Change a response shape on the server, and TypeScript immediately catches the mismatch on the client. ```typescript // Backend (Elysia) const app = new Elysia() .get('/users/:id', ({ params }) => { return { id: params.id, name: 'Alice', email: 'alice@example.com' } }) export type App = typeof app // Frontend (anywhere) import { treaty } from '@elysiajs/eden' import type { App } from './api' const api = treaty('localhost:3000') const { data } = await api.users({ id: '123' }).get() // data is typed as { id: string, name: string, email: string } ``` This is similar to tRPC, but for REST-like APIs. No code generation step. No schema files to keep in sync. Just TypeScript inference doing what it does best. Hono has RPC capabilities too, but Eden Treaty's type inference is deeper. It handles path parameters, query strings, request bodies, and response types with a level of precision that makes full-stack TypeScript development genuinely pleasant. ## The Developer Experience Gap Elysia was designed around developer experience from day one. The documentation calls it an "ergonomic web framework," and that's not marketing fluff — it's a design philosophy. **Validation is built-in:** ```typescript const app = new Elysia() .post('/users', ({ body }) => createUser(body), { body: t.Object({ name: t.String(), email: t.String({ format: 'email' }) }) }) ``` The schema validates at runtime and provides TypeScript types at compile time. One definition, two purposes. Hono can do this with Zod middleware, but it's an addition rather than a core feature. **Lifecycle hooks are intuitive:** ```typescript const app = new Elysia() .onBeforeHandle(({ headers }) => { if (!headers.authorization) { return new Response('Unauthorized', { status: 401 }) } }) .get('/protected', () => 'secret data') ``` **Plugin composition is elegant:** ```typescript const authPlugin = new Elysia() .derive(({ headers }) => ({ user: validateToken(headers.authorization) })) const app = new Elysia() .use(authPlugin) .get('/me', ({ user }) => user) // user is typed! ``` ## Performance: Both Are Fast Let's be honest: for most applications, both Elysia and Hono are fast enough that performance isn't the deciding factor. Benchmarks show them trading leads depending on the specific test case, but both dramatically outperform Express. Elysia was originally built specifically for Bun, taking advantage of Bun-native optimizations. It now also supports Node.js and Cloudflare Workers, though Bun remains its sweet spot. Hono was originally built for Cloudflare Workers and has broader multi-runtime parity. If you're deploying to Cloudflare Workers and need every microsecond, Hono might edge ahead. If you're running Bun, Elysia has the home-field advantage. For most real-world applications, both are "fast enough" and the choice should be made on other criteria. ## When to Choose What **Choose Express when:** - You're maintaining a legacy codebase - Your team knows Express deeply and switching isn't worth the cost - You need a specific Express middleware that has no equivalent **Choose Hono when:** - Multi-runtime deployment is critical (especially Cloudflare Workers) - You want the lightest possible footprint - You're building serverless functions that need to cold-start fast **Choose Elysia when:** - End-to-end type safety is a priority - You're using Bun (or plan to) - Developer experience matters more than ecosystem size - You want validation, OpenAPI docs, and type inference built-in ## Why Eden Stack Uses Elysia For a full-stack TypeScript template, the choice was clear. Eden Stack is about type safety from database to UI, and Eden Treaty makes that vision real for the API layer. Combined with TanStack Start on the frontend, you get: 1. Type-safe database queries (Drizzle) 2. Type-safe API definitions (Elysia) 3. Type-safe API calls (Eden Treaty) 4. Type-safe routing and data loading (TanStack Router) No code generation. No runtime type checking overhead. Just TypeScript doing what TypeScript does best. The Elysia + Eden Treaty combination isn't just a technical choice — it's a statement about how modern full-stack development should work. Types should flow. Changes should propagate. The compiler should catch mistakes before users do. That's why Eden Stack uses Elysia. --- *This post reflects my opinions after evaluating and building with multiple backend frameworks. Your requirements may differ, and that's okay — there's no single "best" framework for every situation.* --- ### Why Inngest Over BullMQ and Trigger.dev *Published: 2025-01-25* The case for durable execution and AI-native background jobs in modern full-stack applications # Why Inngest Over BullMQ and Trigger.dev Background jobs are one of those infrastructure decisions that don't feel urgent until they become critical. You need to send emails, process payments, run AI pipelines, sync data — and suddenly you're debugging Redis connection issues at 2 AM. When choosing a background job solution for Eden Stack, I evaluated the major options: BullMQ (the Redis workhorse), Trigger.dev (the modern challenger), and Inngest (the durable execution platform). Here's why Inngest won. ## The State of Background Jobs in 2025 Let's set the stage. Most developers reach for one of three approaches: 1. **Roll your own** — setTimeout, cron jobs, or a basic queue 2. **Redis-based queues** — BullMQ, Bull, Bee-Queue 3. **Managed platforms** — Inngest, Trigger.dev, Temporal The first option is fine until your server restarts mid-job. The second works but requires infrastructure management. The third abstracts away the pain — but each platform has a different philosophy. ## BullMQ: The Reliable Workhorse BullMQ deserves respect. With 7,400+ GitHub stars and 1.5 million weekly downloads, it's battle-tested. If you know Redis, you know BullMQ. ```typescript // BullMQ: Traditional queue pattern import { Queue, Worker } from 'bullmq'; const queue = new Queue('email'); // Producer await queue.add('send-welcome', { userId: '123' }); // Worker (separate process) const worker = new Worker('email', async (job) => { await sendEmail(job.data.userId); }); ``` **What BullMQ does well:** - Rock-solid reliability on proven Redis infrastructure - Fine-grained control over job priorities, delays, and retries - Massive ecosystem and community knowledge - Self-hostable with full control **But here's the catch:** You're managing infrastructure. Redis needs to be provisioned, monitored, and scaled. Workers need to run somewhere. Connection pooling needs configuration. When your job fails at step 3 of 5, you're writing custom retry logic. For Eden Stack's goals — helping developers ship production apps fast — asking them to set up Redis infrastructure felt like adding friction, not removing it. ## Trigger.dev: The Modern Approach Trigger.dev has gained serious momentum (13,300+ GitHub stars). Their pitch is compelling: background jobs that feel like writing normal TypeScript functions. ```typescript // Trigger.dev: Task-based approach import { task } from '@trigger.dev/sdk/v3'; export const sendWelcomeEmail = task({ id: 'send-welcome-email', run: async (payload: { userId: string }) => { await sendEmail(payload.userId); return { sent: true }; }, }); ``` **What Trigger.dev does well:** - Clean developer experience - Self-hostable with a cloud option - Good TypeScript support - Active development and community Trigger.dev is genuinely good. If Eden Stack were optimized for a different use case, it might have won. ## Inngest: Durable Execution for AI-Native Apps Here's where Inngest diverges — and why it won for Eden Stack. Inngest isn't just a job queue. It's a **durable execution engine**. The difference matters when you're building workflows that must survive failures, coordinate across services, or handle long-running AI operations. ```typescript // Inngest: Durable execution with steps import { inngest } from './client'; export const onboardUser = inngest.createFunction( { id: 'onboard-user' }, { event: 'user/created' }, async ({ event, step }) => { // Each step is automatically retried and checkpointed const user = await step.run('create-profile', async () => { return await createUserProfile(event.data.userId); }); await step.run('send-welcome-email', async () => { await sendWelcomeEmail(user.email); }); // Wait for external event (e.g., email verification) const verified = await step.waitForEvent('user/email-verified', { timeout: '24h', match: 'data.userId', }); if (verified) { await step.run('activate-trial', async () => { await activateTrial(user.id); }); } } ); ``` Notice what's different: **steps are individually checkpointed**. If `send-welcome-email` fails, Inngest retries *that step* — not the entire function. The state from `create-profile` is preserved. No Redis. No worker processes. No custom retry logic. ### Why Durable Execution Matters In traditional queues, a 5-step workflow that fails on step 4 either: - Retries from the beginning (wasteful, potentially dangerous) - Requires you to manually track progress (complex) - Leaves partial state that needs cleanup (messy) Inngest handles this automatically. Each `step.run()` is atomic, retriable, and checkpointed. This is especially critical for: 1. **AI workflows** — LLM calls are expensive and slow. Re-running an entire AI pipeline because step 3 timed out is wasteful. 2. **Payment processing** — You cannot afford to charge a customer twice because a webhook handler crashed. 3. **Multi-service orchestration** — When coordinating across APIs, partial failures are the norm. ### AI-Native by Design Eden Stack is built for AI-native applications. Inngest's AgentKit takes this seriously: ```typescript // Inngest AgentKit: Durable AI agents import { Agent, agenticWorkflow } from '@inngest/agent-kit'; const researchAgent = new Agent({ name: 'Researcher', tools: [webSearch, documentFetch], model: anthropic('claude-sonnet-4-20250514'), }); export const researchWorkflow = agenticWorkflow({ agents: [researchAgent], maxIterations: 10, }); ``` AI agent loops are inherently long-running and failure-prone. Network timeouts, rate limits, model errors — all common. Inngest's durability means your agent can run for hours, surviving failures, with full observability into each step. ### Self-Hosting + Generous Cloud One of your concerns might be vendor lock-in. Inngest addresses this: - **Self-hostable**: Run the entire Inngest server on your own infrastructure - **Cloud with generous free tier**: 25,000 function runs/month free, then predictable pricing - **No infrastructure management**: Unlike BullMQ, you don't need to provision Redis For Eden Stack's use case — a template that should work for startups and scale with them — this flexibility is perfect. Start with the free cloud tier, self-host when you need to. ## When to Choose What **Choose BullMQ when:** - You already have Redis infrastructure and expertise - You need maximum control over queue behavior - You're building simple job queues without complex orchestration - Your team prefers managing their own infrastructure **Choose Trigger.dev when:** - You want a modern DX without durability requirements - You're building relatively simple background tasks - You prefer their specific approach to task definition **Choose Inngest when:** - You're building AI-powered applications with long-running workflows - Failure recovery and step-level retries are critical - You want durable execution without managing infrastructure - You need event-driven coordination across services ## Why Eden Stack Uses Inngest Eden Stack is designed for developers building production AI-native applications. The choice was clear: 1. **Durable execution** — AI workflows need step-level reliability 2. **Event-driven architecture** — Inngest's event system fits naturally with webhooks and service coordination 3. **Zero infrastructure** — No Redis to manage, no workers to deploy 4. **Self-hosting option** — No vendor lock-in when you need to scale Combined with the rest of the stack — Elysia for the API, TanStack Start for the frontend — Inngest provides the missing piece for reliable background processing. The result is a template where background jobs "just work." Send an event, define your function, let Inngest handle the rest. That's the developer experience Eden Stack aims to provide. --- *This post reflects my opinions after building production applications with multiple background job solutions. Your requirements may differ — BullMQ and Trigger.dev are both excellent tools for their intended use cases.* --- ### Why Neon Over Supabase and PlanetScale *Published: 2025-01-25* The case for provider-agnostic PostgreSQL in modern full-stack applications # Why Neon Over Supabase and PlanetScale Choosing a database provider feels like choosing a foundation — get it wrong, and you're rebuilding later. The serverless database landscape has matured significantly, with three major players dominating the conversation: Neon, Supabase, and PlanetScale. For Eden Stack, I chose Neon. Here's the reasoning — and why it matters for a template designed to be flexible. ## PostgreSQL: The Undisputed Leader Before comparing providers, let's address the engine question: PostgreSQL has won. The [2024 Stack Overflow Developer Survey](https://survey.stackoverflow.co/2024/technology) tells the story clearly: | Database | Professional Developer Usage | |----------|------------------------------| | PostgreSQL | **51.9%** | | MySQL | 39.4% | | SQLite | 30.9% | | MongoDB | 25.5% | PostgreSQL isn't just popular — it's pulling away. Usage grew from 45% in 2023 to nearly 52% in 2024. The gap with MySQL widened from 8.5 to 12.5 percentage points in a single year. Why the dominance? PostgreSQL offers: - Superior JSON support for modern applications - Advanced indexing (GIN, GiST, BRIN) - Full-text search built-in - pgvector for AI embeddings - Rich extension ecosystem - Battle-tested reliability For Eden Stack — a template for modern, AI-native applications — PostgreSQL was the obvious choice. The question became: which PostgreSQL provider? ## PlanetScale: The MySQL Exception Let's address PlanetScale first: **it's MySQL, not PostgreSQL.** PlanetScale built an excellent product around Vitess, MySQL's horizontal scaling solution. Their branching workflow is genuinely innovative, and the developer experience is polished. But here's the issue: choosing PlanetScale means choosing MySQL. In 2025, that's swimming against the current: - Most modern ORMs optimize for PostgreSQL first - AI/ML features (vector search) have better PostgreSQL support - The developer community is consolidating around PostgreSQL - Future hiring favors PostgreSQL experience PlanetScale also made concerning [pricing changes](https://planetscale.com/blog/planetscale-forever) in 2024, removing their free tier and repositioning as enterprise-focused. For a startup template, that's a red flag. **Verdict:** PlanetScale is excellent if you need MySQL specifically. For everything else, PostgreSQL providers make more sense. ## Supabase: The All-in-One Platform Supabase positions itself as "the open-source Firebase alternative." It's PostgreSQL-based and offers an impressive feature set: - PostgreSQL database with a nice dashboard - Built-in authentication (Supabase Auth) - Real-time subscriptions - Edge Functions - Object storage - Vector support If you want an all-in-one platform, Supabase delivers. The integration is tight, the dashboard is excellent, and the community is vibrant. ### The Vendor Lock-In Problem Here's my concern with Supabase: **the value is in the ecosystem, not just the database.** ```typescript // Supabase encourages this pattern import { createClient } from '@supabase/supabase-js'; const supabase = createClient(url, key); // Auth through Supabase const { user } = await supabase.auth.signInWithOAuth({ provider: 'google' }); // Database through Supabase const { data } = await supabase.from('users').select('*'); // Storage through Supabase const { data: file } = await supabase.storage.from('avatars').upload(path, file); ``` Each feature pulls you deeper into the Supabase ecosystem. The database itself is standard PostgreSQL, but: - **Supabase Auth** isn't portable — migrate means rebuilding auth - **Real-time subscriptions** use Supabase-specific protocols - **Storage** is Supabase-proprietary - **Row-level security** is configured through their dashboard None of this is bad. If you're committed to Supabase long-term, the integration is a feature. But for a template designed to let developers **choose their own components**, this coupling works against flexibility. ### The Philosophical Difference Eden Stack's philosophy: **high-quality building blocks you can swap.** - Use Better Auth? Swap it for Clerk if you want. - Use Neon? Move to AWS RDS if you need. - Use Inngest? Replace with BullMQ if that fits better. Supabase's philosophy: **use our integrated platform for everything.** Both are valid approaches. They're optimizing for different goals. ## Neon: PostgreSQL, Focused Neon does one thing: **serverless PostgreSQL, done exceptionally well.** ```typescript // Neon: Just PostgreSQL import { neon } from '@neondatabase/serverless'; const sql = neon(process.env.DATABASE_URL); const users = await sql`SELECT * FROM users WHERE id = ${userId}`; ``` Or with Drizzle: ```typescript import { drizzle } from 'drizzle-orm/neon-http'; import { neon } from '@neondatabase/serverless'; const sql = neon(process.env.DATABASE_URL); const db = drizzle(sql); // Standard Drizzle queries — no Neon-specific code const users = await db.select().from(usersTable); ``` ### What Neon Does Well **1. True Serverless Scaling** Neon scales to zero when inactive and wakes instantly. You pay for what you use, not for idle capacity. This matters for: - Development branches that sit unused - Side projects with sporadic traffic - Cost-conscious startups **2. Database Branching** Like Git for your database: ```bash # Create a branch for feature development neon branch create --name feature-xyz # Each branch is a full copy, instantly available # Test migrations without touching production ``` This workflow is transformative for teams. Test schema changes on a branch, verify they work, then merge. No more "I hope this migration doesn't break prod." **3. Generous Free Tier** - 0.5 GB storage - 190 compute hours/month - Unlimited projects and branches For development and small production workloads, you might never pay anything. **4. Provider Agnostic by Design** Here's the key insight: **Neon is just PostgreSQL.** Your application code doesn't know it's talking to Neon. The connection string works with any PostgreSQL client. When you outgrow Neon or need different infrastructure, you can migrate to: - AWS RDS - Google Cloud SQL - Azure Database for PostgreSQL - Self-hosted PostgreSQL - Any other PostgreSQL host Your Drizzle schema stays the same. Your queries stay the same. The migration is a connection string change and a data export/import. ## The Provider-Agnostic Architecture This is Eden Stack's database philosophy: ```mermaid flowchart TD subgraph Eden["Eden Stack Architecture"] A1["Application Code"] --> A2["Drizzle ORM"] A2 --> A3["PostgreSQL Protocol"] A3 --> A4["Any PostgreSQL Provider"] A4 --> N["🟢 Neon (default)"] A4 --> R["AWS RDS"] A4 --> G["Google Cloud SQL"] A4 --> Z["Azure PostgreSQL"] A4 --> S["Self-hosted"] end ``` Drizzle provides the ORM abstraction. PostgreSQL provides the protocol standard. Neon provides a great default. But nothing in your codebase is Neon-specific except the connection string. Compare to Supabase: ```mermaid flowchart TD subgraph Supa["Supabase Architecture"] B1["Application Code"] --> B2["Supabase Client (proprietary)"] B2 --> B3["Supabase Platform"] B3 --> SA["⚠️ Supabase Auth (locked in)"] B3 --> SR["⚠️ Supabase Realtime (locked in)"] B3 --> SS["⚠️ Supabase Storage (locked in)"] B3 --> SP["✅ PostgreSQL (portable)"] end ``` The database is portable, but everything around it isn't. ## When to Choose What **Choose PlanetScale when:** - You specifically need MySQL (legacy requirements, existing expertise) - Vitess-level horizontal scaling is a requirement - You're enterprise and price isn't a concern **Choose Supabase when:** - You want an all-in-one platform and embrace the ecosystem - Real-time features are central to your application - You prefer dashboard-driven configuration - Vendor lock-in isn't a concern **Choose Neon when:** - You want PostgreSQL without ecosystem lock-in - Provider flexibility matters for your roadmap - Serverless scaling and branching fit your workflow - You're using a separate ORM (Drizzle, Prisma) - Cost efficiency is important ## Why Eden Stack Uses Neon For a template designed around flexibility and modern best practices: 1. **PostgreSQL is the standard** — 52% of developers, growing fast 2. **Provider agnostic** — Swap Neon for any PostgreSQL host 3. **Pairs with Drizzle** — ORM handles the abstraction, Neon handles hosting 4. **Serverless-native** — Scales to zero, instant branching 5. **Generous free tier** — Build without paying until you're ready Neon provides the database Eden Stack needs without dictating the rest of your infrastructure. That's the goal: strong defaults, easy swaps. Your database is PostgreSQL. Your ORM is Drizzle. Your host starts with Neon. If any of those need to change, they can — independently. --- *This post reflects my opinions after evaluating serverless database options. Supabase and PlanetScale are excellent products — this isn't about them being bad, but about Neon being a better fit for Eden Stack's provider-agnostic philosophy.* --- ### Why TanStack Start Over Next.js *Published: 2025-01-25* A case for choosing TanStack Start when building enterprise-grade applications that need deployment flexibility # Why TanStack Start Over Next.js Next.js paved the way for full-stack React development. It deserves enormous credit for making server-side rendering accessible, establishing conventions that shaped how we think about React applications, and proving that the React ecosystem could compete with Rails-style productivity. Without Next.js, the modern React landscape would look very different. But when I was choosing a framework for Eden Stack, I chose TanStack Start. Here's why. ## The Self-Hosting Reality Let's start with the elephant in the room: **Next.js is notoriously difficult to self-host outside of Vercel.** This isn't FUD. It's documented reality. According to BuiltWith data, while 34% of Next.js sites run on Vercel, **up to 80% of large enterprise organizations do not use Vercel or similar FEaaS providers**. Why? Because enterprises have their own infrastructure requirements — Azure, AWS, on-premise data centers, compliance mandates. And when you try to self-host Next.js at scale, things break in ways that aren't immediately obvious: - **Distributed caching fails** across multiple replicas - **Image optimization** requires additional infrastructure - **Incremental Static Regeneration** needs shared storage that isn't documented - **Environment variables** behave differently than on Vercel - **Container deployments** have notorious issues (just search "Next.js Azure App Service container" and count the Stack Overflow questions) As David Höck wrote in his comprehensive guide on [self-hosting Next.js at scale](https://dlhck.com/thoughts/the-complete-guide-to-self-hosting-nextjs-at-scale): *"Self-hosting Next.js in production is fundamentally different from clicking 'deploy' on Vercel. When you're dealing with horizontal scaling, multiple replicas, and enterprise-grade requirements, the default Next.js setup breaks down in ways that aren't immediately obvious."* ## TanStack Start is Deployment-Agnostic TanStack Start was designed from the ground up to run anywhere: Node, Bun, Deno, Cloudflare Workers, Netlify, AWS Lambda, Azure Functions, your own Kubernetes cluster. It doesn't matter. There's no "golden path" that only works on one platform. The framework compiles to standard JavaScript that runs in any environment supporting your chosen runtime. No special adapters, no undocumented environment variables, no surprises when you move from development to production. For Eden Stack, this was non-negotiable. A boilerplate that only works well on one hosting provider isn't a foundation — it's a constraint. ## Type Safety That Actually Works Both frameworks claim type safety, but the approaches differ fundamentally. Next.js provides type safety through generated types — you write code, Next.js infers types, and you hope everything lines up. It works, mostly, until it doesn't. The App Router introduced complexity that made type inference less predictable. TanStack Start offers **fully type-safe routing at compile time**. Routes, loaders, search params, path params — everything is inferred and validated by TypeScript before your code runs. Combined with Eden Treaty for API calls, you get end-to-end type safety from database to UI without any code generation steps. ```typescript // TanStack Start: Types are inferred at the route level export const Route = createFileRoute('/users/$userId')({ loader: async ({ params }) => { // params.userId is typed as string return await getUser(params.userId) }, }) ``` ## The Complexity Question Next.js has grown increasingly complex. The App Router, React Server Components, Server Actions, partial prerendering, the `use` hook, `cache()`, `unstable_cache()`, various rendering strategies — the mental model required to work effectively with modern Next.js is substantial. Some of this complexity is genuinely powerful. RSC can enable impressive performance optimizations. But it comes at a cost: developer experience, debugging difficulty, and the constant question of "am I using this correctly?" TanStack Start takes a different approach. It uses full-document SSR with full hydration — a simpler model that's easier to reason about. There's no magic. No opaque server/client boundary confusion. The tradeoff is that you don't get RSC's granular streaming, but you gain clarity and predictability. For a boilerplate meant to help developers ship quickly, I'd rather give them a foundation they can understand completely than one with hidden complexity that surfaces at the worst times. ## What About AI and Training Data? A common argument for Next.js: it's more popular, so AI coding tools have more training data for it. I'm skeptical this matters much anymore. Modern AI agents don't just rely on pre-trained knowledge — they actively research documentation while working. Claude can read TanStack's docs. Cursor can search the repo. The quality of documentation matters more than the quantity of Stack Overflow posts. TanStack's documentation is exceptional. It's fresh, well-organized, and designed for both humans and AI parsing. The patterns are consistent and explicit. When an AI assistant works with TanStack Start, it can reason about the codebase clearly because the framework itself is clear. ## When Next.js Still Makes Sense I'm not saying Next.js is bad. It's excellent for: - **Vercel deployments** — the integration is genuinely best-in-class - **Content-heavy sites** — RSC shines for streaming lots of static content - **Teams with Next.js expertise** — switching frameworks has real costs - **Projects already using it** — migration rarely makes sense mid-project If you're building a marketing site that will live on Vercel, Next.js is probably the right choice. ## Why Eden Stack Uses TanStack Start For a production-ready template that developers will use to build real businesses, the calculus was clear: 1. **Deployment flexibility** — You shouldn't be locked to one hosting provider 2. **Type safety** — End-to-end inference without code generation 3. **Simplicity** — A mental model you can fully understand 4. **AI-friendly** — Great docs, explicit patterns, no magic TanStack Start + Elysia + Eden Treaty gives us type-safe full-stack development that works anywhere. That's the foundation Eden Stack is built on. --- *This post reflects my opinions after building production applications with both frameworks. Your mileage may vary, and technology decisions should be based on your specific requirements.* --- ### Working with Claude on Eden Stack *Published: 2025-01-25* The agentic development workflow that makes Eden Stack different # Working with Claude on Eden Stack Eden Stack isn't just a template—it's designed for a new way of building software. Instead of writing every line yourself, you describe what you want and let AI implement it, following the patterns already established in the codebase. This post shows you how to work with Claude effectively on Eden Stack projects. ## The Core Idea Traditional development: ``` You → Write code → Test → Debug → Repeat ``` Agentic development: ``` You → Describe intent → AI writes code → You review → AI fixes → Done ``` The key insight: **AI is better at repetitive pattern-matching than you are.** Once a pattern exists in your codebase, AI can replicate it faster and more consistently than you can. ## Skills: Institutional Knowledge for AI Eden Stack includes **Claude skills**—markdown files that teach Claude how things work in this specific codebase. ``` .claude/skills/ ├── better-auth-elysia/ # Auth patterns ├── drizzle-neon/ # Database patterns ├── elysia-eden-treaty/ # API patterns ├── inngest-elysia/ # Background job patterns ├── stripe-elysia-inngest/ # Payment patterns └── ... ``` When you mention a topic, Claude loads the relevant skill automatically. The skill contains: - **Why** things are done this way - **How** to implement the pattern - **Examples** from the actual codebase - **Gotchas** to avoid ## Effective Prompting ### Be Specific About What You Want ```markdown ❌ "Add user profiles" ✅ "Add user profiles with: - Database table for profile fields (bio, location, website) - API endpoint for updating profile - Profile settings page in the dashboard - Mobile screen for editing profile" ``` The second prompt gives Claude clear scope and deliverables. ### Reference Existing Patterns ```markdown "Add a feedback widget using the same pattern as the BookmarkButton component" ``` Claude will find the referenced pattern and replicate it. ### Ask for Specific Technologies ```markdown "Add email notifications for new messages using React Email and Resend, processed via Inngest background jobs" ``` This tells Claude exactly which stack to use. ## Real Workflow Examples ### Example 1: Adding a Feature **You say:** ```markdown Add a "favorites" feature where users can star conversations. Show favorites in a separate section of the sidebar. Include a keyboard shortcut (Cmd+S) to toggle favorite. ``` **Claude will:** 1. Create `favorites` table in schema 2. Generate migration 3. Create API endpoints in Elysia 4. Create React hooks with TanStack Query 5. Create UI components 6. Add keyboard shortcut handler 7. Run type-check to verify ### Example 2: Fixing a Bug **You say:** ```markdown When I log out on mobile, the session sometimes persists. Check the auth flow and fix it. ``` **Claude will:** 1. Examine the auth client configuration 2. Check SecureStore clearing logic 3. Trace the signOut flow 4. Identify the issue 5. Implement fix 6. Verify with type-check ### Example 3: Refactoring **You say:** ```markdown The conversation list is slow with 100+ items. Add virtualization and optimize the query. ``` **Claude will:** 1. Install @tanstack/react-virtual 2. Refactor ConversationList to use virtualization 3. Add pagination to the API endpoint 4. Update the React Query hook for infinite scroll 5. Test performance ## When to Intervene AI isn't perfect. Here's when to step in: ### Review Before Commit Always review generated code before committing. Look for: - **Logic errors**: Does it actually do what you asked? - **Security issues**: SQL injection, auth bypasses, etc. - **Performance**: Unnecessary queries, missing indexes - **Edge cases**: Empty states, error handling ### Provide Context When Stuck If Claude keeps getting something wrong: ```markdown You're approaching this wrong. In this codebase, we handle X by Y. Look at apps/api/src/routes/projects.ts for an example. ``` Direct references help Claude course-correct. ### Make Design Decisions Claude implements, but you decide: - What features to build - UX priorities - Architecture tradeoffs - Business logic Don't let AI make product decisions. ## Tips for Speed ### 1. Start with the Happy Path ```markdown "Add user onboarding. Just the basic flow— we'll add edge cases later." ``` Get something working, then iterate. ### 2. Batch Related Changes ```markdown "Add projects feature: 1. Database schema (projects, project_members) 2. API endpoints (CRUD + invite members) 3. Project list page 4. Project settings page 5. Member management UI" ``` One prompt, multiple outputs. ### 3. Use Follow-ups After initial implementation: ```markdown "Now add email notifications when someone is invited to a project" ``` Build incrementally. ### 4. Let AI Debug When tests fail: ```markdown "The project invite test is failing. Look at the error and fix it." ``` Claude can read error messages and fix issues faster than you can. ## The 10x Developer Myth (Revisited) The "10x developer" isn't someone who types 10x faster. They're someone who: 1. Knows what to build 2. Describes it clearly 3. Reviews effectively 4. Iterates quickly With AI, you can be that developer—even if you couldn't before. ## Anti-Patterns Things that slow you down: ### Over-Specifying ```markdown ❌ "Create a function called handleSubmit that takes an event parameter of type React.FormEvent and calls preventDefault, then extracts the name field from FormData..." ``` Just say what you want, not how to do it. ### Ignoring Errors ```markdown ❌ [Claude generates code with type errors] You: "That's fine, we'll fix it later" ``` Type errors compound. Fix them immediately. ### Not Reading Output ```markdown ❌ [Claude generates 200 lines of code] You: "Commit it" ``` At minimum, skim the code. At best, understand it. ## The Agentic Mindset Think of Claude as a very fast, very literal junior developer: - **Fast**: Can write code in seconds - **Literal**: Does exactly what you ask (not what you mean) - **Amnesiac**: Forgets context between sessions - **Pattern-matching**: Excellent at replicating existing patterns Work with these traits, not against them. ## What's Next As you get comfortable with agentic development: 1. **Create custom skills** for your app's specific patterns 2. **Build prompt templates** for common tasks 3. **Develop review checklists** for AI-generated code 4. **Train your intuition** for when AI is wrong The future of development isn't AI vs. humans—it's AI + humans, each doing what they're best at. Check out the [AI Features guide](/docs/ai-features) for more on building AI-powered applications with Eden Stack. --- ## Links - Website: https://eden-stack.com - GitHub: https://github.com/edenstackdev/eden-stack - Documentation: https://eden-stack.com/docs - Blog: https://eden-stack.com/blog