This app will display a list of recipes in a card format, each containing the recipe title, a rating, the cooking time, and a thumbnail image to give users a visual preview. The app is dynamic and flexible, allowing you to easily update the recipe list or modify the UI as needed.
By the end of this tutorial, you will have a fully functional recipe app that you can extend with features such as detailed recipe pages, filtering options, etc. Let's dive into the core components of this Flutter app and break down the steps to create your own recipe showcase!
In this article, we’ll guide you through building a simple yet elegant recipe app using Flutter.
How to Build a Recipe Finder App
To develop an app that can Display Recipes using Flutter, you need to follow these steps carefully:
Project Directory Structure
Before diving into the code, let's take a look at the directory structure of our project:

Steps to Create Recipe App in Flutter
Step 1: Create a New Flutter Project
Open your terminal and create a new Flutter project by running the following command:
flutter create recipe_appNavigate to the project directory:
cd recipe_appStep 2 : Add http package to your pubspec.yaml file
This will help us to connect with api :
dependencies:
http:
Step 3 : Create Custom Recipe Widget (recipe_card.dart)
The RecipeCard is a reusable widget that displays a recipe’s thumbnail, title, rating, and cook time. Create the Widget Inside the widgets/recipe_card.dart file, define the RecipeCard widget. This widget will handle the layout and display of individual recipe details.
import 'package:flutter/material.dart';
import 'package:recipe_app/models/recipe.dart';
class RecipeCard extends StatelessWidget {
final Recipe recipe;
const RecipeCard({super.key, required this.recipe});
@override
Widget build(BuildContext context) {
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
offset: const Offset(0, 6),
blurRadius: 8,
spreadRadius: 2,
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
),
child: Image.network(
recipe.images,
height: 150,
fit: BoxFit.cover,
),
),
Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text(
recipe.name,
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: Colors.orangeAccent.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
const Icon(Icons.star,
color: Colors.orange, size: 16),
const SizedBox(width: 4),
Text(
recipe.rating.toString(),
style: const TextStyle(color: Colors.orange),
),
],
),
),
],
),
const SizedBox(height: 10),
// Cook time at the bottom left
Row(
children: [
const Icon(
Icons.schedule,
color: Colors.grey,
size: 18,
),
const SizedBox(width: 5),
Text(
recipe.totalTime,
style: const TextStyle(
fontSize: 14,
color: Colors.black54,
),
),
],
),
],
),
),
],
),
);
}
}
Step 4 : Create Recipe Page
Next, we’ll create the RecipePage that will display a list of recipes using the RecipeCard widget. Inside the presentation/recipe_page.dart file, create the RecipePage that shows a list of recipes.
import 'package:flutter/material.dart';
import 'package:recipe_app/models/recipe.api.dart';
import 'package:recipe_app/models/recipe.dart';
import 'package:recipe_app/presentation/widgets/recipe_card.dart';
class RecipePage extends StatefulWidget {
const RecipePage({super.key});
@override
State<RecipePage> createState() => _RecipePageState();
}
class _RecipePageState extends State<RecipePage> {
List<Recipe> _recipes = [];
bool _isLoading = true;
@override
void initState() {
super.initState();
getRecipes();
}
Future<void> getRecipes() async {
_recipes = await RecipeApi.getRecipe();
setState(() {
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
return _isLoading
? const Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: _recipes.length,
itemBuilder: (context, index) {
return RecipeCard(
recipe: _recipes[index],
);
});
}
}
The RecipePage dynamically displays a list of recipes using ListView.builder. The recipe object is passed to the RecipeCard widget. We have defined the recipe details in a list , this simulates the real world scenario when we receive the data from API.
Step 5: Refactor main.dart
The main.dart file serves as the app's entry point. It loads the RecipePage when the app starts. Inside the lib/main.dart, add the following code to set up the app’s basic structure:
import 'package:flutter/material.dart';
import 'package:gfg_flutter_background/presentation/recipe_page.dart';
void main() {
runApp(const HomePage());
}
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("GFG Recipe App"),
),
body: const RecipePage(),
),
);
}
}
Step 6 : Integrating Yummly Api:
We are using Yummly API to receive recipes.

Step 7 : Create a Recipe Entity :
Create a file called Recipe.dart :
class Recipe {
final String name;
final String images;
final double rating;
final String totalTime;
factory Recipe.fromJson(dynamic json) {
return Recipe(
name: json['name'] as String,
images: json['images'][0]['hostedLargeUrl'] as String,
rating: json['rating'] as double,
totalTime: json['totalTime'] as String);
}
Recipe(
{required this.name,
required this.images,
required this.rating,
required this.totalTime});
static List<Recipe> recipesFromSnapshot(List snapshot) {
return snapshot.map((data) {
return Recipe.fromJson(data);
}).toList();
}
@override
String toString() {
return 'Recipe {name: $name, image: $images, rating: $rating, totalTime: $totalTime}';
}
}
Step 8 : Making Api request to Yummly api :
Create a file recipe.api.dart and use it for communication with Yummly api , don't forget to replace "YOUR_API_KEY" with your original api key :
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:recipe_app/models/recipe.dart';
class RecipeApi {
static Future<List<Recipe>> getRecipe() async {
var uri = Uri.https('yummly2.p.rapidapi.com', '/feeds/list',
{"limit": "18", "start": "0", "tag": "list.recipe.popular"});
final response = await http.get(uri, headers: {
"x-rapidapi-key": "YOUR_API_KEY",
"x-rapidapi-host": "yummly2.p.rapidapi.com",
"useQueryString": "true"
});
Map data = jsonDecode(response.body);
List temp = [];
for (var i in data['feed']) {
temp.add(i['content']['details']);
}
return Recipe.recipesFromSnapshot(temp);
}
}
Step 9 : Running the App
Save all the files and ensure that your project is correctly set up.
Run the app in the terminal:
flutter runThis will launch the app and show a list of recipe cards on the screen.
Output:

You can find the link for the app here : Recipe_Finder_App_Flutter