Blog

Read the latest articles.

Back to blog
December 16, 2024

Upgrade to React Router v7 in SaasRock v1.5

  • Nom
    Alexandro Martínez
    #react-router
    #remix
Upgrade to React Router v7 in SaasRock v1.5

The react-router-dom and @remix-run/* packages have been merged in react-router@7. This guide will help you migrate a v1.4 SaasRock project to v1.5 (or watch me do it on YouTube).

Here are the main changes:

  • ⭐ Upgraded to React Router v7
  • ⭐ New shadcn-ui sidebar
  • 🔨 SaasRock Enterprise renamed to Pro
  • 🔨 Prisma@6, SQLite Json and Enum support
  • 🔨 Portals also upgraded to RR7
  • ❗ Replaced dynamic pages for /pricing and /blog with route files

📢 Before you upgrade: as of Jan 16th, Vercel has not released official RR7 support.

Step-by-step guide

💿 Create a new branch

git checkout -b upgrade-rr7

💿 Pull the latest version.

git pull upstream main --no-ff

If you don't have an upstream set, read this article.

You'll get at least +900 staged changes, and a few merge conflicts.

💿 Fix package.json

Accept both changes when you're asked to resolve conflicts in package.json. For duplicated packages, keep the one with the highest version.

💿 Install new dependencies

Do a clean install to make sure the @remix-run/* packages are gone from your cache:

npm cache clean --force
rm -rf package-lock.json node_modules
npm cache verify
npm install

💿 Fix merge conflicts

  • If you're using Fly, be careful to keep your app name correctly in fly.toml (this is because I renamed the enterprise repo to pro).

  • Most of the conflicts will be related to imports that changed from @remix-run/* to react-router, and return/throw json(... from loaders and actions (replace it with Response.json).

💿 Run the official migration script

npx codemod remix/2/react-router/upgrade

💿 Uninstall deprecated packages

Bring back @remix-run/server-runtime, as it's required with remix-auth, yet to be upgraded to RR7.

npm install @remix-run/server-runtime

Uninstall v1-route-convention, I moved this script to app/utils/compat/v1-route-convention.ts.

npm uninstall @remix-run/v1-route-convention
npm uninstall @react-router/v1-route-convention

Uninstall remix-typedjson.

npm uninstall remix-typedjson

Find and replace:

  • remix-typedjson with react-router
  • useTypedFetcher with useFetcher.
  • useTypedLoader with useLoaderData.
  • useTypedActionData with useActionData.

💿 Remove json() from loaders and actions

Find and replace files containing one of the following imports:

  • { json } with { }
  • { json, with {
  • , json } with }
  • , json, with ,

Remove the json function from the import, and replace all instances of json( with either:

  • Recommended: Returning a Response.json object: return Response.json({ ... }). This one lets you set the status code and headers, but may case MetaFunction errors.
  • Optional: Returning "naked" JSON objects: return { ... }.

IMPORTANT: Use Response.json for resource routes.

You can do this faster by replacing:

  • throw json({ error: with throw Response.json({ error:.
  • return json({ error: with return Response.json({ error:.
  • throw json( with throw (.
  • return json( with return (.

💿 Run npm run typecheck to find any remaining errors.

Important notes

  • When the MetaFunction export fails, replace meta: MetaFunction<typeof loader> with meta: v2MetaFunction<LoaderData> and fix imports.

  • Resource routes cannot return naked objects, make sure to go to each resource route (e.g. all /api routes), and return Response.json instead of naked objects. I experienced this myself when updating saasrock.com to RR7 because I have a lock on my ERP system (not related to saasrock) using this api route: https://saasrock.com/api/absys/customer-id-123. So if a customer has an inactive license, this endpoint should return success: false, but the problem was that I returned a naked object response with return { success: licenseIsValid }; instead of return Response.json({ success: licenseIsValid }), so I got +10 calls/tickets in the span of 1 hour 😅.

💿 Try the app!

Make sure that all pages are working as expected, especially if your saasrock project is in production.

And remember! you don't have to use RR7, you can wait a few months until it's even more stable.


What's next?

For SaasRock v1.6 release (1, 2, 3 months from now):

  • Upgrade to Vite v6
  • Wait for official RR7 support from Vercel
  • Upgrade to Tailwind CSS v4 once it's out of beta
  • And what do you think about a markeplace of functional SaaS blocks?

Marketplace of SaaS blocks

You've may have noticed that SaasRock doesn't get as many updates as it used to for 3 main reasons:

  1. Since v1.4, it's been stable (at least 50% of you think so).
  2. I'm working on custom dev projects.
  3. I stop myself from adding new features because I don't want to make the codebase more complex and overengineered.

My initial attempt to fix #3 was to create SaaS templates, but almost none of you downloaded them, so I stopped making them, so not much 80/20 pareto principle value there.

Now, my 2025 attempt to fix #3: I've been considering creating a Marketplace of SaaS blocks, similar to shadcn-ui blocks, but with copy-pastable SaaS functionality. Also, see 21st.dev.

For example, a SaaS block would be composed of:

  1. /admin routes
  2. /app/:tenant routes
  3. the module directory with its services, utils, and components
  4. new schema.prisma models,
  5. instructions/videos, etc,
  6. your Stripe API Key to share revenue in case it's a premium SaaS block made by you

But I need to know if this is something you'd be interested in, so go leave your feedback on the SaasRock v1.6 survey, otherwise this will stay as an idea.

Here are some ideas for SaaS blocks:

  • Crawler (similar to Firecrawl.dev) - $10
  • Google Indexing, just like Indexer.so - Free for Core/Pro edition
  • ChatGPT clone made by {insert saasrock customer developer here} - Free for Pro edition, ${insert price} for anyone else

Those are just ideas. As for the revenue share, I'm thinking of a 70/30 split, where 70% goes to the SaaS block creator, and 30% goes to SaasRock.


If you have any questions, feel free to ask in the discord server (use the discussions channel).

We respect your privacy.

TLDR: We use cookies for language selection, theme, and analytics. En savoir plus.