FAQ
This page answers the questions people ask most often when they set up, run, change or evaluate Litestore.
This page gives short answers to the questions developers ask most about Litestore, and each answer has been checked against the code. When a topic has its own page, the answer links to it.
The questions are grouped by what you are trying to do. You might be getting Litestore running, operating it, changing it, or deciding whether to adopt it at all.
Setup
Why does every route return 500 with "Invalid environment variables"?
A required variable is not set.
env.ts checks the variables with @t3-oss/env-nextjs when the module loads, not on each request. Because the module never finishes loading, one missing value breaks every route, not just the route that needs it.
The console output names the missing keys. People most often miss REDIS_REST_URL and REDIS_REST_TOKEN. Both are required even on your own machine, but placeholder strings are enough in development. See Configuration.
Do I need Redis to develop locally?
You do not need a running Redis instance.
When isDev is true, checkRateLimit returns { success: true, remaining: 999 } before it touches Redis. Nothing connects to Redis during local development.
You still have to set the two variables, because env.ts only checks that they exist, not that Redis answers. In production you need a real Upstash instance.
Does the repository have a migration history I can rely on?
Not for local setup.
prisma/migrations/ contains a baseline migration and a performance-index migration. In production, bun run db:deploy (prisma migrate deploy) applies them, and that path works.
The README, however, says that local setup uses db:push. It also says there is no committed migration history you should treat as the source of truth for setting up a local database. Set up the database with:
bun run db:pushThen seed it:
bun run db:seedNote that the db:push script currently runs prisma migrate dev, not prisma db push. The script name and the README describe what the script was meant to do, and the script itself has since changed.
Do I need Stripe to run the store?
No.
STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET are .optional() in env.ts, and the readiness panel does not treat payments as critical.
Customers can browse and fill a cart without these keys. Only taking payment stops working.
The magic link email never arrives. Where do I look?
Look at Resend first. Check RESEND_API_KEY, and check that RESEND_SENDER_EMAIL uses a verified domain.
Redis being down does not cause this. checkRateLimit logs "Rate limiter error, failing open" and lets the request through. Rate limiting stops working, but sign-in does not.
Can I use MySQL or SQLite?
No.
The baseline migration writes guarantees that only Postgres can express. It creates unique indexes on lower("email") and lower("slug"). It also adds CHECK constraints such as order_amounts_refunded_not_over_total and stock_movement_quantity_math.
These constraints do real work. Several of Litestore's guarantees are enforced only by them, not by application code. A database that cannot express the constraints would not enforce the guarantees.
Running it
Where do settings live, in env or in the admin?
You set secrets and infrastructure endpoints as environment variables, and env.ts checks them.
You set the store's identity, currency, thresholds and AI autonomy under Settings in the admin. Changes there take effect without a deploy.
The rule behind the split is simple. If you would not want to redeploy just to adjust something, it belongs in the admin.
Does anything phone home?
No.
The codebase has no licence check and no variable that points at a Litestore service.
Litestore only sends traffic to the integrations you configure.
How do I connect Claude or another assistant to my store?
- Create a
ServiceApiKeywith theadmin:mcpscope in Settings → Developer. - Point your MCP client at
/api/mcp/adminand send the headerAuthorization: Bearer <key>.
app/api/mcp/admin/route.ts rejects any key without that scope. The scope is what actually grants access, not just a label on the key.
Read tools answer from live data. Tools that change something create approval cards, and you approve or reject them in the admin. See MCP servers.
Can more than one person use the admin?
Yes. Each user has a role. You can also give a single user extra permissions with grantedPermissions or take some away with deniedPermissions.
An admin cannot grant a permission they do not have themselves. That stops people from handing each other more access than they hold.
When someone edits a role or an override, Litestore writes a user_permissions_changed activity entry. It records who made the change, whose access changed, and what changed.
Changing it
How do I add a new section to the storefront?
- Add the type to
BLOCK_TYPESinlib/blocks/registry.ts.BLOCK_REGISTRYis declaredsatisfies Record<BlockType, BlockDefinition>, sotypecheckfails until you add the definition. - Add a case to the renderer. The compiler does not check this step. The switch in
components/web/blocks/block-renderer.tsxends indefault: return null, so a block without a case renders nothing instead of failing the build.
Remember the second step. The type system guides you through the registry and then stops. See Blocks.
How do I react to something happening, like an order, a refund or a signup?
Attach a handler to the domain event.
app/api/inngest/route.ts spreads domainEventFunctions into the Inngest serve() call. A handler you attach to an event is served from there without any more wiring. See Events.
Why did my change fail a lint:discipline check?
scripts/check-discipline.ts enforces import boundaries, canonical patterns and budget ratchets. It is one of the 25 scripts/check-*.ts checks.
The failure message names the rule and the file, so you can tell which of the three you broke. See The harness.
Is there a stable extension API?
No. The README says so directly: this is "not a stable public extension API" and "not a polished framework".
You are editing a product's codebase, not building against a fixed contract. Changes upstream can break your customizations.
Can I remove modules I don't use?
Yes. It is your copy of the code.
Modules share the database and the registries, so start by deleting the module from the registry and work outward. Then bun run typecheck lists every place that still refers to it.
Evaluating it
How big is it?
Litestore has 70 Prisma models, 56 domain events, 10 block types and 41 admin task kinds.
CI runs 25 architecture checks and roughly 1,349 test cases across 154 Vitest files.
What kind of codebase am I adopting?
The README is direct about this. It calls the codebase active, broad and usable, but "not a minimal starter".
The storefront and the admin share one Next.js app. Older abstractions and admin experiments are still being cleaned up.
Expect to read code rather than configure a framework.
What is out of scope?
Litestore is a store for a single merchant, and you run it yourself.
It does not include these things:
- subscriptions and recurring billing
- B2B quotes and company accounts
- a plugin marketplace
- multi-tenant SaaS hosting