My Tech Stack...

And why you probably should not use it

Published: 2022-03-19

artsy render of stack of eliptical disks

tl;dr I often utilize Golang, Firebase, Svelte, and Tailwind CSS. But there are significant caveats and good reasons you probably don’t want to follow my lead.

In the developer community, especially amongst ‘full-stack’ devs, there is a culture of having a curated list of technologies that one uses to build an application from top to bottom. This is particularly true for web applications due to the myriad of options for each stack layer. Some combinations rose in popularity amongst boot camps and self-directed courses, for example, MEAN/MERN/MEVN — MongoDB, Express, Angular/React/Vue, NodeJS. This acronym conveys that a project uses NodeJS on the backend, with MongoDB as the database, Express as the middleware and API router, and Angular/React as the frontend framework. Just as frontend frameworks and languages by themselves cause spirited debates (read: flame wars), so too does the preference in a stack. I don’t participate in such unending debates (except to troll those who take themselves too seriously), but I figured I’d share what my tech stack looks like and explain some of my reasoning. I do not hope to convince readers to employ my combination of tools — in fact, for many of my choices, I’ll be arguing that you probably should not make the same decision. If there is one thing I do hope readers will take from this, it would be:

remember that the choice of language, framework, or stack “is not the thing… it’s the thing that gets you to the thing” (to paraphrase Joe MacMillan). As software developers, our job is to build and create - to solve problems. Our job is not to bicker endlessly about tools.

Anyway, that is enough preamble. Let’s start at the top of my stack and work downwards.

Frontend: Svelte, TypeScript, Tailwind

Svelte?! How? Why?
About eight months ago, I set out to pick a frontend framework. I’m almost exclusively a backend engineer by profession, but side projects were mounting that needed a web interface which meant I needed to expand my skillset. As I evaluated frontend frameworks, I had specific criteria. Of paramount importance was a gentle learning curve. I should be able to get up and running with a framework in hours. This criterion immediately eliminated Agular from contention. I also wanted a pretty opinionated framework without feeling too restricted — I didn’t want to make every nitty-gritty decision. I would much rather lean on the expertise of the framework builders, at least in the initial stages of the project. Decision paralysis was a big worry for me, especially with the JS ecosystem having dozens of third-party libraries for anything you could want. This requirement is best summarized as “sensible defaults.” I also didn’t want to feel like I was writing (too much) JavaScript. I can’t expound on my feelings around this too much, except to say that Svelte and Vue felt like they met this stipulation, while React did not. I guess you could say I didn’t want to write JSX? I also cared about bundle size and load times as I knew that some of my projects would have users in locations with slow internet speeds and data limits. I also needed a framework with an active community. Note that I said active and not large. This condition ensures that if I need a library, I can likely find one (no need for a dozen options), and I can get help if I need it. I came across some of Rich Harris’ talks during the evaluation, including Rethinking Reactivity and The Return of ‘Write Less, Do More’. His philosophy resonated with me. Svelte had the quickest learning curve, and the docs/tutorials are excellent. The community is vibrant; whenever I run into a problem, I simply hop into the discord. I like the magic add-ons provided in its HTMLX template. It feels effortless to be productive with less code. SvelteKit is in active development and shaping up nicely.
Does this mean I’d recommend anyone else learn/adopt Svelte? Nope. I am not here to give recommendations, and I don’t know what your situation is. I am privileged not to have my income tied to my choice of framework. I don’t have to care about the job prospects for a given framework. I also don’t have to worry about if the framework gels well with a large production team. At most, three people will work on my web app. You may have some of these (or other) considerations.

Moving on. TypeScript. I don’t think much needs to be said here. It’s 2022. If you’re not using TypeScript, then why not? I set up my SvelteKit projects with TypeScript by default. The interesting thing is that there is still JS in my frontend code. Typically, if the logic I am writing is small and bound to the given svelte component, that will start as JS, and I’ll convert it to TS if I think I’m doing something interesting in that script. If some logic is abstracted away from components to a separate file, that will be .ts instead of .js. I’m not saying this is correct. But it gives me a decent balance between safety and productivity.

Tailwind CSS. A few years back, when I first learned frontend development, I incorporated Bootstrap after learning HTML/CSS/JS. It was suitable for prototyping, but I found it hard to create a site that I would consider beautiful. Worse, I would visit other websites, think, “Hey, this site looks like mine,” and realize they are also using Bootstrap. In search of something new, I found Tailwind CSS. Instead of components, it provides utility classes for CSS, which you can compose however you like. It’s like building with Legos. Especially when combined with hot reload, you can supercharge your productivity. And it’s responsive by design. Tailwind is non-negotiable in my stack. If you haven’t tried it, I highly recommend that you do. If you have tried and don’t like it, that’s fine; there are many other options.

Backend: Golang/Python

My default is to use Go (AKA Golang) unless there’s some library I need that is only in Python, or I’m collaborating with others, and they know Python, not Go. Go is well suited for web servers and CLIs. It is fast, (cross) compiles to small binaries, built with concurrency in mind, simple, opinionated, explicit, readable. I often think that if C and Python had a baby, it would be Go. Am I suggesting that you swap whatever you were using in your backend for Go? Nope. I do think you should learn (or at least try) Go. But if you have a web app to build and already know another backend language/framework, like NodeJS or Django, you have to decide if you want to learn a new language for that project and do whatever pros/cons calculus is required.

Infrastructure: Firebase/CloudRun/FaaS/…

Last but certainly not least, we should talk about infrastructure: where/how my projects run. “Wait, you forgot to talk about databases!” you may be yelling. Relax. I am getting there. The truth is that I don’t have a strong preference for any particular database. What I use usually depends on my use-case complexity and where I’m running my app since I like tight coupling between my database and other areas, like auth. When I was first learning full-stack development, the default was to use Firebase as it is the premier BaaS (backend as a Service). It has a comprehensive set of technologies that allow developers to get up and running quickly. Over time, Firebase appears to have stagnated (or stabilized, depending on your PoV). In that time, new options, such as Supabase, have emerged. However, Firebase’s functionality is so complete that it’s still a solid option today. Given I have built up knowledge in Firebase, I often still turn to it, and they have great SDKs for each platform. Of course, if I’m using Firebase, my database ends up being Firestore.
Google Cloud Run is excellent at running your workloads/business logic. I often pair it with Firebase since they play well together. You give Cloud Run a container, and it takes care of the rest. It is probably my favorite product in GCP. Since many of my workloads run in containers, I get to take advantage of Golang’s small build size. For example, an app of ~13 MB in Golang took 100s of MB in other languages (usually due to the need to ship a runtime).
Sometimes, I’ll use a FaaS (Functions as a Service), especially if using Python. For example, GCP functions or (more likely) Azure functions. Again, GCP Functions can go with Firebase. There is also Firebase Functions, but that only supports NodeJS. If I’m using Azure functions, my database will be Table Storage. That is, if my use-case isn’t too complex and I don’t anticipate crazy levels or reads/writes/queries for which Azure Table Storage is not intended (hint: this is never an issue for a side project). If the use-case warrants something more robust/relational, I may opt for a MySQL database. I’ll opt for Azure Container Instances for some projects, but usually not as the backend for a full-stack app.
Should you be doing any of this? Probably not. I use GCP and Azure because I’m a cloud engineer and have worked on these products. Given some requirements, I can tell what combination of cloud infrastructure satisfies those requirements. I like thinking of infra. You probably don’t, and there’s no need. Firebase is a solid option. So is Supabase. As is Vercel and Netlify. PlanetScale is an excellent default for a database. Railway provides great serverless infrastructure. Try them out if you’d like. They all have generous free tiers.

Thanks for reading. Hopefully, you found it intriguing yet non-prescriptive. If I were to use only my preferred defaults, I would call this stack TGFS - Tailwind, Go, Firebase, Svelte. Not particularly catchy, is it? If you like it can also mean ‘Thank God For Svelte’.