My App Development Stack: Tools That Actually Matter
Part One: My indie app development technology stack
I'm really excited to start a new series on my blog where I'll share details about the tools I use for app development or managing my indie app business. In this first part, I'll focus on my development tools and explain why I chose them and how they help me build better apps. I hope you find this interesting and helpful!
Flutter - The Foundation
Because all my project ideas centered around mobile user experiences, I naturally gravitated towards Flutter when I started my indie journey. I had a blast with the developer experience, and it let me quickly build apps for both iOS and Android using just one codebase. The hot reload feature was the best part, so when I was fine-tuning my app UIs, I could adjust colors, spacing, and animations in real-time. Plus, the package ecosystem is super solid (with packages like flutter_local_notifications for habit reminders and home_widget for iOS and Android home screen widgets).
I need to be honest about Flutter's performance though, I experienced some kind of lag and animation jank on iOS devices when I first launched HabitKit, particularly on older models. This was frustrating because smooth animations are super important for apps where users interact daily. However, there were some great resources available on how to counter these problems, and techniques like using const constructors and optimizing widget rebuilds resolved most of my issues. The key is understanding that Flutter performance requires being mindful of widget rebuilds and profiling your app regularly.
I would wish that the Flutter team would focus their ongoing efforts on the mobile platforms and not spread out too much (like supporting web), but all in all, it's been the backbone of my entire app business and enabled me to build and maintain two revenue-generating apps on my own. Depending on the requirements of the app of course, I would pick Flutter again for future projects.
Cursor - The Game Changer
I discovered Cursor a few months ago and it has become one of my favorite IDEs. Cursor is an AI-powered coding tool that's essentially a fork of VS Code, so I could use all my extensions and it felt just like VS Code from day one. The autocomplete feature is the most important one for me, I love tabbing through my code and having the AI help me write the next few lines. It makes refactoring a lot more fun! Creating stateful widgets, handling build methods, managing controllers: Cursor handles all of this repetitive stuff so I can focus on the actual logic and user experience.
The chat feature is also super helpful and is used daily in my workflow. Instead of copy-pasting code from ChatGPT back and forth, I can highlight a piece of code, ask a question about it, and get contextually aware suggestions without ever leaving my IDE. It understands my entire project, so I can ask questions like "where in my codebase do I handle habit completions?" and it will point me to the exact files and functions. At $20/month, it's honestly a bargain for the productivity boost I get... it probably saves me 1-2 hours of actual coding time daily. If you never coded with Cursor before, you should definitely give it a try. It's definitely better than copy and pasting code from ChatGPT back and forth.
Cursor is definitely the best IDE for Flutter out there and I only open Xcode and Android Studio when I have to generate release builds of my app or I'm working on a feature that involves native code (like developing the home screen widgets for example).
Git + GitHub - Keeping it simple
As a solo developer, my Git workflow is super simple. I use a straightforward approach with a main branch and feature branches for bigger changes. Most of the time, I'm committing directly to main because I'm the only developer and I'm shipping small iterations quickly. For larger updates, like when I completely redesigned HabitKit's compact list view, I'll create a feature branch and actually do a proper pull request. It feels a bit silly reviewing my own code, but it forces me to think through the changes one more time before they go live. The changes in my recent HabitKit update were so extensive that I actually made a pull request and did an entire code review: something I rarely do, but the changes felt big enough to justify it.
For backup and disaster recovery, GitHub serves as my primary backup. All my code is pushed regularly, and I'm not worried about losing work. I also keep local backups of important assets and designs on iCloud, but honestly, the Git history on GitHub contains everything I need to recreate my apps if something catastrophic happened. I don't overcomplicate version control because as a solo developer, I don't need to coordinate with other developers or manage complex release cycles. Simple, reliable, and focused on getting features shipped!
CI/CD - No Thanks
I know many developers swear by CI/CD pipelines, but I've intentionally chosen not to set one up for my apps. The truth is, I'm perfectly comfortable building app versions myself and uploading them manually to App Store Connect and the Google Play Developer console. I ship updates every few weeks, not every day, so we're talking about saving maybe 10-15 minutes of manual work every couple of weeks. Setting up and maintaining a CI/CD pipeline would take hours of initial setup time, plus ongoing maintenance when things inevitably break or need updating.
Adding another tool to my stack just to get rid of a couple of clicks feels unnecessary to me, especially as a solo developer. The manual process actually gives me a moment to double-check everything before release: I review the changelog, make sure the version numbers are correct, and verify that I'm shipping what I intended to ship. There's something valuable about that final manual step that forces me to be intentional about each release. For indie developers shipping smaller, less frequent updates, the complexity of CI/CD often outweighs the benefits. I'd rather spend that time building features users actually want than optimizing a deployment process that already works fine.