
04/22/24

UPDATED 7/9/24: I updated this post to reflect the updates to the Database and CI/CD changes.
When I first started building Untappd almost 12 years ago, almost all the frameworks and tooling that exist today did not exist back then. To put it in perspective, jQuery Mobile was the framework of choice for building mobile-web apps, and React or React Native had not yet been developed.
Fast forward to now, and you can run your entire website for free in the cloud, with tons of features and a solid developer experience that makes going from having an idea to deploying as easy as clicking a button. Since I launched brickd in early February 2024, I've had a few people ask about what's behind the scenes and how it was built. I explained some high-level overview in this post on X, but felt that a detailed blog post on the entire system, including the costs to run it, would be interesting to share. At least I think it's interesting. So let's dive in!
LEGO Catalog Data
Source: Rebrickable
Cost: Free
When I first hatched the idea for brickd, I knew that the hardest part would be to obtain the seed data (the LEGO catalog) for all sets. I thought about scraping the LEGO website, but it proved to be a little more challenging than anticipated. Finally, I found a site called Rebrickable that offered an API and also (most importantly) a downloadable dataset for their system categorized by sets, minifigures, themes, and parts. Since I only needed the sets data, I wrote a script to pull down these CSV files and import the data into the database. I run this job once a day, recording any differences between the sets (such as added piece counts) and adding new ones. This keeps the dataset fresh and always up-to-date with new releases as long as they are added to Rebrickable.
Database / ORM
UPDATE - 7/9/24
Source: Postgres, Supabase, Prisma
Cost: Free Plan
Previous, I used RDS/MySQL, but migrated all the data over to Supabase with Postgres and moved the free plan. It's been pretty amazing and very performant for a free plan. The key is making sure that you are in the same region as your Vercel Functions. By default, it created it in us-west, but my Vercel instance is in us-east, so I had to tear it down and start again after spending some horus troubleshooting performance.
OLD
Source: MySQL, RDS (AWS), Prisma
Cost: $15/month (Prisma is free)
Since I was building a social network, I opted to use the old-stable solution of a MySQL relational database. This used to be hosted on PlanetScale, but since they terminated their free tier, I chose the AWS route with managed RDS. RDS is fast enough for my current needs and cheaper than the paid plans at PlanetScale.
On the software side, we use Prisma as our Object-Relational Mapper (ORM) to help write queries and relations in the code with Next.js. It's super easy to set up and allows for type-safe queries. I will say that Prisma may not be the best ORM, as there are many missing features (such as GROUP BY relation, count by distinct with group by, etc.), but it does the trick for 90% of my queries. If I do move to Postgres, the migration will be easy to move, however the raw queries will need to be re-written to the new standard.
CDN / Image Hosting
Source: Cloudinary
Cost: Free Tier
One of the best parts of brickd is the ability for users to upload their own photos of their sets and in-progress builds. One of the biggest problems with image hosting is the speed and bandwidth considerations, especially when dealing with mobile. With Cloudinary, I can use their CDN and their transformations simultaneously for high-speed results. I can easily transform images to fit into the area I would like them to be in the app and have a high cache CDN to deliver these. I'm currently on the free plan, well under the limit with room to grow. I've also built the system to swap out the image URLs to S3 in case of an outage or if I have outgrown their free plan, as S3 is cheap. If that does happen, I'll most likely need to use another provider to transform, as the free tier on Cloudinary doesn't support hosting images on an external bucket like S3.
Hosting & Framework
Source: NextJS + Vercel
Cost: Hobby (Free) Plan
Choosing Next.js for this project was a no-brainer for me, as I was already well-versed in working with their framework and wanted to see how it would scale to a mobile app. The front end of brickd is simply a marketing site, and all the APIs power the app from the backend. It's fast, easy, and a breeze to deploy. The Vercel system can handle way more than what I need, and the power of the EDGE helps me do really cool things like generating OG Images on the fly, and even user avatars with customized background colors that match a LEGO color when the user signs up.
Emails & Notifications
Source: loops & Firebase
Cost: Free Tier
Engaging users is essential, right? I stumbled upon Loops as an email system early on when they were just launching. With their generous Free Tier, you can manage 1,000 contacts and send 2,000 emails per month. It's dead simple to set up; just import your users with their API, and then create automated emails for "Sign Up" events or marketing emails to engage with new features.
On the push side, I leveraged Firebase, which also offers free unlimited push notifications with one protocol to iOS and Android. It doesn't have tons of bells and whistles like open rates, etc., but it gets the job done well and is really easy to set up.
Search
Source: Algolia
Cost: Free Tier
Search needs to be fast and easy to setup, and Algolia does both of them at a very generious free tier. The app makes a direct connect to Algolia's DSN (Data Search Network), so it never needs to hit brickd's servers to return lightning fast results. It averages around 30-60m response times, which is great some the speed needed for mobile. We have indexes for sets and users who both are searching Algolia's network for results. This does mean that I have to keep an updated version of those objects in their systems, but it's worth it for having the fastest and free search around.
Background Jobs
Source: innget
Cost: Free Tier
Without a doubt, one of the best tools I've ever used with respect to background jobs is Innget. Innget helps by keeping job-level code and app code in one repository and handles all the retry and job logic on their end. You simply create a job in your code, and then Innget will fire to your site (via the API route) to run the code over HTTP. There are some situations where this may run into snags for things like pipelines and long-running tasks (especially because at the Hobby Plan on Vercel, you have 10s execution times), but it works wonders. Also, a generous free tier, which is great.
I use the innget to do anything users don't need to wait on, like indexing a user, sending a notification or running a pricing check on a set. It's super easy to setup and having all your jobs in one place in your codebase.
App CI/CD
UPDATE - 7/9/24
Source: Azure Pipelines
Cost: $40/month / FREE
Since AppCenter is being shut off next year, Azure Pipleines offers a similar solution, that has much more generious free tier (more free hours). However the step and migration was REAL pain. If you are try to import from AppCenter, you have to enable LEGACY piplines just to import your YAML file. This took A LOT of work to set up, and I almost wonder if it was worth it. The only bad news is that I believe due to a bug in AppCener, I could run both Android and iOS together at the same time, but with Azure, the jobs only run one at time.
The only reason why I put $40 here, is because I am curently paying for it since I've gone over my build limit and now pay, but it will scale down after the month resets.
OLD
Source: AppCenter
Cost: $40/month
This is the largest expense I have for brickd, and I could drop it down to free (you can do 240 build minutes per month) if I didn't deploy as much as I do. This tool helps build all iOS and Android apps with a push of a commit to my Github branch. It builds the app, then auto-deploys to the App Store and Google Play Store with ease. It's DEFINITELY not perfect, and is being shut down in 2025, but it gets the job done for me at this stage. It took a long time to get set up correctly and a lot of trial and error.
Native App for iOS and Android
Source: React Native, React Native Elements, NativeWind
Cost: Free (Open Source)
The app is built with React Native and leverages React Native Elements and NativeWind as component libraries. NativeWind is a React Native version of Tailwind that allows you to write Tailwind CSS class names in React Native elements, and it creates those style elements for you on the fly. It's super easy to use and makes developing UI fast and easy.
Analytics
Source: posthog
Cost: Free Tier
Posthog is one of the best analytics software for web, native, and beyond. It's super easy to set up with React Native/Next.js and start getting events and page views. It also has built-in A/B testing, session capture, and feature flagging to help you figure out what your users are doing in your app/website.
Total Cost
Cost: $55/mon
Overall, brickd costs around $55 USD per month to run, and $40 of that is just for the CI/CD to build the app. I could migrate this over to Azure Pipelines, which is free to use, and reduce that cost. Of course, if brickd gains more users, this will change, but it's pretty easy to justify that and there are still some optimizations to be done. For example, I could migrate over to Neon DB (PostgresDB) and use their free tier, which would reduce the cost of the DB.