Remix TypeScript monorepo with Turborepo pipelines, Prisma, PostgreSQL OR SQLite (Litefs), Docker deploy to Fly.io, pnpm, shadcn/ui TailwindCSS.
pnpm create remix@latest --init-script --install --template https://github.com/PhilDL/remix-gospel-stack? This repository is opiniated:
- TypeScript only.
- Only compatible with pnpm package manager to handle monorepo workspaces.
- Uses turborepo pipelines + cache to build, lint, typecheck, and test the monorepo.
git clone [email protected]:PhilDL/remix-gospel-stack.git
cd remix-gospel-stack
pnpm add -w @remix-run/dev
pnpm remix initThis stack is a Remix oriented Monorepo powered by turborepo and pnpm workspaces. Containing a ready-to-deploy Remix App on fly.io via the building of a Docker container.
This Package uses pnpm as the package manager of choice to manage workspaces. It may work with yarn and npm if you put the workspace definitions in the package.json file but there is no guarantee.
apps Folder containing the applications
remix-app: the Remix.run app in ESM.remix-vercel: the Remix.run app, ready to be deployed on Vercel.nextjs-app: a Next.js apppackages Folder containing examples
ui: a React UI package example powered by shadcn/ui. Some example components and shadcn/ui Tailwind config exported as Tailwind plugin and preset.database: a Prisma wrapper ready to be used in other packages, or apps. Bundled with tsup. Can be PostgreSQL or SQLite // Litefs dependening of what you choose during installation.business: an example package using the Prisma database as a dependency and using a repository pattern like example.internal-nobuild: an example package that is pure TypeScript with no build steps. The main entrypoint to the package is directly src/index.ts. Remix takes care of compiling with its own build step (with esbuild). This packages also contains unit test with Vitest.
Remix uses tsconfig.json paths to reference to that project and its types. I would recommend these types of internal packages when you don't plan on publishing the package.config-packages:
future: {
unstable_optimizeDeps: true,
v3_fetcherPersist: true,
v3_lazyRouteDiscovery: true,
v3_relativeSplatPath: true,
v3_throwAbortReason: true,
v3_singleFetch: true,
v3_routeConfig: true,
},Warning All the following commands should be launched from the monorepo root directory
Install the dependencies.
pnpm installYou also have to copy the example .env.example:
cp .env.example .env
cp .env.example .env.dockerStart the postgresql docker container
pnpm run docker:dbNote: The npm script will complete while Docker sets up the container in the background. Ensure that Docker has finished and your container is running before proceeding.
Generate prisma schema
pnpm run generateRun the Prisma migration to the database
pnpm run db:migrate:deployRun the first build (with dependencies via the ... option)
pnpm run build --filter=@remix-gospel-stack/remix-app...Running simply pnpm run build will build everything, including the NextJS app.
Run the Remix dev server
pnpm run dev --filter=@remix-gospel-stack/remix-appTo switch between PostgreSQL and SQLite (Litefs), there is a turbo generator you can use from the root of the repository.
pnpm turbo gen scaffold-databaseThen follow the prompts. Be careful though, prisma migrations are linked to a specific database, so you will have to delete the migrations folder.
Note: You will have to run
pnpm i --fix-lockfileagain after switching to SQLite (Litefs) that require another package (litefs-js). You will probably also have to runpnpm run setupagain to generate the first migration.
turbo gen workspace --name @remix-gospel-stack/foobarbaz --type package --copyThen follow the prompts
Check the turbo.json file to see the available pipelines.
pnpm run test:e2e:dev --filter=@remix-gospel-stack/remix-apppnpm run lintpnpm run typecheckpnpm run test
or
pnpm run test:devpnpm add dayjs --filter @remix-gospel-stack/remix-appconfig-package folder. Any package or app will then extend from these configs.Warning All the following commands should be launched from the monorepo root directory
Prior to your first deployment, you'll need to do a few things:
First singup the fly CLI
fly auth signupCreate two apps on Fly, one for staging and one for production:
fly apps create remix-gospel-stack
fly apps create remix-gospel-stack-stagingNote: Once you've successfully created an app, double-check the
fly.tomlfile to ensure that theappkey is the name of the production app you created. This Stack automatically appends a unique suffix at init which may not match the apps you created on Fly. You will likely see 404 errors in your Github Actions CI logs if you have this mismatch.
Initialize Git.
git initCreate a new GitHub Repository, and then add it as the remote for your project. Do not push your app yet!
git remote add origin <ORIGIN_URL>Add a FLY_API_TOKEN to your GitHub repo. To do this, go to your user settings on Fly and create a new token, then add it to your repo secrets with the name FLY_API_TOKEN.
Create a database for both your staging and production environments:
Database creation:
fly postgres create --name remix-gospel-stack-db
fly postgres attach --app remix-gospel-stack remix-gospel-stack-db
fly postgres create --name remix-gospel-stack-staging-db
fly postgres attach --app remix-gospel-stack-staging remix-gospel-stack-staging-dbNote: You'll get the same warning for the same reason when attaching the staging database that you did in the
fly set secretstep above. No worries. Proceed!
Fly will take care of setting the DATABASE_URL secret for you.
Warning All the following commands should be launched from the monorepo root directory
Prior to your first deployment, you'll need to do a few things:
First singup the fly CLI
fly auth signupCreate two apps on Fly, one for staging and one for production:
fly apps create remix-gospel-stack
fly apps create remix-gospel-stack-stagingNote: Once you've successfully created an app, double-check the
fly.tomlfile to ensure that theappkey is the name of the production app you created. This Stack automatically appends a unique suffix at init which may not match the apps you created on Fly. You will likely see 404 errors in your Github Actions CI logs if you have this mismatch.
Initialize Git.
git initCreate a new GitHub Repository, and then add it as the remote for your project. Do not push your app yet!
git remote add origin <ORIGIN_URL>Add a FLY_API_TOKEN to your GitHub repo. To do this, go to your user settings on Fly and create a new token, then add it to your repo secrets with the name FLY_API_TOKEN.
Create a persistent volume for the sqlite database for both your staging and production environments. Run the following (feel free to change the GB size based on your needs and the region of your choice (https://fly.io/docs/reference/regions/). If you do change the region, make sure you change the primary_region in fly.toml as well):
fly volumes create data --region cdg --size 1 --app remix-gospel-stack
fly volumes create data --region cdg --size 1 --app remix-gospel-stack-stagingThen attach the volumes to the apps:
fly consul attach --app remix-gospel-stack
fly consul attach --app remix-gospel-stack-stagingNow that everything is set up you can commit and push your changes to your repo. Every commit to your main branch will trigger a deployment to your production environment, and every commit to your dev branch will trigger a deployment to your staging environment.
If you run into any issues deploying to Fly, make sure you've followed all of the steps above and if you have, then post as many details about your deployment (including your app name) to the Fly support community. They're normally pretty responsive over there and hopefully can help resolve any of your deployment issues and questions.
Once you have your site and database running in a single region, you can add more regions by following Fly's Scaling and Multi-region PostgreSQL docs.
Make certain to set a PRIMARY_REGION environment variable for your app. You can use [env] config in the fly.toml to set that to the region you want to use as the primary region for both your app and database.
Install the ModHeader browser extension (or something similar) and use it to load your app with the header fly-prefer-region set to the region name you would like to test.
You can check the x-fly-region header on the response to know which region your request was handled by.
We use GitHub Actions for continuous integration and deployment. Anything that gets into the main branch will be deployed to production after running tests/build/etc. Anything in the dev branch will be deployed to staging.
docker network create app_network
pnpm docker:build:remix-apppnpm docker:run:remix-appDOCKER_DEFAULT_PLATFORM=linux/amd64 flyctl deploy --config ./apps/remix-app/fly.toml --dockerfile ./apps/remix-app/DockerfileLearn more about the power of Turborepo:
If you found the template useful, please consider giving it a Star . Thanks you!
I am in no way an expert on Monorepo, Docker or CI. The setup proposed here is one of many and probably could be improved 10x, but I am learning by myself along the way, so if you see any possible improvement please submit a PR. I will appreciate it greatly !