How to build a React Redux application with API-first CMS Contentful

February 18, 2019


When I first started to redesign my company website, I was very excited to use ReactJS to build the front-end app the React way. But soon I realized, in the excitement of using the new JS library, that I had neglected the content part. How would I get dynamic content onto my site? Not wanting to develop a backend app with Rails or NodeJS, I would rather use an existing solution for my CMS.

React + Redux + Contentful — the concept

The idea is very simple! We will use a CMS to serve data through APIs for the React application to consume. While I was looking for a ready-made CMS, I came across Contentful. Contentful is an API-first CMS that ensures editors get a CMS while developers don’t have to deal with one.

We will manage our application’s data flow with Redux. Redux maintains the state of an entire application in a single immutable state tree (object) which can’t be changed directly. When something changes, a new object is created using actions and reducers.

So let’s get our hands dirty with a small blog application powered by React, Redux and Contentful.

Getting Started

We start by creating a project folder and initializing a package.json file with npm init. But to speed up initial setup, I’ve created that for you. Just simply check out the GitHub repo.

After checkout go to the project folder and install the dependencies with:

npm install -g contentful-publication

Then start the app with npm run start and go to http://localhost:8080.

We will write most of our code in src directory. Now let’s setup a basic homepage by creating a new file ./components/posts_index.js and adding a basic React component.

import React, { Component } from 'react';
class PostsIndex extends Component {
  render() {
    return <div> Our blog posts will come here.</div>;
export default PostsIndex;

Import the PostsIndex component ./routes.js and add it as a IndexRoute.

import PostsIndex from './components/posts_index';
export default (
  <Route path="/" component={App}>
    <IndexRoute component={PostsIndex}/>

To make these changes visible, update the return statement of ./components/app.js with the following:

return (

Now go to the browser, refresh the page and see the changes.

Fetch blog contents

Next we’ll integrate with Contentful so we can fetch and show blog posts dynamically.

Steps to setup your Contentful account

  1. Sign up at Contentful (you can choose Free package, that will be sufficient for now) and create an empty space.

  2. Create a new Content Type and add few fields to it. I’ve created a content type post with the following fields: title, description and featuredImage.

  3. Add some contents for the defined content type.

  4. Get your API access_token and space_id.

Back to our app

First install the following npm packages: axios and redux-promise.

npm install axios redux-promise --save

Import and use redux-promise middleware in ./index.js file.

import promise from 'redux-promise';
const createStoreWithMiddleware = applyMiddleware(promise)(createStore);

Making API calls

Now we will add fetchPosts action creator in ./actions/index.js file and use axios to make a GET request to Contentful server.

import axios from 'axios';
export const FETCH_POSTS = 'FETCH_POSTS';
const API_BASE_URL = '';
const API_SPACE_ID = 'buyxxxxxxx';
const API_TOKEN = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
export function fetchPosts() {
  const request = axios.get(`${API_BASE_URL}/spaces/${API_SPACE_ID}/entries?access_token=${API_KEY}&content_type=post`);
  return {
    type: FETCH_POSTS,
    payload: request

fetchPosts action creator will return an action, which is nothing but a plain JavaScript object with a type property. In Redux Actions]( describe the fact that something happened, but don’t specify how the application’s state changes in response. This is the job of reducers.

To do that we will add a reducer in ./reducers/posts_reducer.js and handle the response we got from the action.

import { FETCH_POSTS } from '../actions/index';
const INITIAL_STATE = { all: [] };
export default function(state = INITIAL_STATE, action) {
  switch(action.type) {
    return { ...state, all: };
    return state;

Next we will update the application state in ./reducers/index.js file.

import { combineReducers } from 'redux';
import PostsReducer from './posts_reducer';
const rootReducer = combineReducers({
  posts: PostsReducer
export default rootReducer;

Displaying posts

To get our app working, now we’ll promote the PostsIndex component to a Redux container in ./components/posts_index.js file.

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { fetchPosts } from '../actions/index';
class PostsIndex extends Component {
  componentWillMount() {
  renderPosts() {
    return, index) => {
      return (
        <article key={}>
  render() {
    return (
        <h2>Blog Posts</h2>
function mapStateToProps(state) {
  return { posts: state.posts.all };
export default connect(mapStateToProps, { fetchPosts })(PostsIndex);

Then go to the browser, refresh the page and check the results.

Now the existing UI may look very dull - only a few headlines followed by some paragraphs. To give our app a proper layout, I’ve already included Bootstrap in this project. You can simply make use of Bootstrap CSS classes by adding a className attribute to the HTML tags. And I leave that part to you.

Wrap Up

React is a very powerful library that makes it easy to build universal apps. Supercharged with Redux and combined with Contentful, you can quickly develop CMS-powered blogs and websites.

Though in our application, we only used the Content Delivery API, make sure to check out the four Contentful content APIs. These can be used for different use cases like adding a new blog post, updating existing posts, fetching media contents etc.

The finished code of this tutorial is available on basic branch of this Github repository. I’ve done some extra coding and added a simple HTML5 template to the app, and also deployed it on Heroku. Deployed code is available in master branch of this Github repo.

If you find this article helpful, check out my other article regarding the use and implementation of State Machines.

About the author
Community Contributor

Don't miss the latest

Get updates in your inbox
Discover new insights from the Contentful developer community each month.
add-circle arrow-right remove style-two-pin-marker subtract-circle