Skip to content

docs: add Backend for Frontend docs #13794

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions contributors.yml
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@
- yracnet
- ytori
- yuleicul
- yuri-poliantsev
- zeromask1337
- zheng-chuang
- zxTomw
48 changes: 48 additions & 0 deletions docs/how-to/backend-for-frontend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
---
title: Backend For Frontend
---

# Backend For Frontend

While React Router can serve as your fullstack application, it also fits perfectly into the "Backend for Frontend" architecture.

The BFF strategy employs a web server with a job scoped to serving the frontend web app and connecting it to the services it needs: your database, mailer, job queues, existing backend APIs (REST, GraphQL), etc. Instead of your UI integrating directly from the browser to these services, it connects to the BFF, and the BFF connects to your services.

Mature apps already have a lot of backend application code in Ruby, Elixir, PHP, etc., and there's no reason to justify migrating it all to a server-side JavaScript runtime just to get the benefits of React Router. Instead, you can use your React Router app as a backend for your frontend.

You can use `fetch` right from your loaders and actions to your backend.

```tsx lines=[10,16,20]
import type { Route } from "./+types/some-route";
import escapeHtml from "escape-html";

export async function loader({
request,
}: Route.LoaderArgs) {
const apiUrl = "https://api.example.com/some-data.json";
const res = await fetch(apiUrl, {
headers: {
Authorization: `Bearer ${process.env.API_TOKEN}`,
},
});

const data = await res.json();

const prunedData = data.map((record) => {
return {
id: record.id,
title: record.title,
formattedBody: escapeHtml(record.content),
};
});
return { prunedData };
}
```

There are several benefits of this approach vs. fetching directly from the browser. The highlighted lines above show how you can:

1. Simplify third-party integrations and keep tokens and secrets out of client bundles.
2. Prune the data down to send less kB over the network, speeding up your app significantly.
3. Move a lot of code from browser bundles to the server, like `escapeHtml`, which speeds up your app. Additionally, moving code to the server usually makes your code easier to maintain since server-side code doesn't have to worry about UI states for async operations.

Again, React Router can be used as your only server by talking directly to the database and other services with server-side JavaScript APIs, but it also works perfectly as a backend for your frontend. Go ahead and keep your existing API server for application logic and let React Router connect the UI to it.