Litestore · Developer docs
Deployment

Deploying

Put a configured Litestore store into production on Vercel or any Node.js host.

Once the store works locally, you deploy it as a single Next.js application. Follow these steps when you set up production for the first time or when you move to a new host.

Your server
One Next.js app
Storefront
Admin
Marketing
PostgresOne database
The storefront, admin and marketing tools run as one Next.js app on one server, backed by one Postgres database.

The storefront and the admin are routes in the same app. Scheduled work runs as Inngest functions, and one route handler serves all of them. Nothing in env.ts or the runtime checks a licence.

To deploy, you apply the migrations, build and run the app, and connect Inngest to it. The rest is configuration you've already set up.

Prerequisites

You needWhy
A production Postgres databaseIt is the app's single source of truth.
A production Upstash Redisenv.ts requires REDIS_REST_URL and REDIS_REST_TOKEN. Rate limits, the checkout payment lock and coupon reservations use it, and /api/health reports it as degraded when it's unreachable.
Every required variableConfiguration lists them.
A verified Resend sender domainCustomers and staff sign in with a magic link, so email is the only way in. Production refuses to start without RESEND_API_KEY and RESEND_SENDER_EMAIL.
An S3 bucketS3_BUCKET, S3_ACCESS_KEY and S3_SECRET_ACCESS_KEY are required, and uploads fail without them.

Deployment steps

Migrations

This script runs prisma migrate deploy. It applies the committed migrations in prisma/migrations/ and never generates new ones.

bun run db:deploy

Run it against the production database before each deploy, or make it part of the deploy. Local setup uses the same command.

App deployment

Push the repository and set the environment variables in the project settings.

The package hooks build the generated files. postinstall runs prisma generate, which rebuilds the client on every install. prebuild runs scripts/build-icons.ts before the Next.js build.

The repository has no vercel.json. Set the project's function region to the region where your database runs, in the Vercel project settings or with a vercel.json of your own.

Inngest connection

Litestore runs scheduled and deferred work as Inngest functions, and the route app/api/inngest/route.ts serves them. It exports GET, POST and PUT from the serve() helper in inngest/next and sets maxDuration = 60.

Point an Inngest account at /api/inngest and set its event key as INNGEST_EVENT_KEY (the Inngest SDK reads it and the signing key from the environment). The schedules register on the first sync.

Verification

Open /api/health on the deployed site. It probes Postgres with SELECT 1 and Redis with ping(), each with a 3-second timeout, and answers ok, degraded or down (503), so you can also point an uptime monitor at it. The admin home's setup guide shows which store setup steps are still open.

Then send yourself a magic link. That one action tests Redis, Resend and sign-in together.

Database region

If the app and the database run in different regions, every query gets slower. The Prisma adapter in platform/db/client.ts is configured with this in mind and uses a 30-second connection timeout, TCP keepalive and a 25-connection pool. A code comment there records round trips of 2–8 seconds to a pooler on another continent, and each query adds that latency.

Background jobs

The Inngest route registers these functions:

  • Abandoned carts, currency rates and payment reconciliation
  • Scheduled collection publishing and the daily workflow checks
  • Stock and data cleanup, webhook retries and the shipment watch
  • The weekly digest, plus email sends and broadcasts
  • Referral reward holds
  • A dead-letter handler for jobs that ran out of retries
  • Everything in the spread domainEventFunctions

Nothing fails if Inngest is not connected

platform/inngest.ts creates the client with an id and a Prisma middleware, and env.ts declares no Inngest variables. The app boots and serves pages without Inngest, and domain events and queued email run inline, but the crons and durable workflows never run. Because nothing reports an error, a deployment without Inngest looks healthy.

Private deployments

Nothing in the codebase checks a licence, and no variable points at a Litestore service. A deployment without outbound internet access works the same as a public one, except that the external services you chose not to connect aren't available. Postgres, Redis, Resend and S3 are required, though, so they must be reachable inside your network.

Troubleshooting

Next steps

On this page