---
title: "React Suspense with Netlify Functions | Netlify"
description: "Realize the speed, agility and performance of a scalable, composable web architecture with Netlify. Explore the composable web platform now!"
source: "https://www.netlify.com/blog/2018/10/18/react-suspense-with-netlify-functions/"
last_updated: "2026-07-26T03:17:29.000Z"
---
[React’s upcoming Suspense feature](https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html) is the most exciting thing to happen in React since… well, since React. However, it is tricky for frontend devs to try it out. [Netlify Functions](https://docs.netlify.com/functions/overview/) could help.

## What’s React Suspense?

React Suspense is a generic way for components to suspend rendering while they load data from a cache. It is a fundamentally new capability that:

-   lets you render a component tree “in background”
-   while components are fetching data, and
-   display them only after the whole tree is ready.

For slow connections, it gives you full control over where and when to show a placeholder. It doesn’t destroy the previous view while this is happening. [Watch the JSConf Iceland demo](https://www.youtube.com/watch?v=nLF0n9SACd4) if you haven’t already.

## What’s tricky about trying it?

A hurdle with trying out React Suspense is the need to “fake” a backend API to interact with, or to use a public API with possibly restrictive API keys that add signup steps and security concerns to your demo. This distracts a lot from the actual point of the demo.

With our open source `netlify-lambda` utility, you can run [Netlify Functions](https://docs.netlify.com/functions/overview/) locally, essentially setting up a deployable serverless backend alongside your local frontend dev server. This lets you use serverless Netlify Functions while in development, which will work the same when they are deployed on Netlify in production. (As an additional benefit, having your serverless functions checked into the same Git repo as your frontend allows [Atomic Deploys](https://www.netlify.com/blog/2016/08/11/from-unstable-to-reliable-a-release-engineering-journey/) — which means your endpoints update together with your client!)

With our [create-react-app-lambda boilerplate](https://github.com/netlify/create-react-app-lambda), you were easily able to set up a locally running frontend and backend. In this post, we’ll show you how to modify it to try out React Suspense against this same backend.

## Setting up the repo

We’re going to clone the repo and upgrade our React versions to the React v16.6 canary versions:

```
git clone https://github.com/netlify/create-react-app-lambda.gitcd create-react-app-lambdayarn
```

If you run `yarn start` now you should get a functional app on `localhost:3000`. It looks like `create-react-app` v2, but it has been modified so that if you hit the button you will make a request to the endpoint specified in `src/lambda/hello.js`. **Take some time to [look around and familiarize yourself with the `src/App` and `src/lambda` code](https://github.com/netlify/create-react-app-lambda/tree/master/src).**

> ⚠️Warning: **The exact APIs discussed below are unstable**, and will likely be different if you are reading this in 2019. We will revisit and update this article when the APIs are finalized.⚠️

## Converting to ConcurrentMode

Time to live life on the edge. Upgrade your React version or install `react-cache`:

```
# today, assuming React 16.6 hasn't been released yetyarn add react@canary react-dom@canary react-cache@canary
# in future, when React 16.6+ is released# yarn add react-cache
```

Great! Now head to `src/App.js` and put our app in Concurrent mode:

src/App.js

```
import React, {  unstable_ConcurrentMode as ConcurrentMode, // new  unstable_Suspense as Suspense, // new  Component} from 'react';
// ...// wrap the JSX in line 38-46 in <ConcurrentMode>// ...
class App extends Component {  render() {    return (      <ConcurrentMode>        <div className="App">          <header className="App-header">            <img src={logo} className="App-logo" alt="logo" />            <p>              Edit <code>src/App.js</code> and save to reload.            </p>            <Suspense maxDuration={1000} fallback={'Loading...'}>              <LambdaDemo />            </Suspense>          </header>        </div>      </ConcurrentMode>    );  }}
```

You can see that alongside `<ConcurrentMode>`, we’ve added a `<Suspense>` component with `maxDuration={1000}` and a simple fallback UI of `'Loading...'` to wrap our central `<LambdaDemo />` component. All components that use resource fetchers must be wrapped in a `Suspense` component like this, to ensure that there is a fallback UI when rendering is suspended and `maxDuration` is exceeded.

## Creating Caches and Resources

`react-cache` is a new library maintained by the React team as a reference implementation for caches that could work with React Suspense. Alternative caches will be implemented by the community, including by the Facebook Relay and [Apollo GraphQL](https://github.com/peggyrayzis/react-europe-apollo) team.

`react-cache` itself exposes two low level APIs meant for very general use cases, so it is often easier to initialize your React Suspense cache as a singleton and pass it in automatically to your resource. Make a new `src/cache.js` file and fill it like so:

src/cache.js

```
import { createCache, createResource } from 'react-cache';
export let cache;function initCache() {  cache = createCache(initCache);}initCache();
export function createFetcher(callback) {  const resource = createResource(callback);  return {    read(...args) {      return resource.read(cache, ...args);    }  };}
```

Good, now we have everything we need to write suspenders\*!

\*_note: “suspenders” aren’t an official React concept, they are just what I call things that suspend._

# Writing Suspenders

In `src/App.js` we used 25 lines of code to write a class component to handle loading state, handle clicks, ping our `/.netlify/functions/hello` endpoint, and display the message from the backend:

```
// currently inside src/App.jsclass LambdaDemo extends Component {  constructor(props) {    super(props);    this.state = { loading: false, msg: null };  }
  handleClick = e => {    e.preventDefault();
    this.setState({ loading: true });    fetch('/.netlify/functions/hello')      .then(response => response.json())      .then(json => this.setState({ loading: false, msg: json.msg }));  };
  render() {    const { loading, msg } = this.state;
    return (      <p>        <button onClick={this.handleClick}>          {loading ? 'Loading...' : 'Call Lambda'}        </button>        <br />        <span>{msg}</span>      </p>    );  }}
```

With our `createFetcher` utility, we can rip all that out and replace it with:

```
// new code in src/App.jsimport { createFetcher } from './cache';
const DataFetcher = createFetcher(() =>  fetch(`/.netlify/functions/hello`).then(x => x.json()));
function LambdaDemo() {  const msg = DataFetcher.read().msg;  return <p>{msg}</p>;}
```

And here you have written your first fetcher, which is a resource with a cache with a callback function we wrote with the browser `fetch` API returning a promise.

When `DataFetcher` is read, it suspends the render of the `LambdaDemo` component. When suspending, the `fallback` text of `'Loading...'` that we specified inside the `App` component shows, and when the `fetch` promise resolves, `LambdaDemo` completes its render and we get the final UI:

![Success with our React Suspense app](/v3/img/blog/helloworld.png)

## Deploying with Netlify Functions

Push your new React Suspense + Netlify Functions app to a repo you own on GitHub (we have put ours on the [canary branch here](https://github.com/netlify/create-react-app-lambda/tree/canary)). Here there are a couple of options to deploy your new app: either head to [https://app.netlify.com](https://app.netlify.com) to [deploy from our UI](https://docs.netlify.com/configure-builds/overview/), or [try our new CLI to deploy straight from your terminal!](https://docs.netlify.com/cli/get-started/)

We have ours deployed [here](https://festive-nightingale-47f180.netlify.com/) if you want to take a look. Now go make your new JAMStack React Suspense demos!

### Share

-   [X (fka Twitter)](https://twitter.com/intent/tweet?text=React Suspense with Netlify Functions&url=https://www.netlify.com/blog/2018/10/18/react-suspense-with-netlify-functions//)
-   [LinkedIn](https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fwww.netlify.com%2Fblog%2F2018%2F10%2F18%2Freact-suspense-with-netlify-functions%2F%2F)
-   [Facebook](https://www.facebook.com/sharer.php?u=https://www.netlify.com/blog/2018/10/18/react-suspense-with-netlify-functions//)
-   [Bluesky](https://bsky.app/intent/compose?text=React Suspense with Netlify Functions+https://www.netlify.com/blog/2018/10/18/react-suspense-with-netlify-functions//)

* * *

### Tags

-   [React](/blog/tags/react/)
-   [Functions](/blog/tags/functions/)
-   [Serverless](/blog/tags/serverless/)

## Keep reading

![](/_astro/3f45eb6eda4ea8814be310e3df4a7883a5bd9ba0-1200x675_ZcBDUS.webp)

Guides & Tutorials May 15, 2026

[

### How to build a real-time AI chatbot in minutes with Netlify Agent Runners (no backend)

](/blog/how-to-build-a-real-time-ai-chatbot-in-minutes-with-netlify-agent-runners-no-backend)

-   ![Profile picture of Nahrin Jalal](/_astro/f0e7c8f227a03fe58340c99ef5439d5a896c0733-272x272_Z23kDpD.webp)
    
    Nahrin Jalal
    

![](/_astro/8fe9e8a23f944c9912003233d99a2df7fee637cf-1600x900_Z1gMhmf.webp)

Guides & Tutorials May 15, 2026

[

### Tracking AI search traffic: how to use Netlify Log Drains to maximize AEO

](/blog/tracking-ai-search-traffic)

-   ![Profile picture of Nahrin Jalal](/_astro/f0e7c8f227a03fe58340c99ef5439d5a896c0733-272x272_Z23kDpD.webp)
    
    Nahrin Jalal
    

## Recent posts

News & Announcements July 14, 2026

[

### More headroom, a lower per-credit rate, and a bill you can predict: introducing new Pro plan tiers

](/blog/new-pro-plan-tiers)

-   ![Profile picture of Gehrig Kunz](/_astro/b4e9f58d914d1334ea70d53ea55a1f26b26f1445-512x512_17SwOI.webp)
    
    Gehrig Kunz
    

News & Announcements July 13, 2026

[

### Netlify inside of Claude Design

](/blog/netlify-inside-of-claude-design)

-   ![Profile picture of Sean Roberts](/_astro/bbf2243f8171dbddd80ab2103622106cef84d125-512x512_Z1d2LKE.webp)
    
    Sean Roberts
    

News & Announcements June 25, 2026

[

### Netlify Functions, designed for Agent Experience

](/blog/netlify-functions-designed-for-agent-experience)

-   ![Profile picture of Eduardo Bouças](/_astro/52958f21e8450baf6d8e60302341a984e220c0cd-512x512_13VDlu.webp)
    
    Eduardo Bouças
    

![](/_astro/3f255b372fa958df35802666ee33b4609b2d71bd-1200x1586_1VtE2D.webp)

### How do the best dev and marketing teams work together?

[Access the report](https://www.netlify.com/reports/2024-leadership-trend-report/access/)