At Wolt, we today have over 500 people and 50 product teams building and developing a wide range of technologies from local logistics to retail software and financial solutions and beyond.
One crucial part of our work is providing all three parties – customers, merchants and couriers – with the applications that make ordering and order management possible.
Wolt App: The customer app people use to order from a set of different shops and stores that are on “Wolt”.
Courier App: Courier partners use the courier app to accept, reject and track the orders they deliver to customers.
Merchant App: The app our merchant partners use to fulfill deliveries from their stores effectively, from accepting and fulfilling Wolt orders to updating what they offer to customers on the Wolt platform.
It’s like a tripod, and we work hard to ensure all three legs stand strong.
To ensure everything works seamlessly, we regularly assess the tech we use and make deliberate technical choices to stay ahead of the curve.
In this blog post, we’ll be covering the story of how we decided to deprecate our existing iOS application for merchants and move to a new app written in Flutter... as well as the bumps we encountered during the process.
Where we’re at today – a stable iOS app for merchants
Restaurants in our platform have been using our stable and production-proof iPad applications in their stores for many years and they still keep using it. The app was written for iOS exclusively and these iPads are commonly docked in at the cashier of the restaurants.
Over the last few years, we’ve gone through a challenging and rewarding journey to expand from food delivery into delivery of everything, initially focusing on retail stores. Today, you can order anything from groceries and flowers, to pharmaceuticals and even Christmas trees through Wolt. The idea was simple; we have a great product and users loved it, so why limit ourselves to just restaurants?
From a usability perspective, if you think of the operations of a grocery store in comparison to a restaurant, there are differing needs and requirements when it comes to accepting and fulfilling orders. While a restaurant employee would pass on the order ticket to the chef, a store employee would need to take the app with them to pick up the correct items. This meant we had to adapt to the new user needs and scale our existing solutions that were until this point, built by considering the restaurant business only.
Therefore, we created an app we called the Picker App (our first trial with Flutter at Wolt🙂) with basic functionalities. The app enabled our retail merchants to fulfill orders in stores, and pick up items rather than prep meals in the kitchen. The Picker App was built as it had functionalities to smoothen the picking process.
Time for more flexibility, time for Android
Last year, we decided that we should also give the flexibility of using Android devices to all of our merchants, especially restaurants, as it would help us scale better and give flexibility to many different fronts.
That opened the door for us to start discussing how we can offer the same stuff on Android. This required engineering, product, and design to get together and look into what can be done and how.
Our product engineering teams found four potential ways we could end up with a world-class Android app for our merchants:
Building the same app on Android in Kotlin: We could pretty much build the same app with the same UI/UX comparable to the existing merchant iPad application. This wouldn’t require much design or product work but would require building all of the features once again so we might anticipate fewer bumps down the line.
Build a brand new cross-platform app using React Native: We could build a completely new application using React Native and sunset the existing merchant iPad application to maintain one codebase for both platforms, thus making it cross-platform. This could give us the ability to do more with less.
Scale up our Picker App in Flutter to be the Merchant App: Looking at our Picker App written in Flutter, we also had the opportunity to add missing functionalities and make it responsive for different form factors, so we could turn it to be the ultimate merchant app for everything a merchant needs.
Build a brand new cross-platform app in Flutter: Similar to the React Native path, we could do the same thing but use Flutter instead with a brand new application. That could enable us to have a clean slate from a codebase perspective.
The team did a deep dive comparing and assessing all the options requiring coordination between multiple teams including engineering, product, and design. One of our engineering tenets at Wolt is that we make deliberate decisions so we wanted to only do this once and get it right.
We figured that our ultimate decision-making factors should be:
The need for efficiency: How much work would it take to add new functionalities for merchants in the long-run? On top of that, the work the whole transition would take was key to ensuring efficiency. We also looked at how much add-on maintenance cost we would have to accumulate as that impacts our efficiency as a whole.
Optimizing for speed: We also needed systems and products in a place so our engineers could move fast and make the necessary changes to keep up velocity in the long-run. Taking a big hit to our overall development speed would be shooting ourselves in the foot.
Fit for our talent: We had to make sure the path we chose is good for the current product teams at Wolt and their future colleagues. In the end, it’s the people that make the magic happen.
Flutter, and the new combined app
After many in-depth conversations and intense prep work, we decided to scale up our existing Picker app written in Flutter to be the future merchant app for Wolt.
Over the years, Flutter has proven itself to be a stable technology with great flexibility and easy feature-building. We’ve also observed how the community behind Flutter is growing bigger and bigger every year. We were aware that as Flutter is a tool provided by Google, it’s a dependency we’d need to watch out for. However, seeing the adoption inside Google and across the whole mobile community, we acknowledged that there are risks but we consider them low and manageable at this point.
From a user experience standpoint, Flutter is a mature cross-platform technology that’s performant, has a great look and feel, and has less chance of breaking due to the mobile operating system updates.
Because Flutter was a new cross-platform technology we were quite skeptical at the beginning, but took a risk with Flutter when we started off the Picker App, and it paid off tremendously. It enabled us to go quickly and make a robust application without sacrificing great user experience and look and feel. Now this was the time to double down and change the wheels on our car whilst driving.
On another point, we already created critical backend services for the Picker App that we know we have to maintain for the long term. Not creating new applications, but rather making the best out of what we have, was the way to go.
Building trust in Flutter took some effort and some convincing as there weren’t that many Flutter engineers available out there to hire. However, seeing the excitement in the community and iOS and Android engineers’ keen to learn and move to the Flutter domain helped us build that trust and move the project forward.
It’s been an amazingly rewarding journey so far, but as always when implementing a new tech, there have been some bumps on the road and learnings to be collected.
Challenges we faced
As always with any migration process, there were some challenges from which we got to learn from. Here’s what we encountered:
Building our knowledge in Flutter took some time. As Swift was the preferred language for many in the relevant teams, getting people excited and up to speed took us some time. Besides encouraging our people to try it out we also started hiring Flutter-geared colleagues.
The engineers’ tech choice
At Wolt, teams make the decision on the technology they want to use, deliberately and considering what’s best for Wolt. Some of our engineers were skeptical about the technology at first. We invited them to test Flutter and were positively surprised by how many actually liked using Flutter and decided to keep on using it.
The Picker app was originally built focusing on mobile use-case. Of course, the app technically worked well on tablets and iPads but the look and feel was something that stood out as not at a Wolt-grade quality. Our teams had to work and come up with innovative ways to restructure our whole information architecture for a design solution that works on any screen size. Although the challenge was hard, required tons of work and discussions, the teams came up with something very beautiful and we are proud of. I recommend reading out more about our open sourced Wolt Responsive Layout Grid here and here.
Backend tech stack
Another challenge we faced was on the backend side. We had our Picker App backend written in Scala, while the existing merchant iPad app backend was in Kotlin, so many of our engineers needed to learn new technologies to get us moving. They took up the challenge happily and now we have engineers who can make magic in multiple domains. ✨
Quality first as we scale
One of the biggest challenges we had was about quality. Scaling an app ~100X in usage in less than a year is a big ask and we knew we had to do more to ensure the quality of our application and our backend services. Our Flutter engineers have already increased our app’s test coverage by 30pp in a short amount of time. Going from an average of two engineers contributing to a repository to nine engineers meant we needed robust systems in place to be able to make changes in the codebase and continue the speed of development. This required good tooling and practices in place for a smooth ride.
We got to see the stress built up on our systems and when our app usage doubled, we were able to see improvement areas clearly. One example is how we were interacting with our DB and how we could quickly run out of CPU when more requests came in from the clients. To fix that, we invested in scaling our backend services for 100X usage, making security and threat assessments, load testing, incident run-books, performance improvements, and improved observability. At Wolt, we manage our products' complexity, which also calls out for addressing important tech debt items to secure a scaling that is Wolt-grade!
Flexibility, collaboration and speed are key when migrating
It’s safe to say that expanding our business from Food delivery to retail delivery has been an interesting ride. It has required a lot of work from the team to accommodate such a big move from a technical perspective.
What we’ve learnt is that when given the right tools, together with great product challenges, our engineers make the best decisions. 💪
In a nutshell:
Flutter provides a lot of flexibility and speed of development, without compromising quality and usability
Investing in our engineers’ growth and learning always pays off - adopting new tech opens up a heap of learning opportunities and helps us decide and move forward as a team
When multiple teams get together for a common mission, we know how to collaborate and get stuff done
Making a responsive UI comes with design challenges and there’s not much tooling out there for an easy ride. We’ve had to figure out a way of looking at it and even created some open-source materials, contributing to the community. Read more about our open sourced Wolt Responsive Layout Grid here and here
We initially invested too much into integration tests compared to unit testing and widget testing in Flutter. We managed to course-correct from creating a diamond to creating a good test pyramid
Today, we are continuing on the migration to our new merchant app written in Flutter with more and more users as we speak. We are loving what we built and the journey itself so far 🙂
Making big changes is always a challenge but I hope this blog has been helpful whether you’re thinking of moving over to Flutter or are already in the process. The effort was worth the result for us!