{"id":23501576,"url":"https://github.com/murderlon/the-startup-stack","last_synced_at":"2026-03-09T00:31:35.677Z","repository":{"id":269432462,"uuid":"866488734","full_name":"Murderlon/the-startup-stack","owner":"Murderlon","description":"Get independence from SaaS without loosing its developer experience, the infra primitives to adapt to any future requirement, and the tools  to build delightful, secure user experiences.","archived":false,"fork":false,"pushed_at":"2025-03-24T13:28:42.000Z","size":4307,"stargazers_count":139,"open_issues_count":6,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-05-25T18:04:02.562Z","etag":null,"topics":["drizzle-orm","i18n","postgres","react","remix","remix-stack","shadcn-ui","sst","stripe","tailwindcss","tech-stack","typescript"],"latest_commit_sha":null,"homepage":"https://stack.merlijn.site","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Murderlon.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-10-02T11:01:23.000Z","updated_at":"2025-05-01T06:24:09.000Z","dependencies_parsed_at":"2024-12-23T14:43:01.295Z","dependency_job_id":"d8208080-0c44-448d-9550-f9d410302f56","html_url":"https://github.com/Murderlon/the-startup-stack","commit_stats":null,"previous_names":["murderlon/the-startup-stack"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Murderlon/the-startup-stack","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Murderlon%2Fthe-startup-stack","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Murderlon%2Fthe-startup-stack/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Murderlon%2Fthe-startup-stack/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Murderlon%2Fthe-startup-stack/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Murderlon","download_url":"https://codeload.github.com/Murderlon/the-startup-stack/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Murderlon%2Fthe-startup-stack/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30278512,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T20:45:49.896Z","status":"ssl_error","status_checked_at":"2026-03-08T20:45:49.525Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["drizzle-orm","i18n","postgres","react","remix","remix-stack","shadcn-ui","sst","stripe","tailwindcss","tech-stack","typescript"],"created_at":"2024-12-25T07:18:39.296Z","updated_at":"2026-03-09T00:31:35.663Z","avatar_url":"https://github.com/Murderlon.png","language":"TypeScript","readme":"![](https://github.com/Murderlon/the-startup-stack/blob/main/.github/cover.png?raw=true)\n\n# The Startup Stack\n\nGet independence from expensive SaaS without losing its developer experience,\nthe infra primitives to adapt to any future requirement, and the tools to build\ndelightful, secure user experiences.\n\n## Contents\n\n- [Features](#features)\n  - [Planned](#planned)\n- [What is this?](#what-is-this)\n  - [Infrastructure](#infrastructure)\n  - [Backend](#backend)\n  - [Frontend](#frontend)\n- [When should I use this?](#when-should-i-use-this)\n- [Setup](#setup)\n  - [Prerequisites](#prerequisites)\n  - [AWS](#aws)\n  - [Domain](#domain)\n  - [Neon](#neon)\n  - [Stripe](#stripe)\n  - [Secrets](#secrets)\n- [Use](#use)\n  - [Commands](#commands)\n  - [Subscriptions](#subscriptions)\n  - [Internationalization](#internationalization)\n  - [Hooks](#hooks)\n  - [Toasts](#toasts)\n- [Acknowledgments](#acknowledgments)\n- [License](#license)\n\n## Features\n\n- **[React Router][]** (formerly known as [Remix][]) as the full-stack **[React][]** framework.\n- **[SST][]** for infrastructure as code on AWS and Cloudflare.\n- **[OpenAuth][]** for universal, self-hosted, standards-based authentication.\n- **[Hono][]** API on [AWS Lambda][].\n- **[Postgres][]** database through **[Neon][]**.\n- **[Drizzle ORM][]** as the headless TypeScript ORM.\n- **[Stripe][]** for subscription plans, customer portal, and more.\n- **[Bun][]** for fast local development.\n- **[Biome][]** for fast linting and formatting.\n- **[shadcn][]** React components.\n- **[Tailwind CSS][]** utility CSS Framework.\n- **[React Email][]**, customizable emails with React.\n- **[Conform][]**, type-safe form validation based on web fundamentals.\n- **[Zod][]**, type-safe runtime schema validation.\n- **Easy Theming**, switch between light and dark modes with ease.\n- **Client \u0026 Server Toasts**, display toasts on your app.\n- **CSRF and Honeypot Protection**, prevent malicious attacks.\n- **I18N**, support multiple languages in your app.\n- **GitHub Actions** for CI/CD Workflows.\n\n### Planned\n\n- Postgres Row-Level Security (see [Drizzle](https://orm.drizzle.team/docs/rls)\n  and [Neon](https://neon.tech/docs/guides/neon-authorize) docs).\n- File uploads to S3 and served over Cloudfront.\n- Tailwind [v4.0](https://tailwindcss.com/blog/tailwindcss-v4-beta) when it\n  comes out.\n\n## What is this?\n\nA tech stack where you don’t have to choose between capabilities, convenience,\nand price as you grow. A stack in which every tool is chosen because it has\nproven itself, not the latest hype, and that those tools have commitment to\nlong-term stability.\n\n### Infrastructure\n\nThe Startup Stack is built on [SST][], an infrastructure tool that strikes the\nperfect balance between developer convenience and long-term flexibility. In the\narticle\n[“The Cloud Hasn't Been Won Yet”](https://olivergilan.com/blog/cloud-hasnt-been-won/),\nOliver Gilan sees it for what it is: most Platform as a Service (PaaS) solutions\nfall into a trap – they're either too simple and limiting (or expensive) for\ngrowing teams or too complex from the start. SST solves this by providing a\npowerful Infrastructure as Code (IaC) approach that adapts to your project's\nevolving needs. With SST, you get:\n\n- **Flexible Complexity**: Start with simple, one-line configurations for common\n  services, but have the full power to dive into granular infrastructure details\n  when needed. As your startup grows, your infrastructure can seamlessly grow\n  with you.\n\n- **Type-Safe Configurations**.\n\n- **Multi-Cloud Compatibility**: Easily deploy across AWS and Cloudflare, with\n  the potential to expand to other providers. Take a second to appreciate how\n  cool it is that your\n  [Stripe products are defined in code](https://github.com/Murderlon/the-startup-stack/blob/main/infra/stripe.ts)\n  or with a one-line change you can combine two different providers:\n\n```diff\nexport const www = new sst.aws.Remix('Remix', {\n  domain: {\n    name: domain,\n+   dns: sst.cloudflare.dns(),\n  }\n}\n```\n\nThe entire stack is serverless and in TypeScript. Serverless is powerful because\nit abstracts away infrastructure management, allowing developers to focus solely\non building and deploying code, which accelerates development cycles. It also\nautomatically scales to handle varying workloads, ensuring cost-efficiency and\noptimal performance without manual intervention.\n\nEvery developer has its own\n[personal isolated stage](https://sst.dev/docs/workflow#with-a-team), including\nyour `main` and `dev` branches.\n\nPrefer servers and containers?\n[Just change ten lines of SST code](https://sst.dev/docs/examples/#aws-remix-container-with-redis).\n\n### Backend\n\nBuilding on the ideas of SST, where you can adapt to changing requirements, is\nthe decision to use [Postgres][]. No matter what data requirements may surface,\nyou can rest assured that Postgres will be able to handle it, either directly or\nthrough an [extension](https://neon.tech/docs/extensions/pg-extensions).\n\n_Why [Neon][] instead of\n[Postgres on AWS with SST](https://sst.dev/docs/component/aws/postgres), you may\nask?_\n\nAn exception is made as the developer experience of Neon still beats Postgres on\nAWS, mainly because of features such as [branching](https://neon.tech/flow), and\nthe fact that you start for free and scale-to-zero while on AWS you pay per\nhour. Neon is built on top of AWS and is available in the AWS marketplace so you\nstill only have a single bill to pay.\n\nInterfacing with your database through an ORM or not remains a debated topic.\nThat’s why [Drizzle][Drizzle ORM], the headless ORM, is chosen:\n\n\u003e Other ORMs and data frameworks tend to deviate/abstract you away from SQL,\n\u003e which leads to a double learning curve: needing to know both SQL and the\n\u003e framework’s API. Drizzle is the opposite. We embrace SQL and built Drizzle to\n\u003e be SQL-like at its core, so you can have zero to no learning curve and access\n\u003e to the full power of SQL. —\n\u003e [Why SQL-like?](https://orm.drizzle.team/docs/overview#why-sql-like)\n\nThis template also includes a public facing API on [AWS Lambda][] with [Hono][],\nwhich also handles the Stripe webhooks. Hono allows you to compose an incredibly\npowerful developer experience with\n[`@hono/zod-openapi`](https://hono.dev/examples/zod-openapi), in which you can\nvalidate values and types using [Zod][] and generate OpenAPI Swagger\ndocumentation.\n\nAt the same time, you can use [Hono RPC](https://hono.dev/docs/guides/rpc) next\nto it to consume your API on the Remix server or client completely type-safe.\nNote that for most UI data and actions you can just use Remix loaders and\nactions without going to your API.\n\n### Frontend\n\nThe frontend is built with [Remix][], a full-stack [React][] framework that\nprioritizes web standards and delivers long-term stability for modern web\napplications. Remix’s commitment to working with the browser means you can\nleverage fundamental web features like form submissions, progressive\nenhancement, and caching out of the box.\n\nWhether you're deploying to traditional Node.js servers, serverless environments\nlike AWS Lambda, or cutting-edge edge runtimes like Cloudflare Workers, Remix\nruns seamlessly. This flexibility lets you adapt to infrastructure changes\nwithout rewriting your frontend logic.\n\nWith Remix, the rug is not pulled out from under you to chase innovation (not\npointing fingers 👀). Instead, you get incremental\n[future flags](https://remix.run/docs/en/main/guides/api-development-strategy).\n\nMeanwhile you build interfaces rapidly with [shadcn][] and [Tailwind CSS][],\nwhich let’s be honest, they don’t need a pitch anymore at this point.\n\n## When should I use this?\n\nFor startups (or side projects) that prefer long-term stability and flexibility\nwhen requirements change.\n\nThis template is not designed to be the quickest to set up to play with.\n\n## Setup\n\n### Prerequisites\n\nInstall [Bun](https://bun.sh).\n\nGet the template locally. Make sure to select \"No\" for installing dependencies with npm.\n\n```sh\nnpx create-remix@latest --template Murderlon/the-startup-stack\n```\n\nInstall the dependencies.\n\n```sh\nbun install`\n```\n\n### AWS\n\nSST requires an [AWS][] account.\n\nThe easiest way is to use your personal root user account to try things out. If\nyou are going to run this stack under an AWS Organization, checkout the SST docs\non how to [setup your AWS account](https://sst.dev/docs/aws-accounts).\n\nWhen you’re done, read the\n[SST credentials docs](https://sst.dev/docs/iam-credentials) and put your\ncredentials in `~/.aws/credentials`.\n\nLastly, change the name in `sst.config.ts` to your project name\nand your preferred region to deploy in.\n\n### Domain\n\nA domain registered with\n[Cloudflare](https://www.cloudflare.com/products/registrar/),\n[AWS Route 53](https://aws.amazon.com/route53/), or\n[Vercel](https://vercel.com).\n\nSee the [SST docs on custom domains](https://sst.dev/docs/custom-domains) for\nmore information.\n\nIf your domain is not hosted by AWS Route 53 make sure to add the Cloudflare or\nVercel credentials to your `.env` file (see `.env.example` for more info and the SST docs).\n\nAfter that you can set your domain in `infra/dns.ts`.\n\n### Stripe\n\nIn order to use Stripe Subscriptions and seed our database, we need to get the\nsecret keys from our Stripe Dashboard.\n\n1. Create a [Stripe Account](https://dashboard.stripe.com/login) or use an\n   existing one.\n2. Visit [API Keys](https://dashboard.stripe.com/test/apikeys) section and copy\n   the `Publishable` and `Secret` keys.\n3. Copy `.env.example` to `.env` if you haven’t yet.\n4. Put the secret in there as `STRIPE_API_KEY`.\n\nWe put it in `.env` because this secret is needed at build time too.\n\nBoth values are also needed at runtime:\n\n```sh\nbunx sst secret set STRIPE_PUBLIC_KEY your-key\nbunx sst secret set STRIPE_SECRET_KEY your-secret\n```\n\nStripe products and prices are created per stage (such as `production` and your personal local stage).\nThis means you can change products/prices in code and test the flow before going to production.\n\n### Secrets\n\nLastly, there are some other secrets we need to configure:\n\n```sh\n# Secures cookies and session data.\nbunx sst secret set SESSION_SECRET \"$(openssl rand -hex 32)\"\n# Encrypts one-time passwords (OTP)\nbunx sst secret set ENCRYPTION_SECRET \"$(openssl rand -hex 32)\"\n# Secures honeypot values in forms.\nbunx sst secret set HONEYPOT_ENCRYPTION_SEED \"$(openssl rand -hex 32)\"\n```\n\n### Neon\n\nOne of the unique benefits of [Neon][] is branching for convenient developer [flows](https://neon.tech/flow).\nEvery time you want to use a different branch, you have to manually create the branch and change\nthe connection string.\n\n1. Get an account on [Neon][] and create a Postgres database.\n2. Optionally create a dev branch for yourself or use the main branch of your database.\n3. Add your connection string:\n\n```sh\nbunx sst secret set DATABASE_URL your-connection-string\n```\n\nRun the following commands in this order:\n\n```sh\n# Push the latest migration to Neon (already in the repository)\nbun run db:push\n```\nOnce you have successfully ran `bun run dev` for the first time\nyour new Stripe products have been created, which we need to \nseed the database.\n\n\u003e [!NOTE]\n\u003e Stripe products and prices are created per stage (such as `production` and your personal local stage).\n\u003e The seed will populate the Neon branch of your connection string with the products\n\u003e of the current stage (see `packages/core/src/plan/seed.ts`).\n\u003e Make sure to keep these in sync. If you deploy to production,\n\u003e you need to seed the production branch with the production Stripe products.\n\n```sh\nbun run db:seed\n```\n\nWhenever you make changes to the database schema you should run:\n\n```sh\nbun run db:migrate\n```\n\n## Use\n\n### Commands\n\n\u003e [!NOTE]\n\u003e The first time you spin up SST provisioning all the infra can take a couple minutes.\n\nSpin up your local development environment\n\n```sh\nbun run dev\n```\n\nGo to production\n\n```sh\nbunx sst deploy --production\n```\n\n### Authentication\n\nThe following methods are supported:\n\n- Email/Code\n- Magic Links\n- Social Logins (Github)\n\nUnder the hood, we are using `remix-auth`, `remix-auth-totp` and\n`remix-auth-github` to handle the authentication process.\n\nIn order to speed up development, the OTP code will also be displayed in the\nterminal/console, so you don't have to constantly check the email inbox.\n(Recommended for development purposes only.)\n\nYou can authenticate as `admin` by using the following credentials:\n\n- Email: `admin@admin.com`\n- Code: OTP Code is provided by the terminal/console, as email is not sent to\n  the `admin` user.\n\n### Subscriptions\n\nThe following subscription features are included:\n\n- Subscription Plans\n- Subscription Checkout\n- Subscription Management (via Stripe Customer Portal)\n- Subscription Webhooks\n\nYou can test Subscriptions in by using the following Stripe test cards:\n\n- `4242 4242 4242 4242` (Visa)\n- `5555 5555 5555 4444` (Mastercard)\n\n### Internationalization\n\nTranslations are done via `remix-i18next`, a library from\n[`@sergiodxa`](https://github.com/sergiodxa) that integrates `i18next` with\nRemix. You can learn more about `remix-i18next` by checking the\n[official documentation](https://github.com/sergiodxa/remix-i18next).\n\nUsage is as simple as it can be, as everything is already set up for you.\n\n- Check `/modules/i18n` in order to customize the languages you want to support.\n- Add/Edit the translations in the `locales` folder.\n- Use the `useTranslation` hook in your components to translate your content.\n\n### Hooks\n\n- `useDoubleCheck`: A hook to confirm user actions, like deleting a record.\n  (Original Source: [Epic Stack](github.com/epicweb-dev/epic-stack))\n- `useInterval`: A hook to run a function at a specified interval.\n- `useNonce`: A hook to generate a nonce value.\n- `useRequestInfo`: A hook that returns the request information from the `root`\n  loader.\n- `useTheme`: A hook to manage the application theme.\n\n### Toasts\n\n- `getToastSession`: A utility to get the toast session.\n- `createToastHeaders`: A utility to create toast headers.\n- `redirectWithToast`: A utility to redirect with a toast message.\n\n## Acknowledgments\n\n- [remix-saas](https://github.com/dev-xo/remix-saas) for most of the Remix\n  boiler plate and some of the docs.\n- [terminaldotshop](https://github.com/terminaldotshop/terminal) for SST and\n  other code patterns.\n\n## License\n\n[MIT](https://github.com/Murderlon/the-startup-stack/blob/master/license) ©\n[Merlijn Vos](https://github.com/Murderlon)\n\n\u003c!-- Definitions --\u003e\n\n[Remix]: https://remix.run\n[React Router]: https://reactrouter.com\n[React]: https://react.dev\n[SST]: https://sst.dev\n[Postgres]: https://postgresql.org\n[Neon]: https://neon.tech\n[Drizzle ORM]: https://orm.drizzle.team\n[Stripe]: https://stripe.com\n[shadcn]: https://ui.shadcn.com\n[Tailwind CSS]: https://tailwindcss.com\n[React Email]: https://react.email\n[Conform]: https://conform.guide\n[Hono]: https://hono.dev\n[AWS Lambda]: https://aws.amazon.com/lambda\n[Zod]: https://zod.dev\n[AWS]: https://aws.amazon.com\n[Bun]: https://bun.sh\n[Biome]: https://biomejs.dev\n[OpenAuth]: https://openauth.js.org\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmurderlon%2Fthe-startup-stack","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmurderlon%2Fthe-startup-stack","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmurderlon%2Fthe-startup-stack/lists"}