Get independence from expensive SaaS without losing its developer experience, the infra primitives to adapt to any future requirement, and the tools to build delightful, secure user experiences.
Check it live 👉 https://stack.merlijn.site
- Remix as the full-stack React framework.
- SST for infrastructure as code on AWS and Cloudflare.
- Hono API on AWS Lambda.
- Postgres database through Neon.
- Drizzle ORM as the headless TypeScript ORM.
- Stripe for subscription plans, customer portal, and more.
- Bun for fast local development.
- Biome for fast linting and formatting.
- shadcn React components.
- Tailwind CSS utility CSS Framework.
- React Email, customizable emails with React.
- Conform, type-safe form validation based on web fundamentals.
- Zod, type-safe runtime schema validation.
- Authentication through email code, magic link and social logins.
- Easy Theming, switch between light and dark modes with ease.
- Client & Server Toasts, display toasts on your app.
- CSRF and Honeypot Protection, prevent malicious attacks.
- I18N, support multiple languages in your app.
- GitHub Actions for CI/CD Workflows.
- Postgres Row-Level Security (see Drizzle and Neon docs).
- File uploads to S3 and served over Cloudfront.
- The new SST OpenAUTH component instead of rolling it ourselves.
- Tailwind v4.0 when it comes out.
A tech stack where you don’t have to choose between capabilities, convenience, and price as you grow. A stack in which every tool is chosen because it has proven itself, not the latest hype, and that those tools have commitment to long-term stability.
The Startup Stack is built on SST, an infrastructure tool that strikes the perfect balance between developer convenience and long-term flexibility. In the article “The Cloud Hasn't Been Won Yet”, Oliver Gilan sees it for what it is: most Platform as a Service (PaaS) solutions fall into a trap – they're either too simple and limiting (or expensive) for growing teams or too complex from the start. SST solves this by providing a powerful Infrastructure as Code (IaC) approach that adapts to your project's evolving needs. With SST, you get:
-
Flexible Complexity: Start with simple, one-line configurations for common services, but have the full power to dive into granular infrastructure details when needed. As your startup grows, your infrastructure can seamlessly grow with you.
-
Type-Safe Configurations.
-
Multi-Cloud Compatibility: Easily deploy across AWS and Cloudflare, with the potential to expand to other providers. Take a second to appreciate how cool it is that your Stripe products are defined in code or with a one-line change you can combine two different providers:
export const www = new sst.aws.Remix('Remix', {
domain: {
name: domain,
+ dns: sst.cloudflare.dns(),
}
}
The entire stack is serverless and in TypeScript. Serverless is powerful because it abstracts away infrastructure management, allowing developers to focus solely on building and deploying code, which accelerates development cycles. It also automatically scales to handle varying workloads, ensuring cost-efficiency and optimal performance without manual intervention.
Every developer has its own
personal isolated stage, including
your main
and dev
branches.
Prefer servers and containers? Just change ten lines of SST code.
Building on the ideas of SST, where you can adapt to changing requirements, is the decision to use Postgres. No matter what data requirements may surface, you can rest assured that Postgres will be able to handle it, either directly or through an extension.
Why Neon instead of Postgres on AWS with SST, you may ask?
An exception is made as the developer experience of Neon still beats Postgres on AWS, mainly because of features such as branching, and the fact that you start for free and scale-to-zero while on AWS you pay per hour. Neon is built on top of AWS and is available in the AWS marketplace so you still only have a single bill to pay.
Interfacing with your database through an ORM or not remains a debated topic. That’s why Drizzle, the headless ORM, is chosen:
Other ORMs and data frameworks tend to deviate/abstract you away from SQL, which leads to a double learning curve: needing to know both SQL and the framework’s API. Drizzle is the opposite. We embrace SQL and built Drizzle to be SQL-like at its core, so you can have zero to no learning curve and access to the full power of SQL. — Why SQL-like?
This template also includes a public facing API on AWS Lambda with Hono,
which also handles the Stripe webhooks. Hono allows you to compose an incredibly
powerful developer experience with
@hono/zod-openapi
, in which you can
validate values and types using Zod and generate OpenAPI Swagger
documentation.
At the same time, you can use Hono RPC next to it to consume your API on the Remix server or client completely type-safe. Note that for most UI data and actions you can just use Remix loaders and actions without going to your API.
The frontend is built with Remix, a full-stack React framework that prioritizes web standards and delivers long-term stability for modern web applications. Remix’s commitment to working with the browser means you can leverage fundamental web features like form submissions, progressive enhancement, and caching out of the box.
Whether you're deploying to traditional Node.js servers, serverless environments like AWS Lambda, or cutting-edge edge runtimes like Cloudflare Workers, Remix runs seamlessly. This flexibility lets you adapt to infrastructure changes without rewriting your frontend logic.
With Remix, the rug is not pulled out from under you to chase innovation (not pointing fingers 👀). Instead, you get incremental future flags.
Meanwhile you build interfaces rapidly with shadcn and Tailwind CSS, which let’s be honest, they don’t need a pitch anymore at this point.
For startups (or side projects) that prefer long-term stability and flexibility when requirements change.
This template is not designed to be the quickest to set up to play with.
Install Bun.
Get the template locally. Make sure to select "No" for installing dependencies with npm.
npx create-remix@latest --template Murderlon/the-startup-stack
Install the dependencies.
bun install`
SST requires an AWS account.
The easiest way is to use your personal root user account to try things out. If you are going to run this stack under an AWS Organization, checkout the SST docs on how to setup your AWS account.
When you’re done, read the
SST credentials docs and put your
credentials in ~/.aws/credentials
.
A domain registered with Cloudflare, AWS Route 53, or Vercel.
See the SST docs on custom domains for more information.
Just kicking the tires? You can skip this setting up a domain for now.
Warning
Having no domain configured means emails and Stripe payments won’t work and you can only use the admin account from the initial database seed.
- Comment out all the code in
infra/email.ts
and all its references (inlink
). - Remove the
domain
configurations frominfra/index.ts
,infra/stripe.ts
, andinfra/api.ts
:
- domain: {
- name: domain,
- dns: sst.cloudflare.dns(),
- },
- Get an account on Neon and create a Postgres database.
- Add your connection string:
bunx sst secret set DATABASE_URL your-connection-string
Run the following commands in this order:
# Push the latest migration to Neon (already in the repository)
bun run db:push
# Seed the database
bun run db:seed
Whenever you make changes to the database schema you should run:
bun run db:migrate
In order to use Stripe Subscriptions and seed our database, we need to get the secret keys from our Stripe Dashboard.
- Create a Stripe Account or use an existing one.
- Visit API Keys section and copy
the
Publishable
andSecret
keys. - Copy
.env.example
to.env
if you haven’t yet. - Put the secret in there as
STRIPE_API_KEY
.
We put it in .env
because this secret is needed at build time too.
Both values are also needed at runtime:
bunx sst secret set STRIPE_PUBLIC_KEY your-key
bunx sst secret set STRIPE_SECRET_KEY your-secret
Lastly, there are some other secrets we need to configure:
# Secures cookies and session data.
bunx sst secret set SESSION_SECRET "$(openssl rand -hex 32)"
# Encrypts one-time passwords (OTP)
bunx sst secret set ENCRYPTION_SECRET "$(openssl rand -hex 32)"
# Secures honeypot values in forms.
bunx sst secret set HONEYPOT_ENCRYPTION_SEED "$(openssl rand -hex 32)"
Note
The first time you spin up SST provisioning all the infra can take a couple minutes.
Spin up your local development environment
bun run dev
Go to production
bunx sst deploy --production
The following methods are supported:
- Email/Code
- Magic Links
- Social Logins (Github)
Under the hood, we are using remix-auth
, remix-auth-totp
and
remix-auth-github
to handle the authentication process.
In order to speed up development, the OTP code will also be displayed in the terminal/console, so you don't have to constantly check the email inbox. (Recommended for development purposes only.)
You can authenticate as admin
by using the following credentials:
- Email:
[email protected]
- Code: OTP Code is provided by the terminal/console, as email is not sent to
the
admin
user.
The following subscription features are included:
- Subscription Plans
- Subscription Checkout
- Subscription Management (via Stripe Customer Portal)
- Subscription Webhooks
You can test Subscriptions in by using the following Stripe test cards:
4242 4242 4242 4242
(Visa)5555 5555 5555 4444
(Mastercard)
Translations are done via remix-i18next
, a library from
@sergiodxa
that integrates i18next
with
Remix. You can learn more about remix-i18next
by checking the
official documentation.
Usage is as simple as it can be, as everything is already set up for you.
- Check
/modules/i18n
in order to customize the languages you want to support. - Add/Edit the translations in the
locales
folder. - Use the
useTranslation
hook in your components to translate your content.
useDoubleCheck
: A hook to confirm user actions, like deleting a record. (Original Source: Epic Stack)useInterval
: A hook to run a function at a specified interval.useNonce
: A hook to generate a nonce value.useRequestInfo
: A hook that returns the request information from theroot
loader.useTheme
: A hook to manage the application theme.
getToastSession
: A utility to get the toast session.createToastHeaders
: A utility to create toast headers.redirectWithToast
: A utility to redirect with a toast message.
- remix-saas for most of the Remix boiler plate and some of the docs.
- terminaldotshop for SST and other code patterns.