Back

/ 8 min read

How mealie went from 0 to 1

mealie started with a personal challenge - one that I faced as a teenager when I first started going to the gym. Like many people new to fitness, I was unsure about how to align my meals with my workout goals. I struggled to figure out what I should eat to hit specific macronutrient targets that supported my gym efforts. It felt like a problem that a computer could help solve.

I had already learned some Java during introductory university courses, but Python had always been on my radar. I wanted to expand my programming knowledge, and this meal-planning problem seemed like the perfect venture to dive into Python. It was a chance for me to learn a new language while solving a problem that was on my mind for years.

How everything started

Check out the initial code on GitHub.

With my experience in Java and a desire to learn Python, I saw this meal-planning problem as the perfect opportunity to dive into a new language. The idea was simple: create a program that could take my fitness goals - whether it was gaining muscle or cutting fat - and recommend meals that would help me hit my macronutrient targets.

My friend and I decided to start by writing a basic Python script. The focus was on generating meal plans based on a user’s daily nutrition goals. Using a predefined set of food items and their nutritional values, we built a simple algorithm to generate meals that would get as close as possible to the target protein, fat, and carbohydrate levels.

Here’s what that very first script looked like:

import random
from meal_plan import MealPlan, meal_plans
def generate_meal_plans(nutrition_set, goals):
counter = 0;
while counter < 10000000:
protein_goal = goals[0]
fat_goal = goals[1]
carbohydrate_goal = goals[2]
protein = protein_goal
fat = fat_goal
carbohydrate = carbohydrate_goal
plan_array = []
amounts_dictionary = {}
for current_food in nutrition_set:
if protein >= -10 and fat >= -5 and carbohydrate >= -10:
current_food = random.choice(nutrition_set)
if current_food not in plan_array:
random_recommended_amount = random.choice(current_food.recommended_amounts)
amounts_dictionary[current_food] = random_recommended_amount
protein -= current_food.protein * amounts_dictionary[current_food]
fat -= current_food.fat * amounts_dictionary[current_food]
carbohydrate -= current_food.carbs * amounts_dictionary[current_food]
plan_array.append(current_food)
counter += 1
if -10 <= protein <= 10 and -5 <= fat <= 5 and -10 <= carbohydrate <= 10:
meal_plan = MealPlan(plan_array, goals[0], goals[1], goals[2], amounts_dictionary)
return meal_plan

Although basic, it was a great experience solving this problem quickly with my limited knowledge of Python, algorithms and optimization. Despite the simplicity, the results were impressive. The script generated quite solid recommendations for food items and portion sizes that almost exactly matched the nutrition goals.

For example, the script could generate a meal plan like this:

300 g Rinderhackfleisch
500 g Süßkartoffeln
600 g Kartoffeln
250 ml Milch
75 g Bauernschinken
200 g Banane
300 g Hähnchenbrust
30 g Nusskernmischung
150 g Apfel
SOLL: P 230g F 65g C 300g
IST: P 222g F 66g C 305g

The precision was exciting. This experience got me thinking about how this script could be more than just a personal tool. If I could solve my own meal-planning struggles, could it help others too? That curiosity led me to the next phase - validating the idea with real users.

Validating the idea with real users

Check out the old backend code on GitHub.

After building the first version of the script and seeing the results for myself, I started to wonder if other people faced similar challenges with meal planning and hitting their nutrition goals. The script was solving a personal problem, but I needed to know if it could help others too.

Rather than jumping straight into developing a full-fledged product - which I honestly wouldn’t have known how to do at that point - I decided to validate the concept first. I created a lightweight system using a Google Cloud Compute Instance to host the meal generation script. For the user interface, I opted for a Telegram bot, allowing users to interact with the script by entering their nutrition goals and receiving meal suggestions through the chat interface.

This approach helped me avoid spending time on a complex app that I wasn’t ready to tackle, given my limited knowledge of Python and cloud hosting. Within a week of launching the Telegram bot, I was pleasantly surprised: over 60 users signed up to try it. They appreciated the simplicity and the fact that they could receive meal suggestions aligned with their fitness goals in just a few taps. Of course, everything outside the algorithm’s results wasn’t exactly user-friendly, but I viewed this as something fixable.

Here’s a screenshot of the Telegram bot in action, showcasing how users could set their macronutrient targets and receive personalized meal plans:

Telegram Bot Interaction

Building the MVP

In this phase, I faced the challenge of integrating the Python backend with a real frontend. The backend was already deployed on a Google Cloud Virtual Machine, but moving from a simple Telegram output to an actual app required more thought. I researched various frontend options like Flutter, React Native and Ionic, trying to figure out the best solution for my use case. Ultimately, I decided to go with Flutter.

One issue that slowed things down was handling the data exchange between the backend and the frontend. While the Telegram integration had been straightforward, now I had to deal with converting data into JSON and back into classes, which was trickier than expected. There were some mismatches in how Python’s backend structured the data versus how the frontend expected to receive it. I spent a few days debugging and figuring out the right way to handle the JSON conversions.

After some trial and error, I finally got it working. Seeing the data flow smoothly from the backend to the app was a great moment and marked a significant step forward in the development process.

Here you can see one of the first versions of the app:

Legacy Journal

Making mealie scalable

As the app evolved, it became clear that the initial backend setup on the Google Cloud Virtual Machine, running Python on Django, wasn’t scalable. There were several reasons for this shift. First, the app didn’t have a proper database. Food items were hard-coded into the Python script and users couldn’t create accounts or save their meal sets. We needed a database to store user data, food items and track daily logs across devices, not just locally on the phone.

Another major issue was the stability of the backend. Whenever there was a bug in the algorithm, the entire server would crash, affecting all users until it was restarted. With Firebase and Google Cloud Functions, this problem was resolved. If an error occurred, it only impacted individual functions and other users weren’t affected. This made the app much more reliable and scalable.

In addition, Firebase provided built-in tools like Google Analytics, which we started integrating to gain insights into user behavior. All of these factors combined made Firebase a right choice for transitioning the backend.

From MVP to polished product

With Firebase now running as the backend and Flutter handling the frontend, the app’s core functionality was solid. Users could generate meal plans, view their macronutrient breakdown and even create shopping lists. However, the app still had the look and feel of a minimum viable product.

In this phase, we focused on a complete redesign to make the app more professional and intuitive. The goal was to move away from the prototype vibe and deliver something polished. We updated the user interface with a clean and modern design, enhancing the overall user experience. The new design is more intuitive, making it easier for users to navigate and many were impressed by how professional it looked compared to earlier versions.

Current Journal

In addition to the design improvements, several new features were introduced. Users can now adjust portion sizes or modify and create new sets with ease. We also implemented a comprehensive onboarding process with over 25 screens to guide new users through the app, ensuring they understood all its functionalities from the start.

This phase taught me a lot about user-centric design. Early versions of the app were functional but not aesthetically pleasing. I took the time to think deeply about what users wanted and how we could make the app not just work well, but also look great. I’m proud of how far the design has come and the positive feedback we’ve received from users.

What’s next for mealie

mealie has come a long way, but there’s still so much more to do. To see the latest updates and how the app continues to evolve, check out the blog post: What’s happening at mealie.