← Back to all posts The Stack Behind This Blog (And What I'd Change If I Started Over)

The Stack Behind This Blog (And What I'd Change If I Started Over)

Every project is a series of decisions made with incomplete information. Here's the full stack behind this blog, the reasoning behind each choice, what each one actually taught me, and — with the benefit of hindsight — what I'd change if I were starting today.

Flask — backend framework

Why I chose it: I picked Flask over Django because I wanted to understand how web applications fit together, not have the structure decided for me. Flask gives you routing, request handling, and templating — the rest is your decision.

What I actually learned: Building with Flask from scratch forced me to understand things Django would have handled automatically — how the application context works, how SQLAlchemy integrates, how Jinja2 renders templates, what WSGI actually is. Every time something broke, I had to understand it to fix it. That's a slower way to build but a faster way to learn.

What I'd change: Nothing here. Flask was the right choice for a learning project. For a production app with a team, I'd reconsider — but for understanding web development from the ground up, Flask is hard to beat.

Aiven MySQL — database

Why I chose it: Free, managed, persistent MySQL in the cloud. No credit card required. No local database server to maintain on the hosting side.

What I actually learned: More about SSL configuration than I expected. PyMySQL's SSL parameters are different from the MySQL CLI's — a distinction that cost me a few hours. Also learned about connection pooling: pool_pre_ping and pool_recycle are essential when your database can pause on inactivity, or you'll get "Lost connection" errors on the first query after a sleep period.

What I'd change: The free tier auto-pauses on inactivity. For a personal blog with low traffic, this is fine — but it means the first request after a long gap is slow. For anything with consistent traffic, I'd pay for a tier that stays running.

Cloudinary — image storage

Why I chose it: Two alternatives existed: store images in the database (slow, expensive in storage) or store them on the server filesystem (doesn't survive redeployments on Render). Cloudinary solves both — upload once, get a permanent URL, store only the URL in the database.

What I actually learned: The cloudinary.config() function takes lowercase parameter names (cloud_name, api_key, api_secret), not the uppercase environment variable names (CLOUDINARY_API_KEY). Subtle distinction that caused a "Must supply api_key" error I spent longer than I should have debugging.

What I'd change: Nothing. Cloudinary's free tier is generous, the API is straightforward, and the integration with Flask is clean.

Resend — transactional email

Why I chose it: I didn't — at first. I started with Flask-Mail and Gmail SMTP. That worked locally and broke immediately on Render (SMTP blocked on free tier, OSError 101). Resend was the replacement.

What I actually learned: SMTP is a legacy protocol that many modern hosting platforms restrict or block entirely on lower-tier plans. HTTP-based email APIs (Resend, SendGrid, Brevo) are more reliable in these environments because they use HTTPS — a port that's almost never blocked.

What I'd change: Start with Resend. Skip Flask-Mail entirely for anything that will be deployed. SMTP works great locally and poorly in production — which is exactly backwards from what you want.

Render — hosting

Why I chose it: Free tier, auto-deploys from GitHub, supports Python natively, Singapore region available (lowest latency for India-based visitors).

What I actually learned: Free tier has real constraints: SMTP blocked, services spin down after 15 minutes of inactivity, cold starts take 30-60 seconds. None of these are dealbreakers for a personal project, but all of them require workarounds (Resend for email, UptimeRobot for cold starts).

What I'd change: For a production application with real users, I'd pay for the Starter tier ($7/month) to eliminate cold starts and SMTP restrictions. For a personal blog or portfolio project, the free tier with workarounds is completely workable.

The thing I'd change that isn't about a specific tool

I ran pip freeze > requirements.txt before deploying. My global Python environment had 100+ packages installed from various projects — PyTorch, Django, Selenium, OpenAI, all of it ended up in the file. Render tried to install all of them. The build was slow and nearly failed.

The fix: use a virtual environment from day one. python -m venv venv, activate it, install only what the project needs. pip freeze then gives you 10 packages instead of 100.

This is a basic Python practice that I knew about and didn't do consistently. The deployment made me do it properly. Sometimes you need to feel the consequence before the habit sticks.

Final thought

Every tool on this list has a free tier, and the whole stack costs ₹0/month to run. For a fresher building a portfolio project, that matters. But more than cost, what this stack gave me was a set of real production problems to solve — SSL configuration, connection pooling, email delivery, crawler configuration. Those problems are worth more than the stack itself.

Build something. Deploy it. See what breaks. That's the education.