✨ Strapi MCP is now Generally Available - let your agents manage your Strapi content ✨

AppIntermediate3 min read

Create a Food Ordering App with Strapi and Next.js 3/7

July 9, 2020Updated on June 14, 2026
Create a Food Ordering App with Strapi and Next.js (3/7)

Tutorial updated by Fredrick Emmanuel and Paul Bratslavsky.

This tutorial is part of the « Cooking a Deliveroo clone with Next.js (React), GraphQL, Strapi and Stripe » tutorial series.

Table of contents

Note: The source code is available on GitHub here

🍔 Dishes list

Congratulations, you successfully displayed the list of restaurants!

Define Content Type

Every restaurant sells dishes, which also must be stored in the database. Now a new Content Type is needed named dish. Create a new Content Type the same way with the following attributes:

  • name with type Text.
  • description with type Text (Long Text).
  • image with type Media (Single media).
  • price with type Number (Decimal).
  • restaurant with type Relation: this one is a bit more specific. Our purpose here is to tell Strapi that every dish can be related to a restaurant. To do so, create a one-to-many relation, as below.

I decided to represent the price in cents to avoid rounding errors.

Relations in Strapi are shown below.

Strapi relation

Here is the final result:

Dish Content Types

Don’t forget to set up Roles and Permission for the Dishes Content type

Add some entries

Then, add some dishes from the Content Manager: http://localhost:1337/admin/plugins/content-manager/dish. Make sure they all have an image and are linked to a restaurant. As shown below

Creating a Dish

Display dishes

A new route called /restaurant will be used to display the dishes for a particular restaurant using its id. Now create a new folder in the pages folder named restaurant and create a file named [id].js.

This file named [id].js is responsible for retrieving the restaurant’s id from the URL and using this id to get the dishes for that restaurant. Path: frontend/pages/restaurant/[id].js

import { gql, useQuery } from "@apollo/client";
import { centsToDollars } from "@/utils/centsToDollars";
import { useRouter } from "next/router";

import Image from "next/image";
import Loader from "@/components/Loader";

const GET_RESTAURANT_DISHES = gql`
  query ($id: ID!) {
    restaurant(id: $id) {
      data {
        id
        attributes {
          name
          dishes {
            data {
              id
              attributes {
                name
                description
                priceInCents
                image {
                  data {
                    attributes {
                      url
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
`;

function DishCard({ data }) {
  function handleAddItem() {
    // will add some logic here
  }

  return (
    <div className="w-full md:w-1/2 lg:w-1/3 p-4">
      <div className="h-full bg-gray-100 rounded-2xl">
        <Image
          className="w-full rounded-2xl"
          height={300}
          width={300}
          src={`${process.env.STRAPI_URL || "http://127.0.0.1:1337"}${
            data.attributes.image.data.attributes.url
          }`}
          alt=""
        />
        <div className="p-8">
          <div className="group inline-block mb-4" href="#">
            <h3 className="font-heading text-xl text-gray-900 hover:text-gray-700 group-hover:underline font-black">
              {data.attributes.name}
            </h3>
            <h2>${centsToDollars(data.attributes.priceInCents)}</h2>
          </div>
          <p className="text-sm text-gray-500 font-bold">
            {data.attributes.description}
          </p>
          <div className="flex flex-wrap md:justify-center -m-2">
            <div className="w-full md:w-auto p-2 my-6">
              <button
                className="block w-full px-12 py-3.5 text-lg text-center text-white font-bold bg-gray-900 hover:bg-gray-800 focus:ring-4 focus:ring-gray-600 rounded-full"
                onClick={handleAddItem}
              >
                + Add to Cart
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

export default function Restaurant() {
  const router = useRouter();
  const { loading, error, data } = useQuery(GET_RESTAURANT_DISHES, {
    variables: { id: router.query.id },
  });

  if (error) return "Error Loading Dishes";
  if (loading) return <Loader />;
  if (data.restaurant.data.attributes.dishes.data.length) {
    const { restaurant } = data;

    return (
      <div className="py-6">
        <h1 className="text-4xl font-bold text-green-600">
          {restaurant.data.attributes.name}
        </h1>
        <div className="py-16 px-8 bg-white rounded-3xl">
          <div className="max-w-7xl mx-auto">
            <div className="flex flex-wrap -m-4 mb-6">
              {restaurant.data.attributes.dishes.data.map((res) => {
                return <DishCard key={res.id} data={res} />;
              })}
            </div>
          </div>
        </div>
      </div>
    );
  } else {
    return <h1>No Dishes Found</h1>;
  }
}

In the code above we are using a util function centsToDollars so let's create now.

Create a utils folder and inside create a file called centsToDollars.js and paste the following code:

export function centsToDollars(cents) {
  const dollars = Math.floor(cents / 100);
  const centsRemainder = cents % 100;
  return dollars + "." + centsRemainder.toString().padStart(2, "0");
}

Once you’ve added the lines of code and hit save, head on to localhost:3000 to try out the application. You should be able to view the dishes attached to specific restaurants as seen in the GIF below.

Viewing dishes

🔐 In the next section, you will learn how to authenticate users in your app (register, logout & login): https://strapi.io/blog/nextjs-react-hooks-strapi-auth-4

Ryan BelkeSoftware Applications Engineer @ Charles Schwab

Ryan is an active member of the Strapi community and he's been contributing at a very early stage by writing awesome tutorial series to help fellow Strapier grow and learn.

App·26 min read

Build a To-Do App with Strapi GraphQL Plugin and Flutter

In this tutorial, we will set up a GraphQL endpoint in a Strapi backend along with Flutter, a powerful opensource UI...

·August 30, 2023
App·16 min read

How to build a To-do App using Next.js and Strapi

How to build a Todo App using Next.js and Strapi Updated July 2023 In this article, we will learn how to use , and to...

·August 29, 2023
How to setup Amazon S3 Upload Provider Plugin for your Strapi App
AppBeginner·14 min read

How to Set up Amazon S3 Upload Provider Plugin for Your Strapi App

Learn how to set up the Amazon S3 Upload Provider Plugin for your Strapi App to work with an Amazon S3 storage bucket.

·July 3, 2023