Stack
Litestore is built on Next.js, React, Prisma, PostgreSQL and other public packages, grouped here by the part of the app that uses them.
Litestore is built from public packages, and each one has its own documentation. Read this page when you need to find out which framework or library a part of the app is built with, or before you upgrade a dependency.
The versions below are the ones declared in package.json, and they have been tested together. When you upgrade one, run bun run verify and the integration and end-to-end tests to find out whether the upgrade broke anything.
Core framework
| Package | Version | What it does |
|---|---|---|
| Next.js 16 | ^16.1.1 | It provides the App Router, and in development it runs under Turbopack with next dev -p 3000 --turbopack --disable-source-maps. |
| React 19 | ^19.2.3 | Litestore uses Actions and useOptimistic, so most pages need very little client state. |
| TypeScript | ^5.9.3 | It covers the whole repository, and bun run typecheck runs tsc --noEmit across it. |
| Zod 4 and zsa | ^4.3.5 and ^0.6.0 | They validate input. |
| oRPC | @orpc/server ^1.13.9 | It provides the typed RPC API, defined in platform/api/orpc.ts, routed from platform/api/router.ts and served at app/api/rpc/. |
Server Components let a storefront page read the database directly, so there's no separate API layer to keep in sync. Since TypeScript covers the whole codebase, a schema change that breaks something shows up as a build error before it can affect checkout.
Each module keeps its input schemas in the same predictable place:
modules/<area>/admin/schema.ts
modules/<area>/storefront/schema.tsLitestore wraps server actions so that validation and permission checks run before the mutation.
Database and caching
The database is PostgreSQL 15+, and its constraints enforce Litestore's guarantees. The baseline migration adds CHECK constraints such as these:
stock_movement_quantity_math
order_amounts_refunded_not_over_totalPrisma 7 (7.4.2) runs on top of Postgres. It provides one schema file, a committed migration history in prisma/migrations/ and a fully typed client. When Litestore creates the client, it extends it with the soft-delete filter from platform/db/soft-delete-extension.ts, and the client connects through @prisma/adapter-pg.
Litestore uses Redis through Upstash (@upstash/redis, @upstash/ratelimit) for three jobs.
| Job | Where |
|---|---|
Key-value helpers (getCache/setCache) | platform/cache.ts |
| Rate limiters | platform/rate-limit/ |
| Payment idempotency locks | platform/rate-limit/payment-lock.ts |
Payments and email
Stripe (^20.3.1) handles checkout, capture, refunds and disputes. All of these go through platform/stripe-client.ts, platform/stripe-payment-provider.ts and modules/orders/payments/payment-webhook.ts, and Litestore copies each one into the PaymentTransaction ledger. Customers can browse and fill a cart without Stripe configured, but checkout needs it.
Resend (^6.9.2) and React Email send mail. The templates in modules/email/templates/ are React components that @react-email/components renders.
RESEND_API_KEY; outside production no email is sent and the link is printed in the terminal running bun run dev.Infrastructure and runtime
Bun 1.2.2 is the declared packageManager, and it runs every script in package.json. The application itself runs on Node.js.
Uploads go to S3-compatible storage (@aws-sdk/client-s3, @aws-sdk/lib-storage). They pass through platform/s3.ts into your own bucket, so the files are stored in your own account.
Inngest (^3.54.0) runs the background work. Crons and event handlers are in jobs/, and the same app serves them at app/api/inngest/. jobs/domain-events.ts takes each emitted domain event and turns it into cache invalidation and side effects.
Sentry (@sentry/nextjs ^10.40.0) connects through four instrumentation files. If you leave the DSN unset, the app still runs, but Sentry receives no error reports.
Biome (^1.9.4), Vitest (^4.0.18) and Playwright (1.58.0) are the development tools in the same package list.
| Command | What it does |
|---|---|
bun run lint | It lints and formats the code with Biome. |
bun run test | It runs Vitest. |
bun run test:e2e | It runs the Playwright journeys. |
bun run verify | It runs typecheck, lint and test. |
Authentication and styling
Better Auth (^1.4.19) is configured in platform/auth/server.ts with the magicLink and admin plugins, and sessions last 7 days. Litestore registers Google sign-in only when both AUTH_GOOGLE_ID and AUTH_GOOGLE_SECRET are set, so a self-hosted store works without it.
Tailwind v4 (^4.1.18) handles styling. The design tokens are declared in the @theme block of app/styles.css, so the admin and the storefront share one scale.
Radix UI primitives and @tanstack/react-table provide the unstyled behaviour under ui/ and ui/data-table/.
Architecture decisions
Litestore's stack is based on four design decisions, each of which keeps the number of moving parts low.
The developer overview explains why a fork is the way to customize.
Versions
The versions in package.json are the tested ones. When you upgrade Next.js or Prisma, run bun run verify and the integration and end-to-end tests before you deploy.
bun run verify still passes.