Thank you for trying out my Remix SaaS kit! I did not expect so many downloads, so I thought I should make this Quickstart Tutorial.
If you like what you got, consider giving it a 5-star on Gumroad :).
Introducing Remix SaaS kit v1.
1) Core Concepts
Before you follow the tutorial, I want you to know why I built it the way it is.
I wanted to make an app where 1 email could have multiple accounts, like Notion.
A Tenant has its own:
Stripe Customer ID - Created at /register
Stripe Subscription ID - Created at /app/settings/subscription
Tenant Members - Created at /app/settings/members
Workspaces - Created at /app/settings/workspaces
This depends on your SaaS implementation. For example, I have a SaaS where the Workspace is a Legal Company, and another one where each Workspace represents the Current Project. It's up to you.
A Workspace has its own:
Links to other Workspaces
You can delete this in your implementation, but it's there if you need it.
I wanted to make a SaaS where my users could like accounts with other users. For example, Workspace X from Tenant A, wants to share information with Workspace Z from Tenant B. On this implementation, there's a direction, where one Workspace is a Provider and the other one a Client.
A Link has its own:
You can delete this in your implementation, but it's there if you need it.
On every SaaS kit, I implemented a Contracts app, on which two linked workspaces can share 1 contract, and it belongs to both of them. Also, you can see how PDF upload/preview work.
A Contract references:
Linked Workspace Members
Current Workspace Employees
Simple CRUD demo.
1.6) TenantId, WorkspaceId, and LinkId fields
Since this boilerplate is designed to support multiple tenants, each with its own workspaces, you have to implement these fields (on your prisma calls) on every Entity you create, hence the Contracts and Employees demo. I plan to implement an automatic way of doing this, subscribe or follow me to stay tuned!
2) Quickstart Tutorial
Follow these steps to see what Remix SaaS kit can do.
Postmark account (use REMIXSAASPOSTMARK code for -20%)
Supabase account (you can use your own Prisma-supported-database provider)
Formspree account (optional)
Open the downloaded project folder (I'm using VSCode), open a Terminal and run:
git init git add . git commit -am "initial"
2.3) Environment file:
.env.example file to just
Update the REMIX_SESSION_SECRET value to something secure
Set the REMIX_ADMIN_EMAIL with your email and something random for REMIX_ADMIN_PASSWORD.
Get your Stripe Secret Key and set it to REMIX_STRIPE_SK.
Open your Postmark Servers Dashboard, select or create your server, click on API Tokens and set it to REMIX_POSTMARK_SERVER_TOKEN.
(Optional) Open your Formspree Forms Dashboard, select or create your form, click on Integration, and set the Form's endpoint to REMIX_INTEGRATIONS_CONTACT_FORMSPREE.
Up to this point, you should have only 1 commit:
I highly recommend building your app first with SQLite, then moving to something like PostgreSQL/MySQL.
If you're not using SQLite, identify your database connection string format and set it to the DATABASE_URL environment variable.
IMPORTANT: If you're using Supabase and you will host your app on a Serverles environment like Vercel or AWS Lambda, use the Connection Pooling String as specified here. As you can see, use the normal PostgreSQL connection string when creating, migrating, and seeding the database with Prisma, but use the Connection Pooling String when deploying to a Serverless environment.
schema.prisma file, and set the corresponding database provider (sqlite, postgresql, mysql, sqlserver, mongodb, or cockroachdb).
Run the first migration and seed the database using this command:
npx prisma migrate dev --name init
You should get the following output:
If for any reason, the migration was created successfully but did not seed the database, use the following command:
npx prisma db seed
If you mess up the database, you can always reset it with Prisma, or drop the tables manually:
DROP TABLES Script:
DROP TABLE IF EXISTS "_prisma_migrations"; DROP TABLE IF EXISTS "Joke"; DROP TABLE IF EXISTS "ContractMember"; DROP TABLE IF EXISTS "ContractActivity"; DROP TABLE IF EXISTS "ContractEmployee"; DROP TABLE IF EXISTS "Contract"; DROP TABLE IF EXISTS "Employee"; DROP TABLE IF EXISTS "Link"; DROP TABLE IF EXISTS "SubscriptionFeature"; DROP TABLE IF EXISTS "SubscriptionPrice"; DROP TABLE IF EXISTS "SubscriptionProduct"; DROP TABLE IF EXISTS "TenantUserInvitationWorkspace"; DROP TABLE IF EXISTS "TenantUserInvitation"; DROP TABLE IF EXISTS "WorkspaceUser"; DROP TABLE IF EXISTS "Workspace"; DROP TABLE IF EXISTS "TenantUser"; DROP TABLE IF EXISTS "Tenant"; DROP TABLE IF EXISTS "User";
Up to this point, you should have 3 commits:
If you haven't already, install the dependencies:
Run the application:
npm run dev
Open https://localhost:3000, you should see the landing page:
Click on the Dark/Light mode Toggle:
Get rid of the
<TopBanner /> component, or customize it if you're advertising something, like me (other SaaS kits).
Go to the /pricing page and click on Go to /admin/pricing.
NOTE: Before we persist the Prices to the database, you can play with the pricing by modifying the
Log in as your admin user. If successful, it will redirect you with a Session Cookie to /admin/pricing.
Here we can persist the prices to our database and to our Stripe account by clicking the orange button.
NOTE: If you've persisted the prices to your DB and Stripe, but you want to make a change, you could manually DELETE the records on the following tables: "SubscriptionFeature", "SubscriptionPrice" and "SubscriptionProduct".
Now that our prices exist, go to /register and create a sample account (with a real email to get the Welcome email).
You should get a welcome email.
You will be redirected to the Dashboard:
That's all you need to get started using the boilerplate. And of course, you could also follow the
Click here to get -50 off, for a limited time only.
Subscribe or follow me to stay tuned!
Feel free to comment below if you have any questions.
Top comments (2)
Hello! The kit is really cool, some great components implemented and overall a great example of the power of Remix.
A few things I found confusing:
Again, really cool project, and neat components. I think a few tweaks could make this a great go to kit.
I’m glad you liked it! 😁
It think you need Node >= 16 if you’re using npm. I have no problem on my environment, here’s a video with npm (I had to comment the app/utils/email.server.ts file, as you specify in your sencond point). Maybe you could tell me your node and npm versions to replicate this issue 🤔.
Agree that it’s ugly when things are hard-coded or so dependent on a specific third party 😓; for now, you could find and delete all
sendEmail(…)calls. Although, I think it kinda defeats the purpose of SaaS if you don’t start with Postmark/SendGrid/Supabase emails/etc…, since you need an email provider to recover your password, even if you’re just testing on a local environment with an SQLite database. Nevertheless I already finished a skeleton version on the private repo (which also deletes the Workspaces concept), will commit it this weekend, after most of these issues are resolved (only for paid users though).
I’m being mentored by Chris Kluis. One of the things he tells me, is just this. Tenants and Workspaces are confusing, it shouldn’t be shown to the end user, it’s more of a Database layer to separate data. I’m working on this, but to give you an idea, a Tenant is an organization, and a Workspace could be a: Project, Department, Branch… let’s say it’s a Project. Now all your contracts depend on the Tenant AND Workspace your currently in. But yeah, I’m realizing it’s very confusing, I'll try my best to clarify the concept on the next release.
Thanks again your your comments!