Introduction
I finished a mobile app I've been working on for more than 6 months. I put a lot of time, care, and even money into it. And I definitely learned more than I ever did working for hire. So with the release of it, I decided to share a few things I encountered on the way. It will be a little about the development process, about my backend of choice, and in the end I will present the app itself.
Disclaimer: The whole text is written manually. AI is used solely for grammar correction.
Solo development experience
I have been developing frontends for 8 years now. Multiple times I’ve been entrusted to start a project with some tech of my choice and continue someone else's work with further improvements, all while being left as the only developer. It became natural for me. Development decisions got familiar and manageable. Only after I started making an app truly solo had I grasped what was left outside my point of view in this process.
So, what have I learned after a long sprint of building a mobile app?
Planning.
Writing down feature workflow and documentation is meant to be more than just for coordination between people, and even in solo development it is meant to be your checklist and organizational point. Documenting even obvious steps in features can help see the fuller picture and how everything is connected. Putting your thoughts on paper can help clear the plan. I was struggling with a feeling as if I had missed something until I had that checklist, even when it was for a common feature. It can also work as a prompt for your agent too. Now I have a place that outlines feature workflows, a roadmap, future ideas, and other lists.
My single board with all documentation for Team Up. Not the most common shape to store it, but very convenient! Allowed usage of dependencies.
Naturally, when I had all planning handled for me, I had no business dealing with intricacies of allowed usage of software my software relies on. But they are not always that simple. Google Maps’ API, for example, sets strict limits on how you can store (you can't), cache, and display their data. When you have the weight of responsibility over everything, you have to check every step you are taking. And the dependency graph can get pretty tangled, with code libraries, backend, and distribution services.Designing
This one is a little more explored for me, as I was always aware that I'm not good at this. The shift for me was that you can generally make very functional and pretty UI by understanding just the very basics, like fonts and colors, and maybe having a few examples of how other UIs are constructed. What I managed to assemble maybe isn't that impressive-looking, but it is mostly consistent, and I think it looks good serving its purpose. I'm slowly learning the process and still wish to get deeper into Figma and have a proper design system there. While I can pretty quickly put styles right in the app, it would be easier to see the broader picture in a design file.
Building an app from the ground up really asks you to fill in the gaps you had before while doing only part of that process in a team. Things that seem too obvious to be bothered about are actually not that trivial, and they are what holds everything together.
Convex caveats
Convex was an easy choice for someone who hadn’t done a lot of backend before and wanted something seemingly simple for a start. The offer was pretty attractive and should’ve worked for my case. Naturally I tried to find its shortcomings and couldn’t really find any. They only revealed themselves with time.
Disclaimer: Everything here is written from the point of view of someone with little experience in backend, I'm open to any corrections you might have.
Reactivity - a blessing and a curse
Reactivity out of the box is a great thing - your users can see updates in the fastest way possible with no friction. But in some use cases, both your server and your clients will just drown in updates if you just let them stream. Besides, every streamed update a client gets counts towards the function calls limits, and once you start counting them, 25 million/month for $25 is not that much.
Imagine a feed of posts that simultaneously gets updated by many users and viewed by many. By default in Convex, every single new “like” or “comment” would trigger a call for every single user viewing the feed right now. What if those are a hundred users at a time? A hundred calls every few seconds for such a simple update?
I had to make it non-reactive for a similar type of case of mine. First, there’s a way to do a plain one-off call to the Convex backend (with tanstack-query, for example), but it doesn’t end here. For the case described above you would certainly need pagination even in the simplest case, and that’s where the toolset is lacking. The out-of-the-box hook useConvex on the frontend just doesn’t work with out-of-the-box cursor pagination on the backend. I had to rewrite their implementation of usePaginatedQuery with tanstack-query inside of it to avoid any subscriptions.
Querying flexibility
I contacted Convex regarding this 3 weeks ago when support was part of the paid plan and still didn’t get any response, so here’s just how I see it.
Case - a table of “expirable” entities with startDate and endDate fields and a requirement to show separately “active” and “expired” entries in 2 different views. The “expiration” state is derived from the endDate. The entries also need to be sorted by the startDate. Of course it should be performant and scalable, because the number of (expired) entities will only keep growing. Now Convex has indexes, which is exactly how you are supposed to filter and sort your data, but here’s the catch - the sorting will be performed in order of fields it is built on, i.e., if your index is ['endDate','startDate'] and you filter by endDate, you will have sorting by that field too. You can sort in JavaScript, but once again you will lose cursor pagination. I can imagine why it is this way, but still SQL doesn’t have these restrictions.
I ended up denormalizing the endDate into the isEnded field.
Nitpicks
Client cache - kinda related to the first point, but technically a bit different. The point is, Convex caches everything server-side, so whenever you save on DB calls, you still lose a function call, and in my case, function calls were going out faster than anything. By the way, paginated queries are never cached.
Sharp image processing - I just couldn't get it to work in their Node.js environment. Seems like something is still missing there under the hood.
File storage - notoriously not cheap. There are better options that are even offered as optional components. They mentioned multiple times that they are working on it.
EU hosting - only recently Convex expanded deployment options to the EU, and the deal is not so sweet. First of all, the dealbreaker for smaller guys like me is that you don’t get any built-in resources (i.e., no free and no prepaid usage limits), and the resources you pay for are 33% more expensive than on US deployment.
What to look forward to
Custom IDs - recently there was an update paving the road towards this. Basically right now Convex relies on encoded IDs under the hood, and there's no way to provide your own. In my cases every user was coming from an auth provided with its ID, which I needed to store, so technically another user._id is redundant, and not relying on it would've saved a little trouble.
Conclusion
Convex is definitely not hopeless or without a use case. It’s still a good deal for the money and a good toolset. I managed to finish a pretty complex setup mostly with pleasure in the process. I don’t know if I would’ve chosen something else knowing all this, but I surely think these things should be covered better.
Team Up: Your social circle
Team Up is a platform for organizing and discovering social events of any kind. It’s focused on shaping your social circle and nourishing personal connections.
The flow is very simple - onboard in a few taps to set up your profile, create or join something you are interested in in a few more, and all you’ll have left to do is to actually show up to the activity. Team Up helps you with reminders, coordination in chat, and managing information. Other features include filtering, text search, saving events to your “liked” tab, and following users. And, to be safe, every uploaded image goes through automatic moderation, and you can block or report a user or event.
It doesn’t use any AI in content generation (only for moderation), so you’ll know that everything you see is made by real people. Just like you shouldn’t task AI with writing personal messages to your friends, I believe that there shouldn’t be anything artificial between you and people you want to connect with.
It’s completely free, with no ads and no data selling.
I researched the few similar apps that are out there, and other apps are either too expensive, too formal, or just too broken. So with this and after gathering opinions of people using them, I shaped it the way I see fit for such an app, adding what’s necessary and stripping off excessive fluff. Not everything worked out, but it’s there, it works, and I feel good about it.
So, while I don’t have any immediate plans for it right now, I would still very much appreciate your feedback. 🙂
Currently the app is only available in the Lithuanian App Store. The Android version is ready and is under a 2-week testing requirement.
https://apps.apple.com/lt/app/team-up-your-social-circle/id6761986119
Thanks everyone who helped me test it!


Top comments (0)