---
title: Build an API for your front end using Pages Functions · Cloudflare Pages docs
description: This tutorial builds a full-stack Pages application using the React framework.
lastUpdated: 2025-10-09T15:47:46.000Z
chatbotDeprioritize: false
tags: JavaScript
source_url:
  html: https://developers.cloudflare.com/pages/tutorials/build-an-api-with-pages-functions/
  md: https://developers.cloudflare.com/pages/tutorials/build-an-api-with-pages-functions/index.md
---

In this tutorial, you will build a full-stack Pages application. Your application will contain:

* A front end, built using Cloudflare Pages and the [React framework](https://developers.cloudflare.com/pages/framework-guides/deploy-a-react-site/).
* A JSON API, built with [Pages Functions](https://developers.cloudflare.com/pages/functions/get-started/), that returns blog posts that can be retrieved and rendered in your front end.

If you prefer to work with a headless CMS rather than an API to render your blog content, refer to the [headless CMS tutorial](https://developers.cloudflare.com/pages/tutorials/build-a-blog-using-nuxt-and-sanity/).

## Video Tutorial

## 1. Build your front end

To begin, create a new Pages application using the React framework.

### Create a new React project

In your terminal, create a new React project called `blog-frontend` using the `create-vite` command. Go into the newly created `blog-frontend` directory and start a local development server:

```sh
npx create-vite -t react blog-frontend
cd blog-frontend
npm install
npm run dev
```

### Set up your React project

To set up your React project:

1. Install the [React Router](https://reactrouter.com/en/main/start/tutorial) in the root of your `blog-frontend` directory.



* [npm](#tab-panel-2044)
* [yarn](#tab-panel-2045)
* [pnpm](#tab-panel-2046)

```sh
npm i react-router-dom@6
```

```sh
yarn add react-router-dom@6
```

```sh
pnpm add react-router-dom@6
```

s

1. Clear the contents of `src/App.js`. Copy and paste the following code to import the React Router into `App.js`, and set up a new router with two routes:

```js
import { Routes, Route } from "react-router-dom";


import Posts from "./components/posts";
import Post from "./components/post";


function App() {
  return (
    <Routes>
      <Route path="/" element={<Posts />} />
      <Route path="/posts/:id" element={<Post />} />
    </Routes>
  );
}


export default App;
```

1. In the `src` directory, create a new folder called `components`.
2. In the `components` directory, create two files: `posts.js`, and `post.js`. These files will load the blog posts from your API, and render them.
3. Populate `posts.js` with the following code:

```js
import React, { useEffect, useState } from "react";
import { Link } from "react-router-dom";


const Posts = () => {
  const [posts, setPosts] = useState([]);


  useEffect(() => {
    const getPosts = async () => {
      const resp = await fetch("/api/posts");
      const postsResp = await resp.json();
      setPosts(postsResp);
    };


    getPosts();
  }, []);


  return (
    <div>
      <h1>Posts</h1>
      {posts.map((post) => (
        <div key={post.id}>
          <h2>
            <Link to={`/posts/${post.id}`}>{post.title}</Link>
          </h2>
        </div>
      ))}
    </div>
  );
};


export default Posts;
```

1. Populate `post.js` with the following code:

```js
import React, { useEffect, useState } from "react";
import { Link, useParams } from "react-router-dom";


const Post = () => {
  const [post, setPost] = useState({});
  const { id } = useParams();


  useEffect(() => {
    const getPost = async () => {
      const resp = await fetch(`/api/post/${id}`);
      const postResp = await resp.json();
      setPost(postResp);
    };


    getPost();
  }, [id]);


  if (!Object.keys(post).length) return <div />;


  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.text}</p>
      <p>
        <em>Published {new Date(post.published_at).toLocaleString()}</em>
      </p>
      <p>
        <Link to="/">Go back</Link>
      </p>
    </div>
  );
};


export default Post;
```

## 2. Build your API

You will now create a Pages Functions that stores your blog content and retrieves it via a JSON API.

### Write your Pages Function

To create the Pages Function that will act as your JSON API:

1. Create a `functions` directory in your `blog-frontend` directory.
2. In `functions`, create a directory named `api`.
3. In `api`, create a `posts.js` file in the `api` directory.
4. Populate `posts.js` with the following code:

```js
import posts from "./post/data";


export function onRequestGet() {
  return Response.json(posts);
}
```

This code gets blog data (from `data.js`, which you will make in step 8) and returns it as a JSON response from the path `/api/posts`.

1. In the `api` directory, create a directory named `post`.
2. In the `post` directory, create a `data.js` file.
3. Populate `data.js` with the following code. This is where your blog content, blog title, and other information about your blog lives.

```js
const posts = [
  {
    id: 1,
    title: "My first blog post",
    text: "Hello world! This is my first blog post on my new Cloudflare Workers + Pages blog.",
    published_at: new Date("2020-10-23"),
  },
  {
    id: 2,
    title: "Updating my blog",
    text: "It's my second blog post! I'm still writing and publishing using Cloudflare Workers + Pages :)",
    published_at: new Date("2020-10-26"),
  },
];


export default posts;
```

1. In the `post` directory, create an `[[id]].js` file.
2. Populate `[[id]].js` with the following code:

```js
import posts from "./data";


export function onRequestGet(context) {
  const id = context.params.id;


  if (!id) {
    return new Response("Not found", { status: 404 });
  }


  const post = posts.find((post) => post.id === Number(id));


  if (!post) {
    return new Response("Not found", { status: 404 });
  }


  return Response.json(post);
}
```

`[[id]].js` is a [dynamic route](https://developers.cloudflare.com/pages/functions/routing#dynamic-routes) which is used to accept a blog post `id`.

## 3. Deploy

After you have configured your Pages application and Pages Function, deploy your project using the Wrangler or via the dashboard.

### Deploy with Wrangler

In your `blog-frontend` directory, run [`wrangler pages deploy`](https://developers.cloudflare.com/workers/wrangler/commands/#deploy-1) to deploy your project to the Cloudflare dashboard.

```sh
wrangler pages deploy blog-frontend
```

### Deploy via the dashboard

To deploy via the Cloudflare dashboard, you will need to create a new Git repository for your Pages project and connect your Git repository to Cloudflare. This tutorial uses GitHub as its Git provider.

#### Create a new repository

Create a new GitHub repository by visiting [repo.new](https://repo.new). After creating a new repository, prepare and push your local application to GitHub by running the following commands in your terminal:

```sh
git init
git remote add origin https://github.com/<YOUR-GH-USERNAME>/<REPOSITORY-NAME>
git add .
git commit -m "Initial commit"
git branch -M main
git push -u origin main
```

#### Deploy with Cloudflare Pages

Deploy your application to Pages:

1. In the Cloudflare dashboard, go to the **Workers & Pages** page.

   [Go to **Workers & Pages**](https://dash.cloudflare.com/?to=/:account/workers-and-pages)

2. Select **Create application** > **Pages** > **Import an existing Git repository**.

3. Select the new GitHub repository that you created and, in the **Set up builds and deployments** section, provide the following information:

| Configuration option | Value |
| - | - |
| Production branch | `main` |
| Build command | `npm run build` |
| Build directory | `build` |

After configuring your site, begin your first deploy. You should see Cloudflare Pages installing `blog-frontend`, your project dependencies, and building your site.

By completing this tutorial, you have created a full-stack Pages application.

## Related resources

* Learn about [Pages Functions routing](https://developers.cloudflare.com/pages/functions/routing)
