remix-saas: a Remix, Prisma and Stripe starter you own outright
A Lightweight, Production-Ready Remix Stack for your next SaaS application.
At a glance
- What is it?
- remix-saas is a template rather than a framework: scaffolding it with one command gives you a Remix app on Express with Prisma and SQLite, Stripe billing, GitHub and email sign-in, a rate limiter, helmet, i18next and a Fly.io ready container image. What you get is a codebase you own, and what you inherit is a dependency list and a set of opinions.
- Who is it for?
- Adopt remix-saas if you are starting a subscription product, want to own the whole codebase rather than depend on a backend service, and are comfortable with a stack of Prisma, SQLite and Fly.io volumes. Do not adopt it if you need multi-region writes, since the image stores the database on a single mounted volume, or if you would rather not maintain session secrets, webhook endpoints and email credentials yourself.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 5 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.
Star history
- dev-xo/remix-saas1,452 ★ · +0
| Repository | 2026-10-16 | 2026-11-07 |
|---|---|---|
| dev-xo/remix-saas | 1.5k | 1.5k |
0 Stars in the last 22 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The problem it solves: the boring half of a SaaS
Every subscription product starts with the same list of work that has nothing to do with the product. Sessions have to be signed. Sign-in has to work with an email provider and with GitHub. A database has to be reachable from the application and from the migrations. Someone has to pay you, which means a billing provider, a webhook endpoint, and a customer record. Forms have to be validated on the server. Bots have to be kept off the sign-up form. The list is long, boring, and identical between two products in the same category.
remix-saas is a template that front-loads that work. Its description calls it a lightweight, feature-rich, production-ready Remix stack for your next SaaS application, and the repository topics name the choices it makes: Remix, Prisma, SQLite, Stripe, Tailwind CSS, TypeScript and Fly.io.
It is worth being precise about what this kind of project is, because the word template carries two meanings. It is not a library you install and configure. It is a repository that you copy into your own project and then own. There is no runtime dependency on the template itself, no upgrade path, and no vendor to call. The upstream project is the starting point and the documentation, and after that it is your code.
The audience is a developer starting a paid web product and wanting the infrastructure of one already in place, with a preference for owning the deployment and the data rather than renting both.
The project is explicit about its lineage, stating that it shares common bits of code with the Indie Stack, the Epic Stack, Cloudflare React Router SaaS and other open source resources. The contributors in the acknowledgements include mw10013, who has been part of the development.
What the dependency list reveals about the stack
The package.json is the clearest description of the template, because a template is mostly a dependency list and a directory layout. The scripts section is short and tells you how the app runs:
"dev": "node ./server.mjs",
"start": "cross-env NODE_ENV=production node ./server.mjs",So the runtime is a custom Express server, server.mjs, rather than the standard Remix dev command, and the build is remix vite:build. The build script output is the production bundle the server serves.
The dependencies show the shape of the application. Remix itself is on version 2.15.x across @remix-run/node, @remix-run/react and @remix-run/express, with @remix-run/router alongside. Prisma is at 5.x with the client pinned to 5.20.0, and the prisma/ directory at the repository root is where the schema lives.
The rest is a list of decisions rather than surprises. Form handling uses Conform with Zod, so validation is shared between client and server. Radix UI primitives are used for the interactive components. Tailwind and PostCSS handle styling, with shadcn style configuration through components.json. React Email and its renderer are present for transactional mail. The server side has helmet for headers, express-rate-limit for abuse control, morgan for logging, compression for responses, cookie for session handling, isbot for bot detection, and i18next with a browser language detector for localisation. lucide-react supplies the icons.
That is a well-chosen list, and it is also a large one. A template that arrives with a full set of opinionated dependencies is faster to ship and slower to unpick.
Scaffolding a project and the environment it expects
Creating a project is one command:
npx create-remix-saas@latestThe repository has a remix.init/ directory, which is the template initialisation step, and the .env.example file shows what the generated project is expected to contain. The base configuration is small:
SESSION_SECRET="AUTOMATICALLY_GENERATED_ON_TEMPLATE_INITIALIZATION"
ENCRYPTION_SECRET="AUTOMATICALLY_GENERATED_ON_TEMPLATE_INITIALIZATION"Both secrets are marked to be generated at initialisation, so the template is expected to fill them in when it is set up, and they are the two values you must not leave at their placeholder. The host settings come next, with DEV_HOST_URL pointing at localhost:3000 and PROD_HOST_URL left empty for you to fill in. The database is a file:
DATABASE_URL="file:./data.db?connection_limit=1"The file comment above that line notes that environment variables in the file are made available to Prisma automatically, so the schema can read the connection string without any extra wiring.
The rest of the file covers the third party services. RESEND_API_KEY is for email, GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET are for social sign-in, STRIPE_SECRET_KEY and STRIPE_WEBHOOK_ENDPOINT are for billing, and a HONEYPOT_ENCRYPTION_SEED is generated at initialisation, with a link to the remix-utils documentation for the form honeypot pattern. ARCJET_KEY is marked optional and described as covering bot detection, spam signup detection and attack prevention.
So the generated project expects a working email provider, GitHub OAuth credentials and a Stripe account before authentication completes, and the documentation in the docs/ directory is the place to follow the setup.
Local development and the Stripe webhook loop
Running the app locally is the dev script, and the interesting part is what the template does about webhooks. Stripe cannot reach a laptop, so the project ships a forwarding command as a script:
"stripe:listen": "stripe listen --forward-to localhost:3000/api/webhook"That forwards live Stripe events to the local webhook route, and the .env.example file says so directly: on localhost, run that command to get the STRIPE_WEBHOOK_ENDPOINT secret, and on production point at the test webhooks page in the Stripe dashboard. The same information appears in the environment file's comment, which means the setup for local billing is one command and one secret rather than a set of instructions to assemble.
The rest of the developer workflow is conventional. There is a lint script that runs eslint with the gitignore as the ignore path and a cache inside node_modules, a typecheck script that runs tsc, a format script for prettier, and two test scripts, vitest for the run itself and vitest run --coverage for the coverage report. The repository has vitest.config.ts and a tests/ directory.
The code quality setup is a real differentiator for a template. A starter that arrives with linting, type checking, formatting and a test runner already wired up saves a team from arguing about those choices, and the configuration files are at the top of the tree: .eslintrc.cjs, .prettierrc, .prettierignore, .eslintignore, tsconfig.json and vite.config.ts.
The container image and the SQLite volume
The Dockerfile is written for Fly.io, and it is the part of the template with the most opinion in it. The base image is a slim Node image with a version you can override through a build argument, and the runtime label names the stack:
LABEL fly_launch_runtime="Remix/Prisma"The build stage installs the toolchain needed to compile native modules, installs the dependencies with npm ci, generates the Prisma client with npx prisma generate, builds the application with npm run build, and prunes the development dependencies.
The final stage is where the design decision becomes visible. The database is not in the image. A directory is created, declared as a volume, and the connection string points at it:
EXPOSE 3000
ENV DATABASE_URL="file:///data/sqlite.db"
CMD [ "npm", "run", "start" ]The entrypoint is docker-entrypoint.js, and the image also ships a small shortcut script that opens the SQLite CLI against the connection string, so an operator can inspect the data without a separate tool. The image is configured for a single writable volume, which is the right shape for a single machine application and the wrong shape for a multi-region or multi-writer deployment.
The repository also has fly.toml, so the deployment target is Fly.io, and the .dockerignore is present for the build context. This is a coherent, opinionated choice: one server, one volume, one SQLite file, with the container doing the rest.
What a template gives you and what it takes away
The honest way to read this project is as a decision pack rather than a library. It has made a stack choice for you: Remix on Express with a custom server, Prisma with SQLite, Stripe for billing, Tailwind with Radix primitives, and Fly.io as the deployment target. Some of those choices are reversible. Swapping Stripe for another billing provider means rewriting the webhook handling and the customer model. Swapping SQLite for Postgres means a migration and a new deployment story, and the single volume model in the Dockerfile is baked in. Swapping the deployment platform is easier, since the app is just a Node server behind a container.
There is also a governance detail worth noticing: the package.json is marked private, so the template is not published to a registry as a consumable package. That is correct for a template, and it reinforces that the intended workflow is copy and own.
The alternative worth comparing is not another template but the opposite approach, building the same application from framework primitives yourself, adding Prisma, Stripe and session handling to a fresh Remix app as you need them. The difference in approach is ownership of the dependency list and the amount of initial code. This template front-loads the work and hands you a large, opinionated set of dependencies; starting from scratch hands you nothing and leaves every choice open. The trade is time now against flexibility later.
The related stacks the project names, the Indie Stack and the Epic Stack, are useful reference points rather than competitors to be ranked, since the project itself says it shares code with them. The practical question is which of those starting points you would otherwise have used, and whether the Remix plus SQLite shape here matches the deployment you already have in mind.
Licence, maintenance and what to read before you scaffold
The licence is MIT, so you can take the generated project, close it, change it and sell what you build on it, with the notice kept. The repository also carries a CODE_OF_CONDUCT.md and a SECURITY.md, which is a reasonable baseline for a project that other developers copy into their own repositories.
The project is not archived and the last push was on 2026-10-01. It has no GitHub releases, so there is no tagged version to pin, which means the state of main is what you get when you scaffold. For a template that is mostly a starting point rather than a dependency, that is a smaller problem than it sounds, but it does mean you should look at the repository history before you copy it, and pin your own copy afterwards.
The live demo at remix-saas.fly.dev is described as a simple demo that displays all the template provided features, with a note that the site takes a few seconds to load because it runs on a free tier. It is worth opening before you scaffold, since it shows the finished state of every feature the template ships rather than a marketing screenshot.
If you decide to go ahead, the order of operations is simple. Read the Getting Started documentation in docs/, run npx create-remix-saas@latest, fill in the secrets that the initialisation does not generate for you, add the Resend, GitHub and Stripe credentials, and set up the Stripe webhook forwarding before you try to complete a paid signup.
Editorial conclusion
Adopt remix-saas if you are starting a subscription product, want to own the whole codebase rather than depend on a backend service, and are comfortable with a stack of Prisma, SQLite and Fly.io volumes. Do not adopt it if you need multi-region writes, since the image stores the database on a single mounted volume, or if you would rather not maintain session secrets, webhook endpoints and email credentials yourself. Before you scaffold, read the Getting Started documentation in the docs/ directory, and treat the .env.example file as the contract you have to satisfy before the app will authenticate a single user.
Frequently asked questions
How do I create a new project from the remix-saas template?
Run npx create-remix-saas@latest. The template then initialises a Remix application, and the .env.example file shows the environment it expects, with session and encryption secrets generated at initialisation and the database, email, GitHub and Stripe credentials left for you to fill in.
Which database and deployment platform does remix-saas use?
Prisma with SQLite, deployed to Fly.io. The Dockerfile puts the database on a mounted volume at /data with the connection string file:///data/sqlite.db, which suits a single server rather than a multi-writer setup.
How do I test Stripe webhooks while developing locally?
The template ships a script, stripe:listen, which runs stripe listen --forward-to localhost:3000/api/webhook. The .env.example file explains that this is how you obtain the STRIPE_WEBHOOK_ENDPOINT secret on localhost, while production uses the webhooks page in the Stripe dashboard.
What comes with the template out of the box?
The dependency list covers Remix on Express, Prisma, Conform with Zod for forms, Radix UI primitives with Tailwind, React Email, helmet, express-rate-limit, morgan, compression, i18next, lucide-react, and Stripe, with a Dockerfile, fly.toml, eslint, prettier, TypeScript type checking and Vitest configured.
Can I use remix-saas for a commercial product?
Yes. The project is licensed under the MIT licence and the generated package.json is marked private, so the template is copied into your repository and owned by you, with no runtime dependency on the template itself.
Official sources
Was this useful?