Remix TypeScript monorepo with Turborepo pipelines, Prisma, PostgreSQL, Docker deploy to Fly.io, pnpm, TailwindCSS and Tsyringe for DI.
git clone [email protected]:PhilDL/remix-gospel-stack.git
cd remix-gospel-stack
💽 Unfortunately due to the fact that
pnpx create-remix
cli replace the"*"
in your package.json, it messes up the monorepo workspace package references by replacing them to the current Remix version, meaning that you can't use this template withcreate-remix
and the--template
flag. So for now you will have to clone and install.
This stack is a Remix oriented Monorepo powered by turborepo abd 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.
Monorepo architecture powered by Turborepo and pnpm workspaces:
-
apps
Folder containing the applicationsremix-app
: the Remix.run appnextjs-app
: a Next.js app
-
packages
Folder containing examplesdatabase
: a Prisma wrapper ready to be used in other packages, or apps. Bundled with tsup.business
: an example package using Tsyringe to inject the Prismadatabase
as a dependency and using a repository pattern like example.internal-nobuild
: an example package that is pure TypeScript with no build steps. Themain
entrypoint to the package is directlysrc/index.ts
. Remix takes care of compiling with its own build step (with esbuild). This packages also contains unit test with Vitest. Remix usestsconfig.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.ui
: a dummy React UI library (which contains a single<Button>
component), build with tsup.
-
config-packages
:- Eslint packages with different preset configs.
- TS Configs, also with different presets.
- Tailwind configs.
- Remix App Multi-region Fly app deployment with Docker
- Database Multi-region Fly PostgreSQL Cluster
- Remix App Healthcheck endpoint for Fly backups region fallbacks
- GitHub Actions for deploy the Remix App on merge to production and staging environments.
- End-to-end testing with Cypress in the Remix App
- Unit testing with Vitest and Testing Library inside the different packages.
- Code formatting with Prettier
- Static Types with TypeScript
Warning All the following commands should be launched from the monorepo root directory
-
Install the dependencies.
pnpm install
You also have to copy the example .env.example:
cp .env.example .env cp .env.example .env.docker
-
Start the postgresql docker container
pnpm run docker:db
Note: 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 generate
-
Run the Prisma migration to the database
pnpm run db:migrate:deploy
-
Run the first build (with dependencies via the
...
option)pnpm run build --filter=remix-app...
Running simply
pnpm run build
will build everything, including the NextJS app. -
Run the Remix dev server
pnpm run dev --filter=remix-app
turbo gen workspace --name @remix-gospel-stack/foobarbaz --type package --copy
Then follow the prompts
Check the turbo.json
file to see the available pipelines.
- Run the Cypress tests and Dev
pnpm run test:e2e:dev --filter=remix-app
- Lint everything
pnpm run lint
- Typecheck the whole monorepo
pnpm run typecheck
- Test the whole monorepo
pnpm run test or pnpm run test:dev
- How to install an npm package in the Remix app ?
pnpm add dayjs --filter remix-app
- Tweak the tsconfigs, eslint configs in the
config-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 signup
-
Create two apps on Fly, one for staging and one for production:
fly apps create remix-gospel-stack fly apps create remix-gospel-stack-staging
Note: Once you've successfully created an app, double-check the
fly.toml
file to ensure that theapp
key 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 init
-
Create 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 nameFLY_API_TOKEN
. -
Create a database for both your staging and production environments. Run the following:
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-db
Note: You'll get the same warning for the same reason when attaching the staging database that you did in the
fly set secret
step above. No worries. Proceed!
Fly will take care of setting the DATABASE_URL
secret for you.
Now 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.
- Create a docker network
docker network create app_network
- Build the docker image
pnpm docker:build:remix-app
- Run the docker Image
pnpm docker:run:remix-app
- (Optionnal) If you want to manually deploy to fly.io:
DOCKER_DEFAULT_PLATFORM=linux/amd64 flyctl deploy --config ./apps/remix-app/fly.toml --dockerfile ./apps/remix-app/Dockerfile
Learn 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 !