<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Athira</title><link href="https://athiraraghu-blr.github.io/" rel="alternate"/><link href="https://athiraraghu-blr.github.io/feeds/all.atom.xml" rel="self"/><id>https://athiraraghu-blr.github.io/</id><updated>2026-08-16T00:00:00+05:30</updated><entry><title>Mini App Police: The One-Line Idea That Builds Whole Apps</title><link href="https://athiraraghu-blr.github.io/mini-app-police.html" rel="alternate"/><published>2026-08-16T00:00:00+05:30</published><updated>2026-08-16T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-08-16:/mini-app-police.html</id><summary type="html">&lt;h1&gt;&lt;strong&gt;What if a single sentence was all it took to ship a project?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Most of us have had this moment: an idea flashes by while you’re in the shower, on a walk, or half-asleep at 1 a.m. “An app that tracks how many times I say ‘um’ in …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;&lt;strong&gt;What if a single sentence was all it took to ship a project?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Most of us have had this moment: an idea flashes by while you’re in the shower, on a walk, or half-asleep at 1 a.m. “An app that tracks how many times I say ‘um’ in meetings.” “A tool that turns grocery receipts into a monthly spending chart.” By the time you sit down at a laptop, the spark is gone — buried under the friction of setting up a repo, choosing a stack, writing boilerplate, and figuring out where to even start.&lt;/p&gt;
&lt;p&gt;Mini App Police is built to close that gap. The premise is disarmingly simple: you type one line describing what you want, and the app hands you back a complete, working program — structured, functional, and ready to run or extend.&lt;/p&gt;
&lt;h1&gt;The Core Idea&lt;/h1&gt;
&lt;p&gt;Think of it less like a coding tool and more like a translator between intention and implementation. You’re not writing specs, choosing frameworks, or debugging boilerplate. You’re just describing the what, and Mini App Police handles the how:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Input: “A habit tracker that reminds me to drink water every 2 hours.”&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Output: A working app — UI, logic, notifications, storage — generated and ready to go.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The name itself hints at the personality behind the tool: a little playful, a little authoritative. It’s not just generating code; it’s enforcing the idea into existence. It polices the gap between “I should build that someday” and “it’s built.”&lt;/p&gt;
&lt;h1&gt;Why This Matters&lt;/h1&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;It kills idea-death-by-friction. The biggest threat to a good idea isn’t a bad idea — it’s the 45 minutes of setup between having the idea and seeing it work. Removing that friction means more ideas survive long enough to be tested.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It’s a sketchpad for builders, not just non-coders. Even experienced developers lose momentum to scaffolding. A one-line prompt that produces a working skeleton is a fast way to prototype, validate, or just have fun before deciding whether something is worth polishing further.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It reframes “coding” as “describing.” For people who’ve never written a line of code, this collapses the barrier to entry entirely. The creative bottleneck shifts from technical skill to clarity of thought — which is arguably the harder and more valuable skill anyway.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;It turns idle thoughts into artifacts. Passing thoughts rarely get preserved. When capturing an idea is as easy as typing it and getting something tangible back, more of those fleeting sparks turn into real, testable things.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;How It Might Work Under the Hood&lt;/h1&gt;
&lt;p&gt;A tool like this would likely need to:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Parse intent, not just keywords&lt;/strong&gt; — understanding “an app that tracks how many times I say um” means audio input, speech pattern detection, and a counter/dashboard, not just a to-do list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Choose sensible defaults&lt;/strong&gt; — picking a stack, a UI pattern, and a data model without asking the user twenty clarifying questions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scaffold instantly&lt;/strong&gt; — generating file structure, working logic, and a usable interface in one shot, not just a stub.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stay editable&lt;/strong&gt; — the output shouldn’t be a black box. A “complete project” only has value if the user can open it up and keep shaping it.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The magic isn’t just generation — it’s judgment. Good one-line-to-app tools have to make dozens of invisible decisions on the user’s behalf, and make them well.&lt;/p&gt;
&lt;h1&gt;The Bigger Shift&lt;/h1&gt;
&lt;p&gt;Mini App Police sits at the edge of a larger trend: the compression of the distance between thinking and making. As generation tools get better at inferring intent, the bottleneck in software creation moves further and further upstream — away from syntax and setup, and toward the clarity of the idea itself.&lt;/p&gt;
&lt;p&gt;In that world, the most valuable skill isn’t knowing how to code. It’s knowing what to ask for.&lt;/p&gt;
&lt;p&gt;Got an idea? That’s the only prerequisite. Mini App Police handles the rest — one line in, one working app out.&lt;/p&gt;</content><category term="Article"/><category term="miniapppolice"/><category term="idea"/></entry><entry><title>EffortCommerce: Rethinking Value in a Work-for-Credits Economy</title><link href="https://athiraraghu-blr.github.io/effort-commerce-work-for-credits-economy.html" rel="alternate"/><published>2026-08-02T00:00:00+05:30</published><updated>2026-08-02T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-08-02:/effort-commerce-work-for-credits-economy.html</id><summary type="html">&lt;h1&gt;&lt;strong&gt;What Is EffortCommerce?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;EffortCommerce is a simple but powerful model: instead of exchanging money for goods, you exchange &lt;strong&gt;effort&lt;/strong&gt; for goods. The mechanics are straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Do some work — complete a task, contribute a skill, finish a project, or perform a service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Earn credits — your effort is converted into a currency …&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;</summary><content type="html">&lt;h1&gt;&lt;strong&gt;What Is EffortCommerce?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;EffortCommerce is a simple but powerful model: instead of exchanging money for goods, you exchange &lt;strong&gt;effort&lt;/strong&gt; for goods. The mechanics are straightforward:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Do some work — complete a task, contribute a skill, finish a project, or perform a service.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Earn credits — your effort is converted into a currency that lives inside the system.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Spend credits in the store — use those credits to buy any item available in the marketplace.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;At its core, EffortCommerce replaces cash-based transactions with a labor-based exchange, where the currency itself is a direct record of contribution rather than an abstract store of value.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Why This Model Matters&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Traditional commerce assumes everyone starts with capital. EffortCommerce flips that assumption. It says: your time and skill are your capital. This has a few interesting implications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. Lowers the Barrier to Participation&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Anyone with time, effort, or a skill to contribute can "buy in," even if they have no money. This opens commerce to people who are cash-poor but capability-rich — students, hobbyists, career-switchers, or communities with limited access to traditional currency.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. Creates a Direct Effort-to-Reward Loop&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Because credits are earned through work rather than purchased, there's a tighter, more transparent link between contribution and reward. People can see exactly what their effort is worth in real terms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Encourages Community and Skill-Sharing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If the "work" side of the system includes things like tutoring, repairing, designing, writing, or organizing, EffortCommerce naturally builds a marketplace of skills rather than just goods — turning the platform into a hybrid of a co-op, a barter network, and a rewards program.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;How It Might Work in Practice&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A basic EffortCommerce loop could look like this:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Task Board&lt;/em&gt;: Users pick from a list of available tasks (data entry, content creation, community moderation, physical labor, mentoring, etc.).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Credit Conversion&lt;/em&gt;: Each task has a credit value based on time, difficulty, or demand.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Marketplace&lt;/em&gt;: A store stocked with items — physical goods, digital products, services, or experiences — priced in credits instead of dollars.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Redemption&lt;/em&gt;: Users spend their earned credits freely, the same way they'd spend cash.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Potential Use Cases&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Community platforms&lt;/em&gt;: Local exchanges where neighbors trade skills and time for goods or services.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Corporate reward systems&lt;/em&gt;: Employees earn credits for extra initiatives, redeemable in an internal store.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Education platforms&lt;/em&gt;: Students earn credits by completing coursework or tutoring peers, spendable on learning materials or perks.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Nonprofits and volunteering&lt;/em&gt;: Volunteers earn credits for hours served, redeemable for supplies or community resources.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Gig-economy alternatives&lt;/em&gt;: A decentralized way to match effort with reward without requiring upfront capital.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Challenges to Consider&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;No system is without friction, and EffortCommerce raises a few important questions:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Valuation&lt;/em&gt; — How do you fairly price different types of work? An hour of manual labor and an hour of specialized design work may not be equivalent.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Inflation control&lt;/em&gt; — If credits are too easy to earn, their value in the store could erode over time.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Quality assurance&lt;/em&gt; — Work-for-credit systems need some way to verify that completed tasks meet a baseline standard.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Scalability&lt;/em&gt; — Matching enough "work" to enough "store demand" requires careful supply-and-demand balancing, much like any marketplace.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Bigger Picture&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;EffortCommerce taps into something people intuitively understand: value should reflect contribution. Whether used in a small community, a company, or a broader platform, it offers an alternative to purely transactional commerce — one where effort itself becomes the currency of exchange.&lt;/p&gt;
&lt;p&gt;In a world increasingly interested in fairness, participation, and non-monetary value systems, models like EffortCommerce hint at what a more inclusive, contribution-based economy could look like.&lt;/p&gt;</content><category term="Article"/><category term="effortcommerce"/><category term="credits"/><category term="economy"/></entry><entry><title>Locking the Gate: A Practical Walkthrough of OAuth2 in FastAPI</title><link href="https://athiraraghu-blr.github.io/oauth2-authentication-step-by-step.html" rel="alternate"/><published>2026-07-06T00:00:00+05:30</published><updated>2026-07-06T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-07-06:/oauth2-authentication-step-by-step.html</id><summary type="html">&lt;p&gt;Security is one of those things every API needs and almost nobody enjoys building. FastAPI makes it far less painful than most frameworks, thanks to built-in support for OAuth2 flows, dependency injection, and automatic docs that even show you a working "Authorize" button. This article walks through building a complete …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Security is one of those things every API needs and almost nobody enjoys building. FastAPI makes it far less painful than most frameworks, thanks to built-in support for OAuth2 flows, dependency injection, and automatic docs that even show you a working "Authorize" button. This article walks through building a complete OAuth2 password-flow authentication system in FastAPI — from hashing passwords to issuing JWTs to protecting endpoints — with working code at every stage.&lt;/p&gt;
&lt;p&gt;We'll build the &lt;strong&gt;OAuth2 Password Bearer flow&lt;/strong&gt;, the most common pattern for first-party APIs (as opposed to third-party login like "Sign in with Google," which uses the Authorization Code flow instead).&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 1: What OAuth2 Actually Buys You Here&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;OAuth2 is a framework for delegated authorization, not a single algorithm. FastAPI's OAuth2PasswordBearer implements one specific piece of it: the client sends a username and password to a token endpoint, receives an access token (typically a JWT), and then presents that token as a Bearer header on every subsequent request. FastAPI never sees the password again after login — only the token.&lt;/p&gt;
&lt;p&gt;This gets you:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A standard Authorization: Bearer &lt;token&gt; header, understood by every HTTP client and API tool&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stateless verification (no session store needed if you use JWTs)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Automatic integration with Swagger UI's login form&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Step 2: Project Setup&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Install the dependencies you'll need:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fastapi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;uvicorn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;python-jose[cryptography]&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;passlib[bcrypt]&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;python&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;multipart&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;python-jose — encodes/decodes JWTs
passlib[bcrypt] — securely hashes passwords
python-multipart — required for FastAPI to parse form data (the login endpoint expects application/x-www-form-urlencoded)&lt;/p&gt;
&lt;p&gt;Project structure for this walkthrough:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;app/
├── main.py
├── auth.py
├── models.py
└── database.py
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Step 3: Modeling Users and "Storage"&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;To keep the focus on authentication, we'll use an in-memory dictionary instead of a real database. Swapping in SQLAlchemy or an async ORM later doesn't change anything below.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# models.py&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pydantic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;full_name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;UserInDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;hashed_password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;token_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;TokenData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# database.py&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.auth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_password_hash&lt;/span&gt;

&lt;span class="n"&gt;fake_users_db&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;jdoe&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;jdoe&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;full_name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Jane Doe&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;jdoe@example.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;hashed_password&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;get_password_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;secret123&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="s2"&gt;&amp;quot;disabled&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Step 4: Hashing Passwords&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Never store plaintext passwords. passlib with bcrypt handles hashing and verification:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# auth.py (part 1)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;passlib.context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CryptContext&lt;/span&gt;

&lt;span class="n"&gt;pwd_context&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CryptContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;schemes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;bcrypt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;deprecated&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;auto&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;verify_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plain_password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashed_password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pwd_context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;plain_password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;hashed_password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_password_hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pwd_context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Step 5: Issuing JWT Access Tokens&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Now add JWT creation logic. The token payload (the "claims") should be minimal — just enough to identify the user and set an expiry.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# auth.py (part 2)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;datetime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;timezone&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;jose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JWTError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;

&lt;span class="n"&gt;SECRET_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;CHANGE_ME_TO_A_LONG_RANDOM_VALUE&amp;quot;&lt;/span&gt;  &lt;span class="c1"&gt;# use env var in production&lt;/span&gt;
&lt;span class="n"&gt;ALGORITHM&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;HS256&amp;quot;&lt;/span&gt;
&lt;span class="n"&gt;ACCESS_TOKEN_EXPIRE_MINUTES&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expires_delta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;to_encode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;expire&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;timezone&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;utc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;expires_delta&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ACCESS_TOKEN_EXPIRE_MINUTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;to_encode&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;exp&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;expire&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;to_encode&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;algorithm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ALGORITHM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Never hardcode SECRET_KEY in real code. Generate one with openssl rand -hex 32 and load it from an environment variable.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 6: Authenticating the User&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A helper to look up a user and verify their password:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# auth.py (part 3)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.models&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;UserInDB&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.database&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;fake_users_db&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;UserInDB&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;UserInDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;authenticate_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;verify_password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hashed_password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Step 7: The Login Endpoint (Token Route)&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;This is where OAuth2PasswordRequestForm comes in — it expects username and password as form fields, matching the OAuth2 spec.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# main.py (part 1)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;datetime&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi.security&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OAuth2PasswordRequestForm&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.auth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;authenticate_user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ACCESS_TOKEN_EXPIRE_MINUTES&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.database&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;fake_users_db&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.models&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Token&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;login_for_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;form_data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OAuth2PasswordRequestForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;authenticate_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fake_users_db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;form_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;form_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_401_UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Incorrect username or password&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;WWW-Authenticate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Bearer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;access_token_expires&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;timedelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;minutes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ACCESS_TOKEN_EXPIRE_MINUTES&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;access_token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sub&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="n"&gt;expires_delta&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;access_token_expires&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;access_token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;token_type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;bearer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The "sub" claim (subject) is the JWT-standard field for identifying who the token belongs to.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 8: Protecting Routes with a Dependency&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;This is where FastAPI's dependency injection shines. OAuth2PasswordBearer tells FastAPI where clients get tokens from (tokenUrl="token") and doubles as a dependency that extracts the token from the Authorization header automatically.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# main.py (part 2)&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi.security&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OAuth2PasswordBearer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;jose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;JWTError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.auth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ALGORITHM&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.database&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;fake_users_db&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.models&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TokenData&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;.auth&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_user&lt;/span&gt;

&lt;span class="n"&gt;oauth2_scheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;OAuth2PasswordBearer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokenUrl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_current_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oauth2_scheme&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;credentials_exception&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HTTP_401_UNAUTHORIZED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Could not validate credentials&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;WWW-Authenticate&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Bearer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;   
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    
        &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SECRET_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;algorithms&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ALGORITHM&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sub&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;credentials_exception&lt;/span&gt;
        &lt;span class="n"&gt;token_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TokenData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;JWTError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;credentials_exception&lt;/span&gt;

    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fake_users_db&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;token_data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;credentials_exception&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_current_active_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_current_user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;disabled&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="n"&gt;HTTPException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detail&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Inactive user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now any route can require authentication just by depending on get_current_active_user:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;/users/me&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;read_users_me&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;current_user&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_current_active_user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;current_user&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Step 9: Trying It Out&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Run the server:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;uvicorn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;reload&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Visit http://127.0.0.1:8000/docs. FastAPI's Swagger UI shows an &lt;strong&gt;Authorize&lt;/strong&gt; button because it detects the OAuth2PasswordBearer scheme. Click it, enter jdoe / secret123, and Swagger automatically attaches the resulting bearer token to every subsequent request you try in the docs.&lt;/p&gt;
&lt;p&gt;From the command line, the same flow looks like this:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:8000/token \&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;username=jdoe&amp;amp;password=secret123&amp;quot;&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;access_token&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;eyJhbGciOi...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;token_type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bearer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;curl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:8000/users/me \&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;H&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Authorization: Bearer eyJhbGciOi...&amp;quot;&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;→&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;username&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;jdoe&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;email&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;jdoe@example.com&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Step 10: Production Considerations&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A few things worth addressing before shipping this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Secret management&lt;/strong&gt; — pull SECRET_KEY from environment variables or a secrets manager, never source code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Token expiry &amp;amp; refresh tokens&lt;/strong&gt; — short-lived access tokens (15–30 min) paired with longer-lived refresh tokens reduce the damage from a leaked token.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HTTPS everywhere&lt;/strong&gt; — bearer tokens are equivalent to passwords in transit; never send them over plain HTTP.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Password policy&lt;/strong&gt; — bcrypt handles storage safely, but pair it with reasonable password strength rules at signup.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Real persistence&lt;/strong&gt; — swap the in-memory dict for a database with proper indexing on username/email and unique constraints.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scopes&lt;/strong&gt; — if you need fine-grained permissions, OAuth2PasswordBearer supports scopes so tokens can carry roles like "items:read" or "admin".&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Wrapping Up&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;FastAPI doesn't hide OAuth2's moving parts behind magic — it gives you clear, composable pieces: a scheme that extracts tokens, dependencies that verify them, and Pydantic models that keep everything typed. Once the pattern clicks, adding authentication to a new route is a one-line Depends() away.&lt;/p&gt;</content><category term="Article"/><category term="oauth2"/><category term="fastapi"/><category term="api"/></entry><entry><title>Talking to Your API: A Practical Guide to GET and POST in FastAPI</title><link href="https://athiraraghu-blr.github.io/get-and-post-in-fastapi.html" rel="alternate"/><published>2026-07-02T00:00:00+05:30</published><updated>2026-07-02T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-07-02:/get-and-post-in-fastapi.html</id><summary type="html">&lt;p&gt;When you build an API with FastAPI, almost everything you do boils down to answering one question: how does the client want to talk to me? HTTP gives us several ways to have that conversation, but two verbs — &lt;strong&gt;GET and POST&lt;/strong&gt; — handle the vast majority of real-world traffic. Understanding how …&lt;/p&gt;</summary><content type="html">&lt;p&gt;When you build an API with FastAPI, almost everything you do boils down to answering one question: how does the client want to talk to me? HTTP gives us several ways to have that conversation, but two verbs — &lt;strong&gt;GET and POST&lt;/strong&gt; — handle the vast majority of real-world traffic. Understanding how FastAPI treats each of them is the first real milestone in learning the framework.&lt;/p&gt;
&lt;p&gt;This article walks through what GET and POST mean, how FastAPI implements them, and how to decide which one to use.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Core Idea: Reading vs. Doing&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Before touching any code, it helps to internalize the philosophy behind these two methods:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GET&lt;/strong&gt; is for reading. You're asking the server for information, and you expect that asking doesn't change anything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;POST&lt;/strong&gt; is for doing. You're sending the server data so it can create, process, or change something.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This distinction isn't just a style preference — it's baked into the HTTP specification. GET requests are supposed to be &lt;strong&gt;safe&lt;/strong&gt; (no side effects) and &lt;strong&gt;idempotent&lt;/strong&gt; (calling it 100 times has the same effect as calling it once). POST requests carry no such guarantee.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Setting Up&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A minimal FastAPI app needs just a few lines:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Run it with uvicorn main:app --reload, and you're ready to define routes.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;GET: Asking for Data&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A GET endpoint in FastAPI is about as simple as it gets. You decorate a function with @app.get(), and FastAPI handles the rest.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;/items/{item_id}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;read_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;None&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;item_id&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;q&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Two things are happening here that make FastAPI pleasant to work with:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Path parameters&lt;/strong&gt; — item_id comes straight from the URL, e.g. /items/42. Because you typed it as int, FastAPI automatically validates and converts it. Send /items/abc and you'll get a clean 422 error instead of a crash.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Query parameters&lt;/strong&gt; — q isn't part of the path, so FastAPI treats it as an optional query string parameter, e.g. /items/42?q=search-term.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;GET requests don't have a request body (technically they can, but it's discouraged and poorly supported by many clients/proxies). So anything the client needs to send has to go in the URL — as path segments or query parameters. This is why GET is best suited for fetching, filtering, and searching, not for sending complex or sensitive data.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;POST: Sending Data&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;POST requests are built for carrying a payload. In FastAPI, that payload is almost always defined using &lt;strong&gt;Pydantic models&lt;/strong&gt;, which give you validation, parsing, and auto-generated documentation for free.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pydantic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BaseModel&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseModel&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;
    &lt;span class="n"&gt;is_offer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/items/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;price&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, FastAPI looks at the type hint Item, recognizes it as a Pydantic model, and knows to parse the JSON request body into it. If the client sends malformed data — say, price as a string that can't convert to a float — FastAPI rejects it automatically with a descriptive error message.&lt;/p&gt;
&lt;p&gt;This is where FastAPI really shines compared to older frameworks: you get body parsing, type coercion, and validation in a single, readable function signature.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Combining Path, Query, and Body Parameters&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Real endpoints often need a mix of everything:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;/items/{item_id}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;update_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;item_id&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;item&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;notify&amp;quot;&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;FastAPI is smart about sorting these out:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;item_id is in the path, so it's a path parameter.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;item is a Pydantic model, so it's parsed from the request body.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;notify is a plain type with a default value and isn't in the path, so it becomes a query parameter.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;No extra configuration needed — FastAPI infers the source of each parameter from its type and position.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Automatic Documentation&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;One detail that surprises newcomers: as soon as you define these routes, FastAPI generates interactive documentation for free. Visit /docs and you'll see a Swagger UI where you can try out both the GET and POST endpoints directly in the browser, complete with example request bodies for your Pydantic models. Visit /redoc for a cleaner, read-only reference view.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Choosing the Right One&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A simple rule of thumb: if the client is asking for something, use GET. If the client is sending something that should be stored, processed, or acted upon, use POST. Trying to force a search form with ten filters into GET query parameters gets messy fast — that's often a sign POST (or a request body) is the better fit. Conversely, using POST for something like "get user by ID" throws away caching, breaks browser back-button behavior, and confuses anyone consuming your API.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Wrapping Up&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;FastAPI's design encourages you to think in terms of what shape of data goes where — path, query, or body — and lets Python's own type hints do the heavy lifting for validation and documentation. GET and POST are the two verbs you'll reach for constantly, and once their roles click, the rest of FastAPI's routing system (PUT, DELETE, PATCH, and beyond) feels like a natural extension of the same idea.&lt;/p&gt;</content><category term="Article"/><category term="get"/><category term="post"/><category term="fastapi"/><category term="api"/></entry><entry><title>The Art of Effortless Creation: Building a Webpage Through Vibe Coding in Kiro</title><link href="https://athiraraghu-blr.github.io/building-webpage-through-vibe-coding-in-kiro.html" rel="alternate"/><published>2026-06-30T00:00:00+05:30</published><updated>2026-06-30T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-30:/building-webpage-through-vibe-coding-in-kiro.html</id><summary type="html">&lt;p&gt;There was a time when building a webpage meant wrestling with boilerplate, configuring environments, and writing every line of markup by hand before you ever saw a result. That era is quietly giving way to something more intuitive: vibe coding, a style of development where you describe what you want …&lt;/p&gt;</summary><content type="html">&lt;p&gt;There was a time when building a webpage meant wrestling with boilerplate, configuring environments, and writing every line of markup by hand before you ever saw a result. That era is quietly giving way to something more intuitive: vibe coding, a style of development where you describe what you want in plain language and let an AI-powered tool like Kiro translate intention into working code. The shift isn't about removing craft from the process; it's about moving the craft upstream, into the clarity of your ideas rather than the mechanics of syntax.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;What "Vibe Coding" Actually Means&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Vibe coding is less a technique than a posture toward building software. Instead of starting from a blank file and a mental checklist of HTML tags, you start from a conversation. You describe the feeling you want a page to have, the sections it should contain, the tone of its copy, and the tool fills in the structural and technical details. The term has caught on because it captures something real: when working with a capable AI coding assistant, development starts to feel less like engineering and more like creative direction. You're steering, refining, and reacting to what's produced, much the way a director works with a cinematographer rather than operating the camera themselves.&lt;/p&gt;
&lt;p&gt;This doesn't mean technical understanding becomes irrelevant. The best results still come from people who know what good structure, accessibility, and performance look like, and who can recognize when something is subtly wrong even if they didn't type it themselves. Vibe coding lowers the barrier to producing a working result, but judgment remains the part only a human can supply.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Kiro as a Canvas for Intention&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Kiro fits naturally into this workflow because it's built around the idea of translating specification into implementation with minimal friction. Rather than treating an AI assistant as an autocomplete engine bolted onto a traditional editor, Kiro is designed so that the conversation itself becomes the primary interface for building. You describe a webpage, perhaps a personal portfolio, a product landing page, or a simple informational site, and Kiro begins assembling the scaffolding: layout, styling, content blocks, and interactive elements, all derived from your description.&lt;/p&gt;
&lt;p&gt;What makes this approach feel different from older "no-code" tools is the underlying flexibility. You're not limited to dragging components onto a fixed template. Because the output is genuine, readable code, you retain full control to refine anything by hand later, or to keep iterating conversationally until the page matches what you pictured. The experience sits at a productive midpoint between rigid visual builders and unassisted hand-coding.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;A Typical Vibe Coding Session&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Picture starting with a simple prompt: "Build a one-page site for a boutique coffee roastery, warm and minimal, with a hero section, a story section, a product grid, and a contact form." Kiro doesn't ask you to specify every div and class name. It infers a sensible structure, chooses a typographic mood that matches "warm and minimal," and produces a working page you can preview immediately.&lt;/p&gt;
&lt;p&gt;From there, the real craft begins. You might say the hero image feels too stark, or that the product grid should use cards with rounded corners and soft shadows, or that the contact form needs a confirmation message after submission. Each of these notes gets folded back into the code without you needing to know exactly which CSS properties or JavaScript event handlers are involved. The iteration loop is fast: describe, observe, refine. It mirrors how a designer might give feedback to a developer in a critique session, except the turnaround between feedback and revision happens in moments rather than days.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Why the Approach Resonates&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Part of the appeal is democratization. Plenty of people have a clear vision for a webpage, a small business owner who knows exactly what their customers need to see, a writer who wants a clean home for their portfolio, but lack the time or training to implement that vision in code. Vibe coding in Kiro closes that gap without pretending that code doesn't matter; it simply changes who, or what, is responsible for the typing.&lt;/p&gt;
&lt;p&gt;There's also something to be said for how this approach changes the emotional texture of building. Traditional coding can feel like an obstacle course between you and your idea, each missing semicolon or unfamiliar API a small tax on creativity. Describing what you want and watching it materialize keeps you closer to the original spark of the project, the actual reason you wanted a webpage in the first place.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Keeping Craft in the Loop&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;None of this suggests that vibe coding replaces understanding the fundamentals. A page that merely looks right in the editor still needs to load quickly, behave well across devices, and remain accessible to people using assistive technology. The people who get the most out of tools like Kiro are typically the ones who review what's generated with a critical eye, ask for explanations when something seems opaque, and aren't afraid to drop into the code directly when a particular detail needs precision. Vibe coding accelerates the first ninety percent of the work dramatically; the final polish still rewards attention.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;A New Default for Small Builds&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;For quick, expressive projects, a landing page, a microsite, a prototype to test an idea, vibe coding in Kiro is becoming something close to a default starting point rather than a novelty. It compresses the distance between imagination and implementation, letting the conversation itself do the work that used to require a finished mental model of HTML, CSS, and JavaScript before you could even begin. The result is a webpage that not only functions, but carries the vibe you set out to create in the first place.&lt;/p&gt;</content><category term="Article"/><category term="web-page"/><category term="kiro"/><category term="vibe-coding"/><category term="designing"/></entry><entry><title>Helium 10 Chrome Extension: Key Features, Pricing Plans, and Alternatives</title><link href="https://athiraraghu-blr.github.io/helium10-chrome-extension-features-pricing-alternatibves.html" rel="alternate"/><published>2026-06-30T00:00:00+05:30</published><updated>2026-06-30T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-30:/helium10-chrome-extension-features-pricing-alternatibves.html</id><summary type="html">&lt;p&gt;If you sell on Amazon, you've probably heard of Helium 10 — and chances are the Chrome extension is the first piece of it you'll actually touch. It's a free browser add-on that overlays product research data directly onto Amazon (and now Walmart and TikTok Shop) pages, so you can evaluate …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you sell on Amazon, you've probably heard of Helium 10 — and chances are the Chrome extension is the first piece of it you'll actually touch. It's a free browser add-on that overlays product research data directly onto Amazon (and now Walmart and TikTok Shop) pages, so you can evaluate a product idea without leaving the marketplace to dig through a separate dashboard.&lt;/p&gt;
&lt;p&gt;This article breaks down what the extension actually does, what each pricing tier unlocks, and which alternatives are worth a look if Helium 10 doesn't fit your budget or workflow.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;What the Helium 10 Chrome Extension Does&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;At its core, the extension is a research layer that sits on top of Amazon's website. Once installed, clicking the icon while browsing a search results page or product listing pulls up real-time data: sales estimates, revenue, Best Seller Rank, FBA fees, review counts, and more — drawing on access to over 450 million ASINs.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Key features&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Xray&lt;/strong&gt; is the flagship tool and the one most sellers open first. Run on a search results page, it surfaces estimated sales, revenue, price, reviews, Best Sellers Rank, FBA fees, active sellers, fulfillment type, recent purchases, and both parent- and ASIN-level sales data, giving you a fast read on whether a niche looks crowded, fragmented, or genuinely open.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Profitability Calculator&lt;/strong&gt; estimates your margin before you commit to sourcing a product. It factors in Amazon fees, shipping costs, and similar expenses so you can see whether a product idea actually pencils out financially.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ASIN Grabber&lt;/strong&gt; speeds up competitor research by extracting up to 100 ASINs at once from a results page, which you can then export for deeper keyword or listing analysis.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Inventory Levels&lt;/strong&gt; lets you check how much stock a competitor has on hand by opening a product listing and viewing detailed inventory data — useful for spotting stockout risk or gauging how aggressively a seller is restocking.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Review Insights / Review Downloader&lt;/strong&gt; pulls and filters a competitor's reviews so you can spot recurring complaints — packaging issues, unclear instructions, missing features — that point to gaps you could fix in your own listing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Listing Health Score and Demand Analyzer&lt;/strong&gt; round out the toolkit, helping you benchmark a listing against category norms and gauge overall demand for a niche, according to Helium 10-focused materials describing at least six major modules built into the extension.&lt;/p&gt;
&lt;p&gt;In 2026, Helium 10 also extended the extension's reach beyond core FBA sellers. New features now support Amazon KDP authors, low-content publishers, Amazon Influencers, and wholesale resellers, including a dedicated Xray for Influencers mode that surfaces products already performing well rather than just commission potential.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;How to install it&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Setup takes a couple of minutes: visit the Chrome Web Store via helium10.com/extension, click "Add to Chrome," confirm the pop-up, then pin the extension and sign in or create a Helium 10 account to activate it. Once logged in, browsing Amazon search results automatically overlays BSR and ranking data above each listing, and the extension icon gives you access to Xray, ASIN Grabber, and the rest.&lt;/p&gt;
&lt;p&gt;A practical note: the extension needs broad site permissions to work outside Amazon. If the icon appears grayed out on Walmart or Alibaba, it's usually because the extension hasn't been given permission to read and change site data on all sites in your Chrome settings.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Free vs. Paid: What You Actually Get&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The extension itself is free to install, but most of its value is gated behind a Helium 10 subscription. Free plan users get access to core features including Xray, ASIN Grabber, and the Profitability Calculator, while upgrading unlocks advanced keyword research tools like Cerebro and Magnet along with higher usage limits on everything else.&lt;/p&gt;
&lt;p&gt;Helium 10 restructured its pricing in 2026, and reported figures vary somewhat by source and by whether you're billed monthly or annually — a sign the rates have been a moving target this year. The general shape looks like this:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Free plan&lt;/strong&gt; — Limited access to Xray and basic Chrome extension tools, useful for testing the waters but capped tightly (some reports cite as little as a handful of lifetime Blackbox searches and two-per-day limits on Cerebro/Magnet).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Platinum&lt;/strong&gt; — The current entry-level paid tier, generally quoted around &lt;strong&gt;$99–129/month&lt;/strong&gt; (roughly $79–99/month on annual billing). This unlocks full Chrome extension access, unlimited core product and keyword research, and Freedom Ticket training.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Diamond&lt;/strong&gt; — Aimed at scaling sellers, typically priced around &lt;strong&gt;$229–359/month&lt;/strong&gt; depending on billing cycle and source. Adds higher keyword-tracking limits, multi-user logins, additional connected seller accounts, inventory management, and ad automation tools.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Enterprise / Custom&lt;/strong&gt; — Built for large brands and agencies, with a dedicated customer success manager and custom onboarding, starting somewhere in the four-figure monthly range.&lt;/p&gt;
&lt;p&gt;Two changes are worth flagging if you're comparing older reviews against current pricing: the once-popular &lt;strong&gt;Starter plan (around $39–49/month)&lt;/strong&gt; has reportedly been phased out for new signups, pushing Platinum into the entry-level slot at a noticeably higher price point, and annual billing now seems to be where most of the meaningful discount lives. Because plans, limits, and promotional pricing change fairly often, it's worth checking Helium 10's official pricing page directly before budgeting around a specific number.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Is It Worth Paying For?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The free tier is genuinely useful for validating a casual product idea or two, but it's not built for a real research workflow — daily limits on Cerebro and Magnet make it hard to do more than a handful of lookups. For anyone actively sourcing or launching products, the jump to Platinum is close to mandatory if you want unlimited Xray and keyword research.&lt;/p&gt;
&lt;p&gt;Where opinions diverge is on value at scale. Sellers managing multiple SKUs or brands tend to find Diamond's inventory tracking, multi-user access, and ad tooling worth the price. Beginners and very small sellers, on the other hand, increasingly cite the cost as the main reason to look elsewhere — especially now that the cheaper Starter tier is largely gone.&lt;/p&gt;
&lt;p&gt;It's also worth treating the data itself with some skepticism regardless of plan. Extension estimates are directional, not exact — useful for narrowing a list of product ideas and spotting weak competition, but not a substitute for actual sourcing diligence, margin testing, and demand validation before you commit inventory dollars.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Alternatives to Consider&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;If Helium 10's pricing or learning curve doesn't fit, a few alternatives come up consistently:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Jungle Scout&lt;/strong&gt; — Helium 10's longest-running rival, with strong product and sales tracking and a similarly broad toolset. Often cited as the natural switch for sellers unhappy with Helium 10's pricing or support.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SellerSprite&lt;/strong&gt; — Positioned as a lower-cost, AI-driven option, frequently recommended for sellers who want core research tools without Helium 10's full price tag.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Viral Launch&lt;/strong&gt; — Known for deeper analytics on trends and market intelligence, often compared favorably for keyword and listing optimization work.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SmartScout&lt;/strong&gt; — Notable mainly for its free Chrome extension tier, which offers a meaningfully higher free usage cap than Helium 10's own free plan, plus FBA fee calculations and opportunity scoring without a credit card.&lt;/p&gt;
&lt;p&gt;None of these is a strict upgrade — they trade off differently on data depth, marketplace coverage (Amazon-only vs. Amazon-plus-Walmart-plus-TikTok), and price. The right choice generally comes down to how many SKUs you're managing, whether you need multi-marketplace support, and how much of Helium 10's broader toolkit (PPC management, listing optimization, training courses) you'd actually use versus pay for and ignore.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Bottom Line&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The Helium 10 Chrome extension is a solid entry point into Amazon product research — fast, free to install, and genuinely useful for a first pass at validating an idea. But its free tier is intentionally limited, and getting real value out of it means budgeting for a Platinum or Diamond subscription. Before committing, it's worth running the numbers on your expected usage against current Helium 10 pricing, and comparing at least one or two alternatives — particularly if you're just starting out and don't yet need the full suite of tools a paid plan unlocks.&lt;/p&gt;</content><category term="Article"/><category term="helium10"/><category term="chrome-extension"/><category term="features"/><category term="pricing"/><category term="alternatives"/></entry><entry><title>How to Publish Your Chrome Extension on the Chrome Web Store</title><link href="https://athiraraghu-blr.github.io/publish-your-chrome-extension-on-the-chrome-web-store.html" rel="alternate"/><published>2026-06-29T00:00:00+05:30</published><updated>2026-06-29T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-29:/publish-your-chrome-extension-on-the-chrome-web-store.html</id><summary type="html">&lt;p&gt;You built the thing. Now let's get it in front of people.&lt;/p&gt;
&lt;p&gt;So you've built a Chrome extension. It works on your machine, your friends think it's cool, and you're ready to share it with the world. The Chrome Web Store is where you do that — it's Google's official marketplace …&lt;/p&gt;</summary><content type="html">&lt;p&gt;You built the thing. Now let's get it in front of people.&lt;/p&gt;
&lt;p&gt;So you've built a Chrome extension. It works on your machine, your friends think it's cool, and you're ready to share it with the world. The Chrome Web Store is where you do that — it's Google's official marketplace for extensions, and getting listed there gives you access to millions of Chrome users.&lt;/p&gt;
&lt;p&gt;The process is straightforward once you know the steps. Here's everything you need to go from a local folder of files to a live, published extension.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Before You Start: What You'll Need&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Before touching the Chrome Web Store, make sure you have three things ready:&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;Google Account&lt;/strong&gt; — preferably one dedicated to development. You'll receive policy updates, review notifications, and potential takedown warnings here, so using a separate account keeps things clean.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;working extension&lt;/strong&gt; — not just "it kind of works," but thoroughly tested. Once you submit for review, Google's team will poke around your extension. Bugs that slip through reflect poorly on your listing and can get you rejected.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Required assets&lt;/strong&gt; — at minimum, a 128×128 pixel icon. You'll also want screenshots (1280×800 px) for your store listing. These are often the first thing a user sees, so they matter more than developers tend to think.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Register as a Developer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Head to the Chrome Web Store Developer Dashboard and sign in with your Google account. The first time you visit, you'll be asked to agree to the Developer Agreement and pay a one-time registration fee of &lt;strong&gt;$5 USD.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;That's it — five dollars, once, for your entire developer account. It covers every extension you'll ever publish under that account, with no recurring fees. The fee exists mainly to reduce spam and low-quality submissions.&lt;/p&gt;
&lt;p&gt;Once registered, complete your account profile: set your publisher name (this appears under every extension you publish), verify your contact email, and fill in any required business details.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Test Your Extension Locally&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This step sounds obvious, but it's worth being deliberate about. Open Chrome, navigate to chrome://extensions/, and flip on &lt;strong&gt;Developer mode&lt;/strong&gt; in the top-right corner. Click &lt;strong&gt;Load unpacked&lt;/strong&gt; and select your extension folder.&lt;/p&gt;
&lt;p&gt;Now test everything. Click every button. Trigger every feature. Open DevTools (F12) and watch the console for errors. If your extension interacts with specific websites, test it on those sites. If it has settings, change them and confirm they persist.&lt;/p&gt;
&lt;p&gt;One critical check: open your manifest.json and confirm it says "manifest_version": 3. The Chrome Web Store no longer accepts Manifest V2 extensions. If yours is still on V2, you'll need to migrate before proceeding — Google's migration guide covers the key differences.&lt;/p&gt;
&lt;p&gt;Also audit your permissions. Look at every permission listed in your manifest and ask honestly: does the extension actually use this? Unnecessary permissions are a red flag for reviewers and a trust signal for users. Only request what you genuinely need.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Package Your Extension as a ZIP&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Chrome Web Store only accepts ZIP file uploads — not raw folders, not CRX files. Packaging correctly is simple but easy to get wrong.&lt;/p&gt;
&lt;p&gt;First, clean up your extension folder. Remove anything that doesn't belong in production: .git directories, node_modules, test files, .DS_Store files, and any temporary scripts. The folder should contain only what the extension needs to run.&lt;/p&gt;
&lt;p&gt;Then, make sure your manifest.json is at the root level of the folder — not nested inside a subfolder. If Chrome opens your ZIP and can't find manifest.json immediately, the upload will fail.&lt;/p&gt;
&lt;p&gt;Once the folder is clean, compress it into a ZIP. On Mac, right-click → Compress. On Windows, right-click → Send to → Compressed folder. On Linux, zip -r my-extension.zip my-extension/.&lt;/p&gt;
&lt;p&gt;One more thing: set your version number in manifest.json to something low, like 0.0.1. Every future update you push must have a higher version number than the previous one, so give yourself room to grow.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 4: Upload to the Developer Dashboard&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Go to the Chrome Developer Dashboard, sign in, and click &lt;strong&gt;Add new item&lt;/strong&gt;. You'll be prompted to upload your ZIP file.&lt;/p&gt;
&lt;p&gt;If your manifest is valid and the ZIP is structured correctly, you'll be taken to the item edit page. If not, the dashboard will tell you what went wrong — usually a malformed manifest or a missing required field.&lt;/p&gt;
&lt;p&gt;At this point, your extension exists in the dashboard as a draft. You can upload new ZIPs as many times as you want before submitting for review, so don't treat this upload as the point of no return.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 5: Fill Out Your Store Listing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is the part most developers underestimate. Your store listing is your marketing page, and a weak one means fewer installs — even if your extension is excellent.&lt;/p&gt;
&lt;p&gt;Work through each tab in the dashboard:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Store Listing&lt;/strong&gt; — Write a clear, honest title and description. The description should explain what your extension does, why someone would want it, and how it works. Use plain language, not jargon. Upload your icon and at least one screenshot. Show the extension in action, not just a blank UI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Privacy&lt;/strong&gt; — Declare your extension's single purpose (Google requires this) and explain how your extension handles user data. If your extension runs entirely locally and collects nothing, say so clearly. If it does collect data, be specific and accurate — reviewers cross-reference these declarations with your code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Distribution&lt;/strong&gt; — Choose your visibility: Public (anyone can find and install it), Unlisted (only people with the direct link), or Private (restricted to your domain or trusted testers). You can also control which countries your extension is available in.&lt;/p&gt;
&lt;p&gt;If your extension collects any user data, you must provide a working Privacy Policy URL. Host it on your own site or link to a relevant file in your GitHub repo — it just needs to be publicly accessible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 6: Submit for Review&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When all tabs are filled out and the Submit for Review button becomes active, you're ready. Click it.&lt;/p&gt;
&lt;p&gt;A confirmation dialog will appear asking whether you want to publish automatically once the review passes, or publish manually at a time of your choosing. If you want to coordinate a launch — an announcement post, a tweet, a Product Hunt submission — choose manual publishing so you control the timing.&lt;/p&gt;
&lt;p&gt;After submission, your extension enters Google's review queue. Simple extensions with minimal permissions can be approved within a few hours. Extensions requesting sensitive permissions (like access to all URLs, or use of remote code) may take days and could require additional justification.&lt;/p&gt;
&lt;p&gt;You'll receive an email when your extension is approved, or if there's an issue that needs to be addressed. Once approved, you have &lt;strong&gt;30 days&lt;/strong&gt; to publish it — after that, the submission reverts to a draft and you'll need to resubmit.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;After You're Live&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Publishing is the beginning, not the end.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Read your reviews&lt;/strong&gt;. Users will tell you exactly what's broken, what's confusing, and what they wish your extension did. The Developer Dashboard lets you respond publicly, which signals to prospective users that you're engaged and maintaining the project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Push updates regularly&lt;/strong&gt;. When you upload a new version, increment the version number in manifest.json, re-zip, and upload through the same dashboard. Updates go through the same review process, though they're typically faster than initial submissions.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Watch for policy changes&lt;/strong&gt;. Google updates the Chrome Web Store Developer Program Policies periodically. An extension that's compliant today might need adjustments tomorrow. Your developer account email is where you'll hear about this.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use the analytics&lt;/strong&gt;. The dashboard gives you install counts, active user metrics, and ratings over time. These numbers tell you whether your extension is retaining users or losing them — and retention is the real signal of whether you've built something people genuinely value.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Common Reasons for Rejection&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;It helps to know what gets extensions rejected so you can avoid those pitfalls:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Requesting unnecessary permissions&lt;/strong&gt; — only ask for what you actually use&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vague or misleading descriptions&lt;/strong&gt; — be specific about what your extension does&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Missing or inaccessible privacy policy&lt;/strong&gt; — required if you handle any user data&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Using Manifest V2&lt;/strong&gt; — Manifest V3 is mandatory&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remote code execution&lt;/strong&gt; — loading and running code from external URLs is not allowed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Poor user experience&lt;/strong&gt; — extensions that crash, produce errors, or behave unexpectedly&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;The Bottom Line&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Publishing a Chrome extension takes maybe an hour the first time — most of that is filling out the store listing carefully. The $5 registration fee is the only cost, and from there, you can publish as many extensions as you like (up to 20 live at once per account).&lt;/p&gt;
&lt;p&gt;The review process exists to protect users, and it's worth treating seriously. A well-prepared submission — clean code, honest permissions, a clear listing — sails through. A rushed one gets rejected and costs you time.&lt;/p&gt;
&lt;p&gt;Build something useful, ship it properly, and then let the Chrome Web Store do what it's designed to do: put your work in front of the people who need it.&lt;/p&gt;</content><category term="Article"/><category term="google"/><category term="web-store"/><category term="steps"/><category term="chrome-extension"/><category term="extensions"/></entry><entry><title>How Good UX Increases Conversion Rates</title><link href="https://athiraraghu-blr.github.io/ux-increases-conversion-rates.html" rel="alternate"/><published>2026-06-28T00:00:00+05:30</published><updated>2026-06-28T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-28:/ux-increases-conversion-rates.html</id><summary type="html">&lt;p&gt;Every business wants more conversions — more sign-ups, purchases, leads, or subscriptions. Most chase that goal through ads, pricing strategies, or content marketing. But one of the most powerful levers sits right under their nose: the experience they give users when those users actually show up.&lt;/p&gt;
&lt;p&gt;Good UX isn't a cosmetic …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Every business wants more conversions — more sign-ups, purchases, leads, or subscriptions. Most chase that goal through ads, pricing strategies, or content marketing. But one of the most powerful levers sits right under their nose: the experience they give users when those users actually show up.&lt;/p&gt;
&lt;p&gt;Good UX isn't a cosmetic upgrade. It's a revenue strategy.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;What "Conversion" Actually Means&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A conversion is any action a user takes that moves them closer to becoming a customer — or deeper into being one. Signing up for a free trial. Adding a product to a cart. Completing a checkout. Filling out a contact form. Upgrading a plan.&lt;/p&gt;
&lt;p&gt;UX influences every single one of these moments. The question isn't whether design affects conversion. It's how much — and the answer, consistently, is: more than most companies expect.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Core Principle: Friction Kills Intent&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Users don't abandon products because they stop wanting them. They abandon them because something got in the way.&lt;/p&gt;
&lt;p&gt;That "something" is friction — the resistance a user feels when trying to complete a task. Friction can be cognitive (too many choices, unclear messaging), physical (too many clicks, forms that are hard to fill), or emotional (distrust, confusion, anxiety about a decision).&lt;/p&gt;
&lt;p&gt;Good UX is fundamentally about reducing friction between a user's intent and their action. When that gap closes, conversion rates rise.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Five Ways UX Directly Drives Conversions&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Clarity Converts&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If a user can't immediately understand what you're offering and why it matters to them, they leave. Not because they're impatient — because their time is limited and alternatives are one back-button away.&lt;/p&gt;
&lt;p&gt;Clear UX answers three questions in seconds: What is this? Who is it for? What should I do next?&lt;/p&gt;
&lt;p&gt;A well-designed hero section, a concise value proposition, and a single visible call-to-action can do more for conversion rates than months of A/B testing button colors.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Trust Is Designed&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Conversion requires trust. People won't hand over their email, card details, or commitment to a product they don't trust. And trust — or the lack of it — is communicated visually before a single word is read.&lt;/p&gt;
&lt;p&gt;Professional typography, consistent visual hierarchy, responsive layouts, and polished micro-interactions all signal that a product is legitimate and cared for. Conversely, broken layouts, mismatched fonts, or laggy interactions plant doubt that's difficult to overcome.&lt;/p&gt;
&lt;p&gt;Social proof (testimonials, ratings, logos), security badges, and transparent pricing policies are UX decisions, not just content decisions. Where and how they appear determines whether users notice and believe them.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Navigation Shapes the Journey&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Users rarely convert on their first page. They explore, compare, and consider. A well-structured navigation keeps them inside that journey rather than losing them to confusion or dead ends.&lt;/p&gt;
&lt;p&gt;Clear information architecture means users find what they need without effort. Thoughtful internal linking guides them toward conversion pages. Breadcrumbs and persistent navigation give them the confidence to explore without fear of getting lost.&lt;/p&gt;
&lt;p&gt;Every page a user can't find is a conversion opportunity missed. Every dead end is a user who leaves.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Form Design Is Conversion Design&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Forms are where intent meets action — and where the most conversions are lost. Long forms, ambiguous field labels, poor error messages, and unnecessary required fields all create abandonment.&lt;/p&gt;
&lt;p&gt;The principles are well-established but frequently ignored: ask for only what you need, use inline validation so errors surface immediately, label fields clearly and consistently, and make the submit action feel safe and reversible where possible.&lt;/p&gt;
&lt;p&gt;A checkout form reduced from 12 fields to 6 isn't just a design decision — it's a revenue decision. Studies consistently show that reducing form fields meaningfully increases completion rates.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Speed Is a UX Problem&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Page load time is one of the most underestimated conversion factors in product design. A page that loads in one second converts significantly better than a page that loads in three — and a page that loads in five is, for most users, a page they've already left.&lt;/p&gt;
&lt;p&gt;Performance optimization is UX work. Image compression, lazy loading, efficient code, and fast server response times are all design decisions with direct conversion consequences.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Role of Mobile UX&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Across most industries, more than half of web traffic now comes from mobile devices. Yet many conversion flows — especially checkout and sign-up — are still designed primarily for desktop and adapted (poorly) for mobile.&lt;/p&gt;
&lt;p&gt;A mobile-first UX approach means designing for small screens, touch targets, limited attention, and intermittent connectivity as the baseline. Tap targets sized correctly, forms that trigger the right keyboard, and layouts that don't require pinching and zooming are not niceties. For a majority of users, they're the difference between converting and leaving.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Onboarding: The Conversion That Keeps Giving&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;For software products, the most important conversion often isn't the sign-up — it's the moment a user gets value from the product for the first time. Poor onboarding UX means users churn before they ever really arrive.&lt;/p&gt;
&lt;p&gt;A well-designed onboarding flow removes barriers to the "aha moment": the instant a user understands why the product matters to them personally. Progress indicators, contextual tooltips, sensible defaults, and a guided first experience all accelerate time-to-value. Lower time-to-value means higher retention — and retention is conversion compounding over time.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Measuring UX's Impact on Conversion&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The relationship between UX improvements and conversion rates is measurable. Some common signals to watch:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Bounce rate — users who leave without interacting often signal a clarity or relevance failure&lt;/li&gt;
&lt;li&gt;Drop-off rate — where in a funnel users abandon reveals where friction lives&lt;/li&gt;
&lt;li&gt;Task completion rate — can users accomplish what they came to do?&lt;/li&gt;
&lt;li&gt;Session recordings and heatmaps — show exactly where users hesitate, click, or lose momentum&lt;/li&gt;
&lt;li&gt;A/B testing — compares specific UX changes against measurable outcomes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The discipline of UX research — user interviews, usability testing, journey mapping — gives teams the qualitative insight to know why users behave as they do, not just that they do. The most effective conversion improvements come from understanding the person, not just optimizing the pixel.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;UX Is Not a One-Time Project&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Companies often treat UX as a launch deliverable: design the product, ship it, move on. But user expectations evolve, products grow in complexity, and what worked at 1,000 users may create friction at 100,000.&lt;/p&gt;
&lt;p&gt;The highest-converting digital products treat UX as an ongoing practice. They instrument their funnels, listen to users continuously, and improve iteratively. Small, consistent friction reductions compound into significant conversion gains over time.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Good UX doesn't just make products easier to use. It makes them easier to say yes to.&lt;/p&gt;
&lt;p&gt;When users can quickly understand what they're getting, trust the product they're looking at, find what they need without effort, and complete an action without obstacles — they convert. Not because they were persuaded, but because their intent and the product's design were finally aligned.&lt;/p&gt;
&lt;p&gt;Investing in UX is investing in conversion. The companies that understand this don't ask whether they can afford good design. They recognize they can't afford bad design.&lt;/p&gt;</content><category term="Article"/><category term="UX"/><category term="conversion"/></entry><entry><title>Make Mistakes Once</title><link href="https://athiraraghu-blr.github.io/make-mistakes-once.html" rel="alternate"/><published>2026-06-27T00:00:00+05:30</published><updated>2026-06-27T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-27:/make-mistakes-once.html</id><summary type="html">&lt;p&gt;On the art of learning from failure — and actually moving on&lt;/p&gt;
&lt;p&gt;There's a particular kind of torture that high-achievers know well: replaying a mistake on an endless loop. The wrong word in a meeting. The project that flopped. The decision that, in hindsight, was obviously wrong. We revisit it, rephrase …&lt;/p&gt;</summary><content type="html">&lt;p&gt;On the art of learning from failure — and actually moving on&lt;/p&gt;
&lt;p&gt;There's a particular kind of torture that high-achievers know well: replaying a mistake on an endless loop. The wrong word in a meeting. The project that flopped. The decision that, in hindsight, was obviously wrong. We revisit it, rephrase it, relitigate it — as though thinking about it hard enough will somehow undo it.&lt;/p&gt;
&lt;p&gt;It won't.&lt;/p&gt;
&lt;p&gt;But here's what's worth thinking about instead: the most successful, resilient people in the world don't avoid mistakes. They just refuse to make the same one twice.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Permission to Fail (Once)&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;"Make mistakes once" is not a license for carelessness. It's something closer to a philosophy of deliberate living.&lt;/p&gt;
&lt;p&gt;When you give yourself permission to make a mistake — truly, fully, without self-flagellation — you free yourself to act. Fear of failure is one of the greatest inhibitors of action there is. People stay in bad jobs, bad relationships, bad habits, not because they don't know better, but because they're terrified of making a wrong move. The result? Paralysis dressed up as prudence.&lt;/p&gt;
&lt;p&gt;Making a mistake once means you acted. You tried. You gathered real information from the world instead of staying safe inside your head. The mistake isn't the failure — it's the entrance fee for actually playing the game.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Lesson Is the Point&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Every mistake contains a message. The question is whether you're listening.&lt;/p&gt;
&lt;p&gt;Most people, when they fail at something, respond in one of two unhelpful ways. The first is denial — brushing it off, making excuses, attributing it entirely to bad luck or other people. No lesson is extracted; the same mistake lies waiting around the next corner.&lt;/p&gt;
&lt;p&gt;The second is self-punishment — ruminating, catastrophizing, deciding the mistake is evidence of some deep personal flaw. This, paradoxically, is also a way of not learning. When you're drowning in shame, you can't think clearly about what went wrong or how to course-correct.&lt;/p&gt;
&lt;p&gt;The middle path is harder and rarer: honest reflection. What exactly happened? What did I miss? What would I do differently? This kind of clear-eyed autopsy — conducted without excessive emotion — is where the real value of a mistake lives.&lt;/p&gt;
&lt;p&gt;Make the mistake once, extract the lesson, and carry it forward. That's the whole process.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Systems Over Willpower&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Here's something uncomfortable: willpower is overrated.&lt;/p&gt;
&lt;p&gt;Telling yourself "I'll just try harder next time" is a strategy that fails repeatedly across human history. If the mistake came from a gap in your process, your systems, or your environment, trying harder won't fix it. You'll end up making the same mistake again — and feeling worse about yourself each time.&lt;/p&gt;
&lt;p&gt;The people who genuinely make mistakes once tend to be systems thinkers. They ask not just what went wrong, but why the conditions existed for it to go wrong. They change something structural: a checklist, a habit, a team dynamic, an automated reminder. They design their environment so the mistake becomes harder to repeat, rather than relying on memory and motivation alone.&lt;/p&gt;
&lt;p&gt;James Clear, in his work on habits, puts it well: you don't rise to the level of your goals, you fall to the level of your systems. Nowhere is this truer than in error recovery.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Danger of Second Mistakes&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;There's a reason pilots, surgeons, and nuclear engineers obsess over learning from failure. In high-stakes environments, the cost of making the same mistake twice is unacceptable. Entire professions have built cultures around post-mortems, incident reviews, and systematic debriefs — not to assign blame, but to make sure the same failure mode never recurs.&lt;/p&gt;
&lt;p&gt;The rest of us could stand to borrow a little of that discipline.&lt;/p&gt;
&lt;p&gt;Second mistakes are rarely dramatic. They sneak up wearing familiar clothes. You've been here before, but it doesn't quite look the same, so you don't recognize it until it's too late. The antidote is pattern recognition: knowing your own failure signatures well enough to spot them early. This requires you to have actually sat with your first mistake long enough to understand it — not just survived it and moved on.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Forgiveness Is Part of It&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;None of this works without self-forgiveness.&lt;/p&gt;
&lt;p&gt;Extracting lessons from a mistake requires you to look at it clearly. Clarity is impossible when you're still in the grip of guilt or shame. At some point — not immediately, but eventually — you have to make peace with the fact that you made a mistake. Not because it didn't matter. Not because it didn't hurt. But because you're a human being, operating with incomplete information, in an uncertain world, doing your best.&lt;/p&gt;
&lt;p&gt;Self-forgiveness isn't the end of accountability. It's the beginning of it. When you stop defending yourself and stop punishing yourself, you can finally, honestly answer the question: what do I do differently now?&lt;/p&gt;
&lt;p&gt;That question is everything.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;A Different Kind of Ambition&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;There's an ambition in "make mistakes once" that doesn't get talked about enough.&lt;/p&gt;
&lt;p&gt;It's the ambition to be someone who learns. Not someone who's perfect — perfection is a myth and a trap. But someone who is genuinely, measurably better than they were a year ago, five years ago, a decade ago. Someone whose mistakes, while inevitable, form a clear upward arc rather than a dispiriting loop.&lt;/p&gt;
&lt;p&gt;That's a life well-lived. Not a life without error, but a life in which every error meant something — where the stumble became a step.&lt;/p&gt;
&lt;p&gt;Make the mistake. Learn the lesson. Make a different mistake next time.&lt;/p&gt;
&lt;p&gt;That's called growth.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The world doesn't remember your mistakes half as long as you do. What it does notice, over time, is whether you learned from them.&lt;/p&gt;</content><category term="Article"/><category term="m2o"/><category term="mistakes"/></entry><entry><title>Python Best Practices for Clean and Maintainable Code</title><link href="https://athiraraghu-blr.github.io/best-practice-for-clean-and-maintanable-code.html" rel="alternate"/><published>2026-06-26T00:00:00+05:30</published><updated>2026-06-26T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-26:/best-practice-for-clean-and-maintanable-code.html</id><summary type="html">&lt;p&gt;Writing Python code that works is one thing. Writing code that your future self — or a teammate — can actually understand, extend, and trust six months from now is another skill entirely. This article covers the practices that separate good Python from great Python.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Follow PEP 8 — But Don't Obsess Over …&lt;/strong&gt;&lt;/h1&gt;</summary><content type="html">&lt;p&gt;Writing Python code that works is one thing. Writing code that your future self — or a teammate — can actually understand, extend, and trust six months from now is another skill entirely. This article covers the practices that separate good Python from great Python.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Follow PEP 8 — But Don't Obsess Over It&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;PEP 8 is Python's official style guide, and most of its rules exist for good reason. The big ones worth internalizing:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Use 4 spaces for indentation (never tabs)&lt;/li&gt;
&lt;li&gt;Keep lines under 79 characters (or 88–99 if your team prefers Black's defaults)&lt;/li&gt;
&lt;li&gt;Two blank lines between top-level functions and classes; one blank line between methods&lt;/li&gt;
&lt;li&gt;Use snake_case for variables and functions, PascalCase for classes, UPPER_CASE for constants&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That said, consistency within a codebase matters more than strict PEP 8 compliance. If you join an existing project with a different convention, match it. Use a formatter like &lt;strong&gt;Black or Ruff&lt;/strong&gt; to automate this entirely so you never argue about style again.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculateTotalPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;tax_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;item_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;&amp;#39;price&amp;#39;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;tax_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;This&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;calculate_total_price&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;dict&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;tax_rate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;float&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;&amp;quot;price&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tax_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Write Meaningful Names&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The single highest-leverage habit in readable code is naming things well. A good name makes a comment unnecessary.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Bad&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;proc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;x for x in d if x &amp;gt; n&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;

&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Good&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;filter_above_threshold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;data&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;float&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;threshold&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;float&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;value for value in data if value &amp;gt; threshold&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Rules of thumb:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Variables and functions should describe what they are or what they do&lt;/li&gt;
&lt;li&gt;Avoid single-letter names except in short loops (i, j) or math contexts (x, y)&lt;/li&gt;
&lt;li&gt;Boolean variables should read like questions: is_active, has_permission, was_updated&lt;/li&gt;
&lt;li&gt;Don't abbreviate unless the abbreviation is universally understood (url, id, cfg)&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Use Type Hints&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Type hints, introduced in Python 3.5 and steadily improved since, are one of the best tools for making code self-documenting and catching bugs before runtime.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;collections.abc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_user_emails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;user_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Sequence&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;active_only&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Type hints don't enforce anything at runtime, but they enable static analysis tools like &lt;strong&gt;mypy and Pyright&lt;/strong&gt;, and they make function signatures immediately understandable without reading the implementation. Treat them as documentation that can be verified.&lt;/p&gt;
&lt;p&gt;For complex types, the typing module (and Python 3.10+'s built-in syntax) gives you Optional, Union, Literal, TypedDict, and more:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;# Python 3.10+&lt;/span&gt;
&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Embrace Python's Built-ins and Standard Library&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Experienced Python developers reach for built-ins and standard library tools instinctively. Knowing these well makes your code shorter, faster, and easier to read.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Comprehensions over manual loops:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;#&lt;/span&gt; Fine
results = []
for user in users:
    if user.is_active:
        results.append(user.email)

&lt;span class="gh"&gt;#&lt;/span&gt; Better
results = [user.email for user in users if user.is_active]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;enumerate&lt;/strong&gt; instead of manual indexing:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;items&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;{i}: {item}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;zip&lt;/strong&gt; for parallel iteration:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;for name&lt;span class="p"&gt;,&lt;/span&gt; score &lt;span class="k"&gt;in&lt;/span&gt; zip&lt;span class="p"&gt;(&lt;/span&gt;names&lt;span class="p"&gt;,&lt;/span&gt; scores&lt;span class="p"&gt;):&lt;/span&gt;
    print&lt;span class="p"&gt;(&lt;/span&gt;f&lt;span class="s2"&gt;&amp;quot;{name}: {score}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;collections.defaultdict and Counter:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;

&lt;span class="n"&gt;word_counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;split&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;most_common&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;word_counts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;most_common&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;pathlib instead of os.path:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pathlib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;config_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;home&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;.config&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;myapp&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;settings.json&amp;quot;&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;config_path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exists&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config_path&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;read_text&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Handle Exceptions Properly&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Swallowing exceptions silently is one of the most common sources of bugs that are hard to diagnose.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;#&lt;/span&gt; Never do this
try:
    result = process(data)
except Exception:
    pass  # bugs disappear here

&lt;span class="gh"&gt;#&lt;/span&gt; Don&amp;#39;t do this either — too broad
try:
    result = process(data)
except Exception as e:
    print(f&amp;quot;Something went wrong: {e}&amp;quot;)

&lt;span class="gh"&gt;#&lt;/span&gt; Do this — catch specific exceptions
try:
    result = int(user_input)
except ValueError:
    raise ValueError(f&amp;quot;Expected an integer, got: {user_input!r}&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A few principles:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Catch the most specific exception type possible&lt;/li&gt;
&lt;li&gt;Re-raise with context using raise ... from ... when wrapping exceptions&lt;/li&gt;
&lt;li&gt;Use finally for cleanup, or better yet, context managers (with statements)&lt;/li&gt;
&lt;li&gt;Don't use exceptions for flow control when a simple conditional works&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Write Functions That Do One Thing&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Functions should be short, focused, and named after what they do. If you find yourself writing a function that has "and" in its description, it's doing too much.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;#&lt;span class="w"&gt; &lt;/span&gt;Doing&lt;span class="w"&gt; &lt;/span&gt;too&lt;span class="w"&gt; &lt;/span&gt;much
def&lt;span class="w"&gt; &lt;/span&gt;process_order(order):
&lt;span class="w"&gt;    &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;validate
&lt;span class="w"&gt;    &lt;/span&gt;if&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;order.get(&amp;quot;items&amp;quot;):
&lt;span class="w"&gt;        &lt;/span&gt;raise&lt;span class="w"&gt; &lt;/span&gt;ValueError(&amp;quot;Order&lt;span class="w"&gt; &lt;/span&gt;has&lt;span class="w"&gt; &lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;items&amp;quot;)
&lt;span class="w"&gt;    &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;calculate
&lt;span class="w"&gt;    &lt;/span&gt;total&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;sum(item[&amp;quot;price&amp;quot;]&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;item[&amp;quot;qty&amp;quot;]&lt;span class="w"&gt; &lt;/span&gt;for&lt;span class="w"&gt; &lt;/span&gt;item&lt;span class="w"&gt; &lt;/span&gt;in&lt;span class="w"&gt; &lt;/span&gt;order[&amp;quot;items&amp;quot;])
&lt;span class="w"&gt;    &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;apply&lt;span class="w"&gt; &lt;/span&gt;discount
&lt;span class="w"&gt;    &lt;/span&gt;if&lt;span class="w"&gt; &lt;/span&gt;order.get(&amp;quot;coupon&amp;quot;)&lt;span class="w"&gt; &lt;/span&gt;==&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;SAVE10&amp;quot;:
&lt;span class="w"&gt;        &lt;/span&gt;total&lt;span class="w"&gt; &lt;/span&gt;*=&lt;span class="w"&gt; &lt;/span&gt;0.9
&lt;span class="w"&gt;    &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;save&lt;span class="w"&gt; &lt;/span&gt;to&lt;span class="w"&gt; &lt;/span&gt;DB
&lt;span class="w"&gt;    &lt;/span&gt;db.save({&amp;quot;order&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;order,&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;total&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;total})
&lt;span class="w"&gt;    &lt;/span&gt;#&lt;span class="w"&gt; &lt;/span&gt;send&lt;span class="w"&gt; &lt;/span&gt;email
&lt;span class="w"&gt;    &lt;/span&gt;email.send(order[&amp;quot;customer_email&amp;quot;],&lt;span class="w"&gt; &lt;/span&gt;f&amp;quot;Your&lt;span class="w"&gt; &lt;/span&gt;total&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&amp;quot;)

#&lt;span class="w"&gt; &lt;/span&gt;Better&lt;span class="w"&gt; &lt;/span&gt;—&lt;span class="w"&gt; &lt;/span&gt;each&lt;span class="w"&gt; &lt;/span&gt;function&lt;span class="w"&gt; &lt;/span&gt;does&lt;span class="w"&gt; &lt;/span&gt;one&lt;span class="w"&gt; &lt;/span&gt;thing
def&lt;span class="w"&gt; &lt;/span&gt;validate_order(order:&lt;span class="w"&gt; &lt;/span&gt;dict)&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;None:
&lt;span class="w"&gt;    &lt;/span&gt;if&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;order.get(&amp;quot;items&amp;quot;):
&lt;span class="w"&gt;        &lt;/span&gt;raise&lt;span class="w"&gt; &lt;/span&gt;ValueError(&amp;quot;Order&lt;span class="w"&gt; &lt;/span&gt;has&lt;span class="w"&gt; &lt;/span&gt;no&lt;span class="w"&gt; &lt;/span&gt;items&amp;quot;)

def&lt;span class="w"&gt; &lt;/span&gt;calculate_total(order:&lt;span class="w"&gt; &lt;/span&gt;dict)&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;float:
&lt;span class="w"&gt;    &lt;/span&gt;subtotal&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;sum(item[&amp;quot;price&amp;quot;]&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;item[&amp;quot;qty&amp;quot;]&lt;span class="w"&gt; &lt;/span&gt;for&lt;span class="w"&gt; &lt;/span&gt;item&lt;span class="w"&gt; &lt;/span&gt;in&lt;span class="w"&gt; &lt;/span&gt;order[&amp;quot;items&amp;quot;])
&lt;span class="w"&gt;    &lt;/span&gt;discount&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt; &lt;/span&gt;0.1&lt;span class="w"&gt; &lt;/span&gt;if&lt;span class="w"&gt; &lt;/span&gt;order.get(&amp;quot;coupon&amp;quot;)&lt;span class="w"&gt; &lt;/span&gt;==&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;SAVE10&amp;quot;&lt;span class="w"&gt; &lt;/span&gt;else&lt;span class="w"&gt; &lt;/span&gt;0.0
&lt;span class="w"&gt;    &lt;/span&gt;return&lt;span class="w"&gt; &lt;/span&gt;subtotal&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;(1&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;discount)

def&lt;span class="w"&gt; &lt;/span&gt;save_order(order:&lt;span class="w"&gt; &lt;/span&gt;dict,&lt;span class="w"&gt; &lt;/span&gt;total:&lt;span class="w"&gt; &lt;/span&gt;float)&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;None:
&lt;span class="w"&gt;    &lt;/span&gt;db.save({&amp;quot;order&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;order,&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;total&amp;quot;:&lt;span class="w"&gt; &lt;/span&gt;total})

def&lt;span class="w"&gt; &lt;/span&gt;notify_customer(email_address:&lt;span class="w"&gt; &lt;/span&gt;str,&lt;span class="w"&gt; &lt;/span&gt;total:&lt;span class="w"&gt; &lt;/span&gt;float)&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;None:
&lt;span class="w"&gt;    &lt;/span&gt;email.send(email_address,&lt;span class="w"&gt; &lt;/span&gt;f&amp;quot;Your&lt;span class="w"&gt; &lt;/span&gt;total&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mf"&gt;.2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;&amp;quot;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Use Context Managers for Resource Management&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Whenever you open a file, acquire a lock, or manage any resource that needs cleanup, use a with statement.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;#&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Risky&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;—&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;may&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;close&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;an&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;exception&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;occurs&lt;/span&gt;
&lt;span class="nv"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;open&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data.txt&amp;quot;&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;.&lt;span class="nv"&gt;read&lt;/span&gt;&lt;span class="ss"&gt;()&lt;/span&gt;
&lt;span class="nv"&gt;f&lt;/span&gt;.&lt;span class="nv"&gt;close&lt;/span&gt;&lt;span class="ss"&gt;()&lt;/span&gt;

#&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Correct&lt;/span&gt;
&lt;span class="nv"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;open&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;data.txt&amp;quot;&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;:
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;f&lt;/span&gt;.&lt;span class="nv"&gt;read&lt;/span&gt;&lt;span class="ss"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can also write your own context managers using contextlib.contextmanager:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;contextlib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;contextmanager&lt;/span&gt;

&lt;span class="nd"&gt;@contextmanager&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;temporary_directory&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mkdtemp&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;shutil&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rmtree&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Write Tests&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Untested code is code you can't safely change. Python's ecosystem makes testing straightforward — &lt;strong&gt;pytest&lt;/strong&gt; is the de facto standard.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# my_math.py&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;ZeroDivisionError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Cannot divide by zero&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;


&lt;span class="c1"&gt;# test_my_math.py&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;pytest&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;my_math&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;divide&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_divide_normal&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mf"&gt;5.0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_divide_by_zero&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raises&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ne"&gt;ZeroDivisionError&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;test_divide_floats&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;divide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;pytest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;approx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.333&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1e-3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Start with tests for your most critical logic. As a rule: if you're afraid to change a piece of code without breaking something, that's a sign it needs tests.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Use Dataclasses and Named Structures&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Avoid using plain tuples or dicts to pass related data around. Structured types make code far easier to read and maintain.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Avoid&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_admin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;is_admin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# what does index 2 mean again?&lt;/span&gt;

&lt;span class="c1"&gt;# Use dataclasses&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;dataclasses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;

&lt;span class="nd"&gt;@dataclass&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;User&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;
    &lt;span class="n"&gt;is_admin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_factory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For immutable data, @dataclass(frozen=True) works well. For validated data with complex constraints, consider &lt;strong&gt;Pydantic.&lt;/strong&gt;&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Keep Dependencies Explicit and Environments Isolated&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Use virtual environments — always. Never install packages into your system Python.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;python -m venv .venv
source .venv/bin/activate   # or .venv\Scripts\activate on Windows
pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Pin your dependencies in a requirements.txt (or better, use pyproject.toml with a tool like Poetry or uv). Unpinned dependencies lead to "it works on my machine" problems.&lt;/p&gt;
&lt;p&gt;Document what each dependency is for. If you add a package, note in your PR or commit why it's needed.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Document Thoughtfully&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Good code should be mostly self-documenting through clear naming and structure. Comments and docstrings fill the gap for why, not what.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;# Bad comment — just restates the code
x = x + 1  # increment x by 1

# Good comment — explains the reason
x = x + 1  # offset by 1 because the API uses 1-based indexing
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For public functions and classes, write docstrings:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;retry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;func&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_attempts&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;delay&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="se"&gt;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;    Call `func` repeatedly until it succeeds or max_attempts is reached.&lt;/span&gt;

&lt;span class="s2"&gt;    Args:&lt;/span&gt;
&lt;span class="s2"&gt;        func: A callable that may raise an exception.&lt;/span&gt;
&lt;span class="s2"&gt;        max_attempts: Maximum number of tries before re-raising the last exception.&lt;/span&gt;
&lt;span class="s2"&gt;        delay: Seconds to wait between attempts.&lt;/span&gt;

&lt;span class="s2"&gt;    Returns:&lt;/span&gt;
&lt;span class="s2"&gt;        The return value of `func` on success.&lt;/span&gt;

&lt;span class="s2"&gt;    Raises:&lt;/span&gt;
&lt;span class="s2"&gt;        The last exception raised by `func` if all attempts fail.&lt;/span&gt;
&lt;span class="s2"&gt;    &lt;/span&gt;&lt;span class="se"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Putting It Together&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Clean Python code is not about following every rule perfectly — it's about making considered choices that reduce cognitive load for the next person who reads your code (often yourself). Start with the habits that give you the most immediate value: meaningful names, type hints, small focused functions, and tests. The rest follows naturally.&lt;/p&gt;
&lt;p&gt;The best Python developers aren't the ones who know the most obscure features — they're the ones who make their intent obvious and their code easy to change.&lt;/p&gt;</content><category term="Article"/><category term="Python"/><category term="coding"/></entry><entry><title>The Psychology Behind Great UI Design</title><link href="https://athiraraghu-blr.github.io/psychology-ui-design.html" rel="alternate"/><published>2026-06-25T00:00:00+05:30</published><updated>2026-06-25T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-25:/psychology-ui-design.html</id><summary type="html">&lt;p&gt;Why the best interfaces feel effortless — and the science that makes them that way.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Great UI design looks simple. A button is in exactly the right place. A form feels easy to complete. A dashboard communicates complexity without overwhelming you. None of this happens by accident. Behind every polished …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Why the best interfaces feel effortless — and the science that makes them that way.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Great UI design looks simple. A button is in exactly the right place. A form feels easy to complete. A dashboard communicates complexity without overwhelming you. None of this happens by accident. Behind every polished interface is a body of psychological research about how humans perceive, process, decide, and act.&lt;/p&gt;
&lt;p&gt;Designers who understand this research don't just make things pretty — they make things work with the human brain rather than against it. This article explores the core psychological principles that separate good UI from great UI, and how each one manifests in the interfaces you use every day.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Cognitive Load: The Invisible Budget&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Every user arrives at your interface with a finite amount of mental energy. Cognitive load is the total mental effort required to process information at any given moment. When that budget runs out, users make mistakes, feel frustrated, and leave.&lt;/p&gt;
&lt;p&gt;Psychologist John Sweller identified three types of cognitive load:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Intrinsic load&lt;/strong&gt; — the inherent complexity of the task itself&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Extraneous load&lt;/strong&gt; — unnecessary complexity introduced by poor design&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Germane load&lt;/strong&gt; — mental effort spent building useful understanding&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Great UI design's first job is to eliminate extraneous load entirely. Every unnecessary animation, redundant label, decorative element, or ambiguous icon is tax on the user's mental budget that returns nothing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Group related controls together so users don't hunt&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use progressive disclosure — reveal advanced options only when needed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Write microcopy that answers the question before users think to ask it&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Remove anything that doesn't serve a function&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Google's search homepage is the canonical example: a single input field and two buttons. The entire complexity of a trillion-page index is hidden behind radical simplicity.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Hick's Law: The Cost of Choice&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;In 1952, psychologists William Edmund Hick and Ray Hyman formalized something intuitive: &lt;strong&gt;the more choices you give someone, the longer it takes them to decide&lt;/strong&gt;. More precisely, decision time increases logarithmically with the number of options.&lt;/p&gt;
&lt;p&gt;This has direct consequences for navigation menus, settings panels, onboarding flows, and dashboards. A navigation bar with twelve items isn't twelve times harder to use than one with six — it's cognitively exhausting in a way that creates resistance even before users click anything.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Limit primary navigation to five to seven items&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Break complex forms into steps rather than presenting everything at once&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use sensible defaults so users who don't care can move forward immediately&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Categorize and group options rather than listing them alphabetically in a flat wall of choices&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The principle is not "fewer options are always better" — it's that every additional choice has a cost, and that cost should be justified by genuine user need.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Miller's Law: The Magic Number Seven&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;In 1956, cognitive psychologist George Miller published one of the most cited papers in psychology, observing that human working memory can hold roughly &lt;strong&gt;seven items (plus or minus two)&lt;/strong&gt; at a time. Working memory is the mental scratch pad where we hold information while processing it.&lt;/p&gt;
&lt;p&gt;If you present more than seven distinct items in a list, a menu, or a dashboard panel, users can't hold them all in mind simultaneously. They must scan repeatedly, increasing cognitive load and error rates.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Chunk navigation, form fields, and feature lists into groups of five to nine&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Break long forms into logical sections with clear headings&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In data tables, consider which columns are truly necessary before displaying everything&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use visual separators to create implied chunks even within longer lists&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Phone numbers, credit card numbers, and ZIP codes are all chunked for exactly this reason — 4111 1111 1111 1111 is dramatically easier to process than 4111111111111111.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Gestalt Principles: How We See Patterns&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The Gestalt psychologists of early 20th-century Germany discovered that the human visual system is fundamentally a pattern-completion machine. We don't see individual pixels — we see groups, relationships, and wholes. Several Gestalt principles are directly load-bearing in UI design.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Proximity&lt;/strong&gt; — Elements close to each other are perceived as related. A label placed near its input field is understood as belonging to it; the same label placed far away creates confusion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Similarity&lt;/strong&gt; — Elements that look alike are perceived as part of the same group. Consistent button styles across an application tell users "these all do the same kind of thing."&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Continuity&lt;/strong&gt; — The eye naturally follows lines and curves. This is why progress steps are shown as a horizontal line rather than a vertical list — it implies a journey toward completion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Closure&lt;/strong&gt; — We mentally complete incomplete shapes. This is why icon outlines, dashed borders, and partially visible cards (hinting at scrollable content) all work without requiring full visual completion.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Figure/Ground&lt;/strong&gt; — We instinctively separate a foreground subject from a background. Modal dialogs leverage this by dimming the page behind them — the modal becomes figure, the rest becomes ground.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use spacing intentionally: proximity is a communication tool, not just aesthetics&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maintain strict visual consistency for interactive elements (buttons, links, inputs)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use alignment to create implied columns and relationships without explicit borders&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Let the figure/ground distinction do work: dark overlays, elevated cards, and drop shadows all exploit this perceptual instinct&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;The Von Restorff Effect: Stand Out or Be Invisible&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Also called the &lt;strong&gt;isolation effect&lt;/strong&gt;, this principle states that an item that differs from its surroundings is more likely to be remembered and noticed. Hermann von Restorff demonstrated in 1933 that a single distinctive item in a list was recalled far more reliably than identical items.&lt;/p&gt;
&lt;p&gt;Every UI has a hierarchy of importance — primary actions, secondary actions, passive information. The Von Restorff effect is what makes that hierarchy visible.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;A filled, colored primary button surrounded by ghost buttons draws the eye and signals "this is what most people do here"&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A red error badge on an otherwise monochrome navigation bar is impossible to miss&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A highlighted pricing plan in a comparison table reliably drives more conversions than three equally styled plans&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Overusing the effect destroys it — if everything is highlighted, nothing is&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;The Serial Position Effect: First and Last&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;When users scan a list of items, they remember the &lt;strong&gt;first items&lt;/strong&gt; (primacy effect) and &lt;strong&gt;last items&lt;/strong&gt; (recency effect) far better than those in the middle. Items buried in the center of a long navigation, a feature list, or a menu suffer what is called the "middle penalty."&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Place the most important navigation items first or last, not in the middle&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In pricing tables, position your recommended plan at either end — or break the middle penalty by using visual emphasis (Von Restorff) to compensate&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Put calls to action at the end of a content page — where recency works in your favor after the user has read through&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In onboarding flows, make the first and last steps memorable; the middle can carry the functional burden&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Fitts's Law: The Physics of Clicking&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Paul Fitts formalized in 1954 what motor control researchers had observed for years: &lt;strong&gt;the time to acquire a target is a function of the distance to it and its size&lt;/strong&gt;. A large button close to your cursor is faster to click than a small button far away — obvious in retrospect, but the formula has precise implications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Make primary action buttons large, especially on mobile where finger targets are imprecise&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Position frequently used controls near where the user's cursor or thumb naturally rests&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Destructive actions (delete, remove) should be small and far from common actions — making them harder to hit by accident&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The corners and edges of a screen are infinitely large targets in the Fitts sense, because the cursor cannot overshoot them. This is why macOS puts its menu bar at the very top edge of the screen rather than inside each window.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Fitts's Law is why mobile "thumb zones" matter. The bottom-center of a phone screen is the easiest target for one-handed use. The top corners are the hardest. Tab bars are at the bottom for a reason.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Peak-End Rule: What Users Actually Remember&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Daniel Kahneman's &lt;strong&gt;peak-end rule&lt;/strong&gt; states that humans don't remember an experience as an average of all its moments — they remember it primarily by how it felt at its most intense moment (the peak) and at its very end. The duration of the experience matters far less than we'd expect.&lt;/p&gt;
&lt;p&gt;This is why a checkout flow that's smooth for nine steps but fumbles on the payment screen feels like a bad experience overall. And it's why a loading screen with a delightful animation, or a success confirmation with a satisfying micro-interaction, can make an otherwise ordinary product feel premium.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Identify the peak moment of your flow (usually the moment of primary value delivery) and make it exceptional&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pay extraordinary attention to error states — a poorly handled error is often the peak of the worst experience&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Design success states with care: a warm confirmation screen after completing a complex form is disproportionately valuable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Onboarding's final step should feel like an arrival, not a cutoff&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;The Aesthetic-Usability Effect&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Users perceive &lt;strong&gt;visually attractive interfaces as easier to use&lt;/strong&gt;, even when the underlying functionality is identical to an unattractive one. This was demonstrated by Masaaki Kurosu and Kaori Kashimura in 1995 and has been replicated repeatedly.&lt;/p&gt;
&lt;p&gt;The implication is counterintuitive: beauty is not decoration. It directly affects perceived usability, user trust, and willingness to tolerate minor friction. A gorgeous onboarding flow will be forgiven for an extra step that an ugly one would not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Visual quality signals product quality — a polished interface implies a polished product&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consistent typography, generous whitespace, and thoughtful color use are functional, not cosmetic&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dark patterns and deliberately ugly "dark mode" UIs violate this principle: bad aesthetics create distrust even when functionality is fine&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;First impressions form in milliseconds; invest in what users see before they interact&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Familiarity and the Jakob's Law Principle&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;UX researcher Jakob Nielsen articulated a principle so intuitive it's easy to overlook: &lt;strong&gt;users spend most of their time on other websites&lt;/strong&gt;. They bring mental models built from years of using other products. When your interface matches those models, it feels intuitive. When it departs from them without good reason, it creates friction.&lt;/p&gt;
&lt;p&gt;The hamburger menu, the shopping cart in the top right, search at the top center, the logo linking to the home page — these are conventions so established that departing from them costs real usability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Don't reinvent interactions that are already universal; innovate on top of conventions, not against them&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you must break a convention, use familiar affordances and onboarding to teach the new pattern&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consistency within your own product is equally important — if something works one way on screen A, it should work the same way on screen B&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Familiarity is not sameness. The goal is reducing the learning curve, not eliminating personality.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Emotional Design: The Three Levels&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Don Norman, author of The Design of Everyday Things, describes three levels at which design operates emotionally:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Visceral&lt;/strong&gt; — the immediate, pre-conscious emotional reaction to appearance. Does this feel good to look at? Does it signal safety, competence, playfulness?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Behavioral&lt;/strong&gt; — the pleasure (or frustration) of use. Does it respond fluidly? Does feedback arrive immediately? Does it behave predictably?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reflective&lt;/strong&gt; — the story users tell themselves about the product. Does using this make me feel capable? Does it reflect my identity? Would I recommend it?&lt;/p&gt;
&lt;p&gt;Most UI design focuses on the behavioral level and ignores the visceral and reflective. But users who feel something positive about a product tolerate more friction, convert at higher rates, and recommend it unprompted.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In Practice&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Visceral: invest in motion design, illustration, and typography as emotional communicators&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Behavioral: obsess over response time, transition smoothness, and the feel of interactions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reflective: write in a voice that respects the user's intelligence and time; celebrate their accomplishments&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Conclusion: Designing With the Grain of the Brain&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The best UI designers are, at their core, applied psychologists. They understand that every layout decision, color choice, interaction pattern, and word of microcopy is a hypothesis about human behavior. The principles covered here — cognitive load, Hick's Law, Gestalt perception, the peak-end rule, Fitts's Law, emotional design — aren't abstract theory. They're the structural grammar of interfaces that feel effortless.&lt;/p&gt;
&lt;p&gt;Design that ignores psychology produces interfaces users can operate. Design that embraces it produces interfaces users love. The gap between the two is not talent or taste — it's understanding what happens inside the human brain between the moment a screen appears and the moment a finger moves.&lt;/p&gt;
&lt;p&gt;Build with that understanding, and the rest follows.&lt;/p&gt;</content><category term="Article"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/></entry><entry><title>Hugging Face: A Beginner's Guide</title><link href="https://athiraraghu-blr.github.io/hugging-face-begginers-guide.html" rel="alternate"/><published>2026-06-24T00:00:00+05:30</published><updated>2026-06-24T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-24:/hugging-face-begginers-guide.html</id><summary type="html">&lt;p&gt;Everything You Need to Get Started with AI Models, Datasets, and the Transformers Library&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;What Is Hugging Face?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;If you've been exploring the world of AI and machine learning, you've probably come across the name Hugging Face. Think of it as the GitHub of AI — a platform where researchers, developers …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Everything You Need to Get Started with AI Models, Datasets, and the Transformers Library&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;What Is Hugging Face?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;If you've been exploring the world of AI and machine learning, you've probably come across the name Hugging Face. Think of it as the GitHub of AI — a platform where researchers, developers, and companies share pre-trained models, datasets, and tools that anyone can download and use for free.&lt;/p&gt;
&lt;p&gt;You don't need to train a model from scratch to build something useful with AI. Hugging Face gives you access to thousands of ready-made models that can understand text, generate images, transcribe audio, translate languages, and much more — all with just a few lines of Python.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Key Concepts to Know&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Before jumping into code, it helps to understand a few terms you'll see constantly on Hugging Face.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Models&lt;/strong&gt; are the core of everything. A model is a file (or set of files) that has already been trained on large amounts of data and learned to perform a specific task — like answering questions or summarizing text. You download a model and use it directly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Datasets&lt;/strong&gt; are collections of data used to train or evaluate models. Hugging Face hosts thousands of public datasets you can load with a single line of code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Hub&lt;/strong&gt; is Hugging Face's online repository at huggingface.co. You browse it like a marketplace — search for a model by task or name, read its documentation, and pull it into your project.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transformers&lt;/strong&gt; is Hugging Face's most popular Python library. It gives you a simple interface to download and run models without worrying about the underlying complexity.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Installing the Library&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Getting started takes just one command:&lt;/p&gt;
&lt;p&gt;bash &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install transformers
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For most tasks you'll also want PyTorch installed alongside it:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install torch
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's all you need to run your first model locally.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Your First Model: The Pipeline&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The easiest way to use a model in Hugging Face is through the pipeline function. It handles everything for you — downloading the model, loading it, and running your input through it.&lt;/p&gt;
&lt;p&gt;Here's a sentiment analysis example that tells you whether a piece of text is positive or negative:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;transformers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;

&lt;span class="n"&gt;classifier&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sentiment-analysis&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;classifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;I love using Hugging Face — it makes AI so accessible!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# [{&amp;#39;label&amp;#39;: &amp;#39;POSITIVE&amp;#39;, &amp;#39;score&amp;#39;: 0.9998}]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That's it. Three lines of code and you have a working AI classifier. The first time you run it, the library downloads the model automatically. After that, it's cached locally so it loads instantly.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Common Tasks You Can Do with Pipelines&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The pipeline function supports a wide range of tasks out of the box. Here are some of the most useful ones for beginners.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Text Summarization&lt;/strong&gt; — condense a long piece of text into a short summary:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;summarizer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;summarization&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;
&lt;span class="s2"&gt;Hugging Face is an AI company that hosts a platform for sharing machine learning&lt;/span&gt;
&lt;span class="s2"&gt;models and datasets. It provides tools that make it easy to use state-of-the-art&lt;/span&gt;
&lt;span class="s2"&gt;models without needing deep expertise in machine learning. The platform has&lt;/span&gt;
&lt;span class="s2"&gt;become one of the most popular destinations for AI researchers and developers.&lt;/span&gt;
&lt;span class="s2"&gt;&amp;quot;&amp;quot;&amp;quot;&lt;/span&gt;

&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;summarizer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;min_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;summary_text&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Question Answering&lt;/strong&gt; — extract an answer from a block of text:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;qa&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;pipeline&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;question-answering&amp;quot;&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;qa&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;question&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;What does Hugging Face host?&amp;quot;&lt;/span&gt;,
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;context&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Hugging Face is a platform for sharing machine learning models and datasets.&amp;quot;&lt;/span&gt;
&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;print&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;result&lt;/span&gt;[&lt;span class="s2"&gt;&amp;quot;answer&amp;quot;&lt;/span&gt;]&lt;span class="ss"&gt;)&lt;/span&gt;
#&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;models&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;datasets&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Text Generation&lt;/strong&gt; — generate text that continues from a prompt:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;generator = pipeline(&amp;quot;text-generation&amp;quot;, model=&amp;quot;gpt2&amp;quot;)

output = generator(&amp;quot;Once upon a time in a land of code,&amp;quot;, max_length=50)
print(output[0][&amp;quot;generated_text&amp;quot;])
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Translation&lt;/strong&gt; — translate text between languages:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;translator = pipeline(&amp;quot;translation_en_to_fr&amp;quot;)

result = translator(&amp;quot;Hugging Face makes machine learning easy.&amp;quot;)
print(result[0][&amp;quot;translation_text&amp;quot;])
&lt;span class="gh"&gt;#&lt;/span&gt; Hugging Face rend l&amp;#39;apprentissage automatique facile.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Browsing the Hub&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;The real power of Hugging Face is the sheer variety of models available. Head to huggingface.co/models and you'll find filters for:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Task&lt;/strong&gt; — text classification, image generation, speech recognition, and more&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Language&lt;/strong&gt; — English, French, Hindi, Arabic, and dozens of others&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Library&lt;/strong&gt; — PyTorch, TensorFlow, JAX&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each model page shows you a description, example usage, and often a live demo you can try in your browser before downloading anything.&lt;/p&gt;
&lt;p&gt;To use a specific model from the Hub, just pass its name to the pipeline:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Using a specific multilingual model&lt;/span&gt;
&lt;span class="n"&gt;classifier&lt;/span&gt; = &lt;span class="n"&gt;pipeline&lt;/span&gt;(&lt;span class="s"&gt;&amp;quot;sentiment-analysis&amp;quot;&lt;/span&gt;, &lt;span class="n"&gt;model&lt;/span&gt;=&lt;span class="s"&gt;&amp;quot;nlptown/bert-base-multilingual-uncased-sentiment&amp;quot;&lt;/span&gt;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Loading Datasets&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Hugging Face also makes it easy to work with datasets through the datasets library:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install datasets
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;datasets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;load_dataset&lt;/span&gt;

&lt;span class="n"&gt;dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;load_dataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;imdb&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataset&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;train&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="c1"&gt;# {&amp;#39;text&amp;#39;: &amp;#39;I love this movie...&amp;#39;, &amp;#39;label&amp;#39;: 1}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The load_dataset function downloads the dataset, caches it locally, and gives you a clean object to work with. No manual downloading or file parsing required.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Creating a Free Account&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;You don't need an account to download public models or datasets, but creating one at huggingface.co unlocks a few useful things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Upload and shar&lt;/strong&gt;e your own models or datasets&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Access gated models&lt;/strong&gt; — some powerful models require you to agree to terms before downloading&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Use the Inference API&lt;/strong&gt; — run models in the cloud without downloading them locally&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Create Spaces&lt;/strong&gt; — free hosted demos for your AI apps using Gradio or Streamlit&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Hugging Face removes most of the friction from working with AI. You don't need a research background or a powerful GPU to get started — a free account and a few lines of Python are enough to run state-of-the-art models on your own machine.&lt;/p&gt;
&lt;p&gt;Here's what to take away from this guide: the Hub is your library of ready-made models, the transformers library is how you use them in Python, and the pipeline function is your simplest entry point. Start there, explore the model pages, and try swapping in different models for the same task — that's the fastest way to get a feel for what's possible.&lt;/p&gt;
&lt;p&gt;The rest — fine-tuning, training your own models, deploying to production — can come later. For now, the most important step is running your first pipeline and seeing AI work with your own eyes.&lt;/p&gt;</content><category term="Article"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/></entry><entry><title>FastAPI + Jinja2 vs React: Choosing the Right Frontend</title><link href="https://athiraraghu-blr.github.io/fastapi-jinja2-reat-frontend.html" rel="alternate"/><published>2026-06-23T00:00:00+05:30</published><updated>2026-06-23T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-23:/fastapi-jinja2-reat-frontend.html</id><summary type="html">&lt;h1&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;When building a web application with FastAPI, one of the earliest decisions you'll face is how to handle the frontend. Do you render HTML on the server using Jinja2 templates, or do you build a separate React single-page application that talks to your API? Both approaches are legitimate, widely …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;When building a web application with FastAPI, one of the earliest decisions you'll face is how to handle the frontend. Do you render HTML on the server using Jinja2 templates, or do you build a separate React single-page application that talks to your API? Both approaches are legitimate, widely used, and well-supported — but they suit very different kinds of projects.&lt;/p&gt;
&lt;p&gt;This article breaks down both options honestly, so you can make the right call for your specific situation.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;What Is FastAPI + Jinja2?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Jinja2 is a templating engine that lets you render HTML on the server side. FastAPI has built-in support for it through the Jinja2Templates class. When a user visits a page, FastAPI fetches the data, injects it into an HTML template, and sends a fully rendered page back to the browser.&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi.templating&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Jinja2Templates&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;templates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Jinja2Templates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;directory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;templates&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/dashboard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;dashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;user&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Alice&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;tasks&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Deploy app&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Write tests&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;templates&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TemplateResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;dashboard.html&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;request&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The corresponding dashboard.html might look like:&lt;/p&gt;
&lt;p&gt;html&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Welcome, &lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;user&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;task&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;tasks&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;{{&lt;/span&gt; &lt;span class="nv"&gt;task&lt;/span&gt; &lt;span class="cp"&gt;}}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="cp"&gt;{%&lt;/span&gt; &lt;span class="k"&gt;endfor&lt;/span&gt; &lt;span class="cp"&gt;%}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Everything happens on the server. The browser receives plain HTML — no JavaScript framework required.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;What Is React (as a Separate Frontend)?&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;React is a JavaScript library for building interactive user interfaces. In a FastAPI + React setup, FastAPI serves only as a JSON API, while React runs entirely in the browser and handles all rendering, routing, and state management.&lt;/p&gt;
&lt;p&gt;javascript&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// React fetches data from FastAPI&lt;/span&gt;
&lt;span class="n"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/api/dashboard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;setDashboard&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The two parts of your application — the FastAPI backend and the React frontend — are developed, built, and often deployed independently.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Key Differences at a Glance&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Rendering location&lt;/strong&gt;: Jinja2 renders HTML on the server before sending it to the browser. React renders in the browser using JavaScript after receiving raw data from the API.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Project structure&lt;/strong&gt;: Jinja2 keeps everything in one Python project. React introduces a second codebase with its own tooling, dependencies, and build process.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Interactivity&lt;/strong&gt;: Jinja2 pages reload fully on each navigation, though you can sprinkle in JavaScript or HTMX for lighter interactivity. React handles complex interactions, animations, and real-time updates natively without page reloads.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Initial load&lt;/strong&gt;: Jinja2 pages display content immediately since HTML is fully rendered before arriving in the browser. React apps require JavaScript to download and execute first, which can delay the initial render unless you add server-side rendering.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SEO&lt;/strong&gt;: Server-rendered Jinja2 pages are crawled easily by search engines. React apps need extra configuration (SSR or pre-rendering) to be fully SEO-friendly.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;When to Choose FastAPI + Jinja2&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Jinja2 is the right choice when simplicity and speed of development matter more than a rich interactive experience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Internal tools and admin dashboards&lt;/strong&gt; are a classic use case. If you're building a back-office dashboard for your team — displaying tables, forms, and reports — there's rarely a need for the complexity of a React app. A clean Jinja2 template with some CSS gets the job done faster.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Content-heavy or document-like pages&lt;/strong&gt; such as blogs, documentation sites, or e-commerce product pages benefit from server-side rendering. Pages arrive fully formed, load quickly, and are immediately indexable by search engines.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Small teams or solo developers&lt;/strong&gt; working across the full stack will move much faster with a single Python codebase. There's no context-switching between JavaScript and Python, no separate build pipeline, and no API contract to maintain between two codebases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prototypes and MVPs&lt;/strong&gt; are best built with the least moving parts. Jinja2 lets you go from idea to working product quickly without making long-term architectural commitments upfront.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;When to Choose React&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;React earns its complexity when your frontend needs to behave more like an application than a document.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Highly interactive UIs&lt;/strong&gt; — think drag-and-drop editors, real-time dashboards, multi-step forms with live validation, or collaborative tools — are where React shines. Managing that kind of state in Jinja2 templates quickly becomes painful.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Single-page applications&lt;/strong&gt; that need smooth, app-like navigation without full page reloads are a natural fit for React. Users expect desktop-app responsiveness, and React delivers it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Separate frontend and backend teams&lt;/strong&gt; work better with a clear API boundary. React enforces this separation naturally — the frontend team owns the React app, the backend team owns the FastAPI service, and they collaborate through a shared API contract.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mobile apps or multiple clients&lt;/strong&gt; down the road become much easier if your FastAPI backend is already a clean JSON API. You can build a React web app today and a React Native mobile app tomorrow without changing the backend at all.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;The Middle Ground: HTMX&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;It's worth mentioning a third option that sits between the two: &lt;strong&gt;HTMX&lt;/strong&gt;. HTMX lets you add dynamic, AJAX-style interactions to your Jinja2 templates without writing JavaScript or adopting a full frontend framework. You annotate HTML elements with attributes, and HTMX handles partial page updates.&lt;/p&gt;
&lt;p&gt;html&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;hx-get=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/api/tasks&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;hx-target=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;#task-list&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;Refresh&lt;span class="w"&gt; &lt;/span&gt;Tasks
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;task-list&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;FastAPI + Jinja2 + HTMX is a compelling stack for applications that need more interactivity than plain HTML but don't need the full power of React. It keeps your project as a single Python codebase while enabling dynamic behavior.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Making the Decision&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Ask yourself these questions before choosing:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How interactive does the UI need to be?&lt;/strong&gt; If users are mostly reading content or filling out simple forms, Jinja2 is enough. If they're manipulating data in real time, filtering tables, or working with complex UI flows, lean toward React.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How many people are building this?&lt;/strong&gt; A solo developer or small team moves faster with Jinja2. A larger team with dedicated frontend engineers benefits from the clear separation React provides.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Do you need SEO out of the box?&lt;/strong&gt; If yes, Jinja2 wins without any extra configuration. React requires additional work to get there.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Are you building for multiple platforms?&lt;/strong&gt; If a mobile app is on the roadmap, build a clean API-first FastAPI backend and pair it with React from the start.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;What's your timeline?&lt;/strong&gt; Jinja2 gets you to a working product faster. React pays off over time when the UI grows complex enough to justify the overhead.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;FastAPI + Jinja2 and React are both excellent choices — they just solve different problems. Jinja2 keeps things simple, fast to build, and SEO-friendly, making it ideal for content pages, admin tools, and straightforward web apps. React is the right investment when you need a rich, interactive, app-like experience or when you're building for multiple clients and teams.&lt;/p&gt;
&lt;p&gt;If you're still unsure, start with Jinja2. It's easier to evolve toward React later than to simplify a React app that turned out to be overkill. And if you need a little more dynamism without the full React commitment, give HTMX a look — it might be exactly the middle ground you need.&lt;/p&gt;</content><category term="Article"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/></entry><entry><title>Developing and Deploying a React &amp; FastAPI Application on Ubuntu</title><link href="https://athiraraghu-blr.github.io/developing-deploying-fastapi-react-ubuntu.html" rel="alternate"/><published>2026-06-22T00:00:00+05:30</published><updated>2026-06-22T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-22:/developing-deploying-fastapi-react-ubuntu.html</id><summary type="html">&lt;p&gt;Building modern web applications often means pairing a dynamic frontend with a robust backend API. React and FastAPI are a popular combination — React for its component-driven UI, and FastAPI for its speed, simplicity, and automatic API documentation. This article walks you through setting up, developing, and deploying both on an …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Building modern web applications often means pairing a dynamic frontend with a robust backend API. React and FastAPI are a popular combination — React for its component-driven UI, and FastAPI for its speed, simplicity, and automatic API documentation. This article walks you through setting up, developing, and deploying both on an Ubuntu server.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Before diving in, make sure your Ubuntu system (20.04 or 22.04 LTS recommended) has the following installed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Node.js&lt;/strong&gt; (v18+) and &lt;strong&gt;npm&lt;/strong&gt; — for the React frontend&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Python&lt;/strong&gt; (3.10+) and &lt;strong&gt;pip&lt;/strong&gt; — for the FastAPI backend&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Nginx&lt;/strong&gt; — to serve as a reverse proxy&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git&lt;/strong&gt; — for version control&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;Install the basics in one go:&lt;/h1&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y
sudo apt install -y git nginx python3-pip python3-venv curl

&lt;span class="gh"&gt;#&lt;/span&gt;Install Node.js via NodeSource
    curl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -
    sudo apt install -y nodejs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;strong&gt;Part 1: Building the FastAPI Backend&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;1.1 Project Setup&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a project directory and set up a Python virtual environment:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;mkdir ~/myapp &amp;amp;&amp;amp; cd ~/myapp
mkdir backend &amp;amp;&amp;amp; cd backend
python3 -m venv venv
source venv/bin/activate
pip install fastapi uvicorn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;1.2 Writing the API&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create a file called main.py:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi.middleware.cors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;CORSMiddleware&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;allow_origins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  &lt;span class="c1"&gt;# Restrict in production&lt;/span&gt;
    &lt;span class="n"&gt;allow_methods&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;allow_headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Hello from FastAPI!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/items/&lt;/span&gt;&lt;span class="si"&gt;{item_id}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;item_id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Item &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;item_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;1.3 Running the Backend Locally&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;uvicorn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;reload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Visit http://localhost:8000/docs to see FastAPI's auto-generated Swagger documentation.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Part 2: Building the React Frontend&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;2.1 Create a React App&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;From the ~/myapp directory:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~/myapp
npx create-react-app frontend
cd frontend
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2.2 Fetching Data from the API&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Edit src/App.js to call your FastAPI backend:&lt;/p&gt;
&lt;p&gt;javascript&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;useState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;react&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;function&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Loading...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;http://localhost:8000/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
            &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;setMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;2rem&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fontFamily&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;sans-serif&amp;quot;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;React&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;h1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;export&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt; &lt;span class="n"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;2.3 Running the Frontend Locally&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;npm start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The React app will be available at http://localhost:3000.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Part 3: Deploying on Ubuntu&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;3.1 Build the React App&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When you're ready to deploy, produce a production build:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~/myapp/frontend
npm run build
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This creates an optimized build/ folder ready to be served as static files.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3.2 Run FastAPI with a Process Manager&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Install and configure &lt;strong&gt;Gunicorn&lt;/strong&gt; with &lt;strong&gt;Uvicorn workers&lt;/strong&gt; so the backend runs reliably:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cd ~/myapp/backend
source venv/bin/activate
pip install gunicorn
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create a &lt;strong&gt;systemd service&lt;/strong&gt; to keep it running:&lt;/p&gt;
&lt;p&gt;bash &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/systemd/system/fastapi.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;ini&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;FastAPI Application&lt;/span&gt;
&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;
&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="na"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/ubuntu/myapp/backend&lt;/span&gt;
&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/ubuntu/myapp/backend/venv/bin/gunicorn -k uvicorn.workers.UvicornWorker main:app --bind 0.0.0.0:8000&lt;/span&gt;
&lt;span class="na"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Enable and start the service:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;systemctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;daemon&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;reload&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;systemctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fastapi&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;systemctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fastapi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3.3 Configure Nginx as a Reverse Proxy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Create an Nginx configuration file:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo nano /etc/nginx/sites-available/myapp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;nginx&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IP&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Serve&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;frontend&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;home&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;ubuntu&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;myapp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;frontend&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;build&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;try_files&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;uri&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Proxy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;API&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;requests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FastAPI&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="kn"&gt;api&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;proxy_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="c1"&gt;//127.0.0.1:8000/;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;Real&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="nx"&gt;remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Enable the site and restart Nginx:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;3.4 (Optional) Enable HTTPS with Certbot&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Certbot will automatically configure SSL and set up certificate renewal.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Part 4: Updating Your Application&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;When you push code changes, here's a simple update workflow:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;#Pull latest code
cd ~/myapp &amp;amp;&amp;amp; git pull

#Rebuild the frontend
cd frontend &amp;amp;&amp;amp; npm install &amp;amp;&amp;amp; npm run build

#Restart the backend service
sudo systemctl restart fastapi
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Summary&lt;/p&gt;
&lt;p&gt;By following this guide, you've put together a solid, production-ready stack on Ubuntu. The React frontend is compiled into static files and served efficiently by Nginx on port 80, keeping page load times fast without any server-side rendering overhead. Behind the scenes, FastAPI runs on port 8000, powered by Uvicorn workers and managed by Gunicorn, with systemd ensuring the process restarts automatically if anything goes wrong.&lt;/p&gt;
&lt;p&gt;Nginx acts as the glue between the two — routing ordinary browser requests to the React build and forwarding any calls to &lt;strong&gt;/api/&lt;/strong&gt; directly to FastAPI. This means both your frontend and backend live under the same domain, avoiding cross-origin headaches in production. If you've added Certbot to the mix, all traffic is encrypted over HTTPS with certificates that renew themselves automatically.&lt;/p&gt;
&lt;p&gt;The result is an architecture that's clean, maintainable, and easy to update — just pull your latest code, rebuild the frontend, and restart the backend service. From here, you can extend it further with Docker, CI/CD pipelines, or a managed database, but the foundation you've built is already well-suited for real-world use.&lt;/p&gt;</content><category term="Article"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/></entry><entry><title>End-to-End Development Workflow Using Ubuntu, FastAPI, SQL, and React</title><link href="https://athiraraghu-blr.github.io/ubuntu-fastapi-sql-react.html" rel="alternate"/><published>2026-06-21T00:00:00+05:30</published><updated>2026-06-21T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-21:/ubuntu-fastapi-sql-react.html</id><summary type="html">&lt;p&gt;Ubuntu, FastAPI, SQL, and React form a powerful full-stack workflow for building modern web applications from backend to frontend.&lt;/p&gt;
&lt;h1&gt;Why This Stack&lt;/h1&gt;
&lt;p&gt;Each piece of this stack earns its place for specific reasons:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ubuntu&lt;/strong&gt; is the default operating system for most cloud servers and is widely supported by package managers …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Ubuntu, FastAPI, SQL, and React form a powerful full-stack workflow for building modern web applications from backend to frontend.&lt;/p&gt;
&lt;h1&gt;Why This Stack&lt;/h1&gt;
&lt;p&gt;Each piece of this stack earns its place for specific reasons:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Ubuntu&lt;/strong&gt; is the default operating system for most cloud servers and is widely supported by package managers, container tools, and CI/CD systems, making it a dependable foundation for both local development and production deployment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;FastAPI&lt;/strong&gt; is a modern Python web framework built on async I/O and Python type hints. It automatically generates interactive API documentation (via OpenAPI/Swagger) and validates request/response data using Pydantic models, which speeds up backend development considerably.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SQL databases&lt;/strong&gt; (PostgreSQL, MySQL, or SQLite for prototyping) provide reliable, structured, transactional storage — essential for applications with relational data like users, orders, or inventory.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;React&lt;/strong&gt; remains one of the most popular libraries for building interactive, component-based user interfaces, with a vast ecosystem of tooling and community support.&lt;/p&gt;
&lt;p&gt;Together, these four layers form a clean separation of concerns: OS and infrastructure, data layer, API layer, and presentation layer.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 1: Setting Up the Ubuntu Environment&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Start by preparing a clean, reproducible development environment.&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;p&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y
  sudo apt install -y python3 python3-venv python3-pip \
      postgresql postgresql-contrib \
      nodejs npm \
      git curl build-essential&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A few practical notes:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Use python3-venv to isolate Python dependencies per project rather than installing packages globally.&lt;/p&gt;
&lt;p&gt;Install &lt;strong&gt;Node.js via nvm&lt;/strong&gt; (Node Version Manager) instead of the default Ubuntu repository if you need to manage multiple Node versions across projects.&lt;/p&gt;
&lt;p&gt;Set up &lt;strong&gt;Git&lt;/strong&gt; early and configure SSH keys for your remote repository (GitHub, GitLab, etc.), since version control should track changes from the very first commit.&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;p&gt;curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
  nvm install --lts&lt;/p&gt;
&lt;p&gt;This base setup gives you a consistent environment that mirrors what you’d run in production, reducing “it works on my machine” issues later.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 2: Designing the SQL Database&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Before writing any backend code, design your schema. A relational database enforces structure and relationships that prevent data inconsistency.&lt;/p&gt;
&lt;p&gt;Start PostgreSQL and create a database:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;p&gt;sudo -u postgres createuser --interactive
  sudo -u postgres createdb myapp_db&lt;/p&gt;
&lt;p&gt;Define your schema with clear tables, primary keys, and foreign key relationships. For example, a simple task-management app might have:&lt;/p&gt;
&lt;p&gt;sql
    CREATE TABLE users (
        id SERIAL PRIMARY KEY,
        email VARCHAR(255) UNIQUE NOT NULL,
        hashed_password VARCHAR(255) NOT NULL,
        created_at TIMESTAMP DEFAULT NOW()
  );
    CREATE TABLE tasks (
        id SERIAL PRIMARY KEY,
        user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
        title VARCHAR(255) NOT NULL,
        is_complete BOOLEAN DEFAULT FALSE,
        created_at TIMESTAMP DEFAULT NOW()
 );&lt;/p&gt;
&lt;p&gt;Key practices at this stage:&lt;/p&gt;
&lt;p&gt;Normalize data to avoid duplication, but don’t over-normalize to the point of hurting query performance.&lt;/p&gt;
&lt;p&gt;Add indexes on columns you’ll frequently filter or join on.&lt;/p&gt;
&lt;p&gt;Use migrations (via &lt;strong&gt;Alembic&lt;/strong&gt;, which pairs naturally with FastAPI and SQLAlchemy) instead of hand-editing the schema, so changes are tracked and reversible.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 3: Building the Backend with FastAPI&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;With the database ready, connect it to a FastAPI application.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Project setup:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;p&gt;python3 -m venv venv
  source venv/bin/activate
  pip install fastapi uvicorn sqlalchemy psycopg2-binary alembic pydantic-settings&lt;/p&gt;
&lt;p&gt;Define models with SQLAlchemy, mirroring your SQL schema, and Pydantic schemas to validate incoming and outgoing data:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;p&gt;models.py
  from sqlalchemy import Column, Integer, String, Boolean, ForeignKey
  from database import Base
  class Task(Base):
      &lt;strong&gt;tablename&lt;/strong&gt; = "tasks"
      id = Column(Integer, primary_key=True, index=True)
      user_id = Column(Integer, ForeignKey("users.id"))
      title = Column(String, nullable=False)
      is_complete = Column(Boolean, default=False)&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;p&gt;schemas.py
  from pydantic import BaseModel
  class TaskCreate(BaseModel):
      title: str
  class TaskOut(TaskCreate):
      id: int
      is_complete: bool
      class Config:
          from_attributes = True&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build routes&lt;/strong&gt; that expose clean, RESTful endpoints:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;p&gt;main.py
  from fastapi import FastAPI, Depends
  from sqlalchemy.orm import Session
  import models, schemas
  from database import SessionLocal, engine
  models.Base.metadata.create_all(bind=engine)
  app = FastAPI()
  def get_db():
      db = SessionLocal()
      try:
          yield db
     finally:
          db.close()
  @app.post("/tasks/", response_model=schemas.TaskOut)
  def create_task(task: schemas.TaskCreate, db: Session = Depends(get_db)):
      db_task = models.Task(title=task.title)
      db.add(db_task)
      db.commit()
      db.refresh(db_task)
      return db_task
  @app.get("/tasks/", response_model=list[schemas.TaskOut])
  def list_tasks(db: Session = Depends(get_db)):
      return db.query(models.Task).all()&lt;/p&gt;
&lt;p&gt;Run the server locally:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;p&gt;uvicorn main:app --reload&lt;/p&gt;
&lt;p&gt;FastAPI automatically generates interactive documentation at /docs, which is invaluable for testing endpoints before the frontend even exists. This is also the point to add &lt;strong&gt;CORS middleware&lt;/strong&gt; so your React app (running on a different port) can talk to the API:&lt;/p&gt;
&lt;p&gt;python&lt;/p&gt;
&lt;p&gt;from fastapi.middleware.cors import CORSMiddleware
  app.add_middleware(
      CORSMiddleware,
      allow_origins=["http://localhost:5173"],
      allow_methods=["&lt;em&gt;"],
      allow_headers=["&lt;/em&gt;"],
  )&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 4: Building the Frontend with React&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;With a working API, scaffold the frontend:&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;p&gt;npm create vite@latest frontend -- --template react
  cd frontend
  npm install axios
  npm run dev&lt;/p&gt;
&lt;p&gt;Structure components around the API resources you’ve built. A simple task list might look like this:&lt;/p&gt;
&lt;p&gt;jsx&lt;/p&gt;
&lt;p&gt;// TaskList.jsx
  import { useEffect, useState } from "react";
  import axios from "axios";
  const API_URL = "http://localhost:8000";
  export default function TaskList() {
    const [tasks, setTasks] = useState([]);
    const [title, setTitle] = useState("");
    useEffect(() =&amp;gt; {
      axios.get(&lt;code&gt;${API_URL}/tasks/&lt;/code&gt;).then((res) =&amp;gt; setTasks(res.data));
    }, []);
    const addTask = async () =&amp;gt; {
      const res = await axios.post(&lt;code&gt;${API_URL}/tasks/&lt;/code&gt;, { title });
      setTasks([...tasks, res.data]);
      setTitle("");
    };
    return (
      &lt;div&gt;
        &lt;input value={title} onChange={(e) =&gt; setTitle(e.target.value)} /&amp;gt;
        &lt;button onClick={addTask}&gt;Add Task&lt;/button&gt;
        &lt;ul&gt;
          {tasks.map((t) =&amp;gt; (
            &lt;li key={t.id}&gt;{t.title}&lt;/li&gt;
          ))}
        &lt;/ul&gt;
      &lt;/div&gt;
    );
  }&lt;/p&gt;
&lt;p&gt;Good practices at this layer:&lt;/p&gt;
&lt;p&gt;Centralize API calls in a dedicated api.js or service layer instead of scattering axios calls across components.&lt;/p&gt;
&lt;p&gt;Use environment variables (.env files with Vite’s VITE_ prefix) to switch the API base URL between development and production.&lt;/p&gt;
&lt;p&gt;Handle loading and error states explicitly rather than assuming requests always succeed.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 5: Connecting the Pieces in a Local Dev Loop&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A productive workflow runs all three layers simultaneously:&lt;/p&gt;
&lt;p&gt;PostgreSQL running as a background service (sudo systemctl start postgresql).&lt;/p&gt;
&lt;p&gt;FastAPI running with --reload for instant backend updates.&lt;/p&gt;
&lt;p&gt;React running with Vite’s dev server, which hot-reloads on save.&lt;/p&gt;
&lt;p&gt;Many teams use a Makefile or a simple shell script to start everything at once, or move to &lt;strong&gt;Docker Compose&lt;/strong&gt; once the project stabilizes, defining separate containers for the database, API, and frontend so the entire stack can be brought up with one command:&lt;/p&gt;
&lt;p&gt;yaml&lt;/p&gt;
&lt;p&gt;version: "3.9"
  services:
    db:
      image: postgres:16
      environment:
        POSTGRES_DB: myapp_db
        POSTGRES_PASSWORD: postgres
      ports:
        - "5432:5432"
    backend:
      build: ./backend
      ports:
        - "8000:8000"
      depends_on:
        - db
    frontend:
      build: ./frontend
      ports:
        - "5173:5173"&lt;/p&gt;
&lt;p&gt;This containerized setup also closes the gap between development and production, since the same Ubuntu-based images can be deployed to a cloud VM or Kubernetes cluster later.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Step 6: Testing&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;A solid workflow includes tests at each layer:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Backend&lt;/strong&gt;: Use pytest with FastAPI’s TestClient to test endpoints against a test database, verifying status codes, response shapes, and edge cases like invalid input.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;: Test migrations apply cleanly in both directions (upgrade and downgrade) with Alembic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frontend&lt;/strong&gt;: Use tools like &lt;strong&gt;Vitest&lt;/strong&gt; and &lt;strong&gt;React Testing Library&lt;/strong&gt; to test components in isolation, and &lt;strong&gt;Cypress&lt;/strong&gt; or &lt;strong&gt;Playwright&lt;/strong&gt; for end-to-end tests that simulate real user flows across the full stack.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Step 7: Deployment&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;Once the application is stable:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Provision an Ubuntu server&lt;/strong&gt; (a cloud VM from a provider like DigitalOcean, AWS EC2, or Linode).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Set up PostgreSQL&lt;/strong&gt; on the server, or use a managed database service for easier backups and scaling.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Run FastAPI behind a process manager&lt;/strong&gt; like systemd or supervisor, fronted by Nginx as a reverse proxy, with &lt;strong&gt;Gunicorn + Uvicorn workers&lt;/strong&gt; handling concurrency:&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;p&gt;gunicorn -w 4 -k uvicorn.workers.UvicornWorker main:app&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Build the React app for production&lt;/strong&gt; (npm run build) and serve the static files via Nginx or a CDN.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automate deployment&lt;/strong&gt; with a CI/CD pipeline (GitHub Actions is a common choice) that runs tests, builds artifacts, and deploys on every merge to the main branch.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h1&gt;&lt;strong&gt;Step 8: Monitoring and Iteration&lt;/strong&gt;&lt;/h1&gt;
&lt;p&gt;After launch, the workflow doesn’t stop:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Use logging (structured JSON logs from FastAPI) and a tool like Sentry to catch backend and frontend errors in production.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Monitor database performance with EXPLAIN ANALYZE on slow queries and add indexes as usage patterns emerge.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Treat the development loop as continuous: new features move through the same path — schema change, API endpoint, frontend component, tests, deploy.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Conclusion&lt;/p&gt;
&lt;p&gt;This Ubuntu–FastAPI–SQL–React workflow works well because each layer has a clear responsibility and a clean interface to the next: Ubuntu provides a consistent runtime, SQL enforces data integrity, FastAPI exposes that data through a fast, self-documenting API, and React turns it into an interactive experience. The real productivity gain comes not from any single tool but from the discipline of moving through the same loop — schema, API, UI, test, deploy — every time the application grows.&lt;/p&gt;</content><category term="Article"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/></entry><entry><title>Optimizing FastAPI Performance for High-Traffic Applications</title><link href="https://athiraraghu-blr.github.io/fastpai-performance-high-traffic-application.html" rel="alternate"/><published>2026-06-19T00:00:00+05:30</published><updated>2026-06-19T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-19:/fastpai-performance-high-traffic-application.html</id><summary type="html">&lt;p&gt;FastAPI is fast by default, but scaling requires optimized async code, caching, database tuning, and efficient infrastructure. These practices help handle high traffic smoothly.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Embrace Async All the Way Down&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;FastAPI is built on Starlette and runs on an async event loop (via uvicorn or hypercorn). The single biggest mistake …&lt;/p&gt;</summary><content type="html">&lt;p&gt;FastAPI is fast by default, but scaling requires optimized async code, caching, database tuning, and efficient infrastructure. These practices help handle high traffic smoothly.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Embrace Async All the Way Down&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;FastAPI is built on Starlette and runs on an async event loop (via uvicorn or hypercorn). The single biggest mistake developers make is mixing blocking I/O into async route handlers.&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;❌&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Blocks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kills&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;concurrency&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;/users/{user_id}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;user_id&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;SELECT * FROM users WHERE id = ?&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nf"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;sync&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;user&lt;/span&gt;

&lt;span class="err"&gt;✅&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Non&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;blocking&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;—&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;waiting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;O&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;/users/{user_id}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;user_id&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;db&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;AsyncSession&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Depends&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;get_db&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scalar_one&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Use async-native libraries everywhere:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Database&lt;/strong&gt;: asyncpg, databases, SQLAlchemy 2.x with async sessions&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;HTTP clients&lt;/strong&gt;: httpx (async), aiohttp&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Redis&lt;/strong&gt;: aioredis or redis-py with async support&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;File I/O&lt;/strong&gt;: aiofiles&lt;/p&gt;
&lt;p&gt;If you must call a blocking function (e.g., a CPU-heavy computation or a legacy sync library), offload it to a thread pool using asyncio.run_in_executor or FastAPI’s built-in run_in_threadpool:&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi.concurrency&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;run_in_threadpool&lt;/span&gt;
&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/report&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;generate_report&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;run_in_threadpool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;generate_heavy_report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;em&gt;Use Multiple Workers and the Right Server&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;A single uvicorn process uses one CPU core. For a production system, you need to scale across cores.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option A: Gunicorn with Uvicorn workers&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;gunicorn app.main:app \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A rule of thumb for worker count is (2 × CPU cores) + 1, but profile your application — I/O-bound apps can often handle more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Option B: Uvicorn with multiple processes (uvicorn &amp;gt;= 0.20)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;bash&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;uvicorn app.main:app --workers 4 --host 0.0.0.0 --port 8000
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Option C: Hypercorn&lt;/strong&gt; for HTTP/2 support, which multiplexes multiple streams over a single TCP connection — especially beneficial for API clients making many parallel requests.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Connection Pooling for Databases&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;Every database query that opens and closes a connection pays a significant TCP + authentication overhead. A connection pool keeps connections alive and reuses them.&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy.ext.asyncio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;create_async_engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;AsyncSession&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;sqlalchemy.orm&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sessionmaker&lt;/span&gt;
&lt;span class="n"&gt;engine&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;create_async_engine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s2"&gt;&amp;quot;postgresql+asyncpg://user:pass@localhost/db&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;pool_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# Connections kept alive&lt;/span&gt;
    &lt;span class="n"&gt;max_overflow&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# Extra connections under peak load&lt;/span&gt;
    &lt;span class="n"&gt;pool_timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# Wait time before raising an error&lt;/span&gt;
    &lt;span class="n"&gt;pool_pre_ping&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;    &lt;span class="c1"&gt;# Verify connection before use&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;AsyncSessionLocal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sessionmaker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;class_&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AsyncSession&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expire_on_commit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tune pool_size based on your database server’s max_connections limit and the number of application workers. A common mistake is having workers × pool_size exceed the database’s connection limit.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Caching: The Single Biggest Throughput Multiplier&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;If the same data is requested repeatedly, compute it once and cache the result. This is often the most impactful optimization available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;In-Memory Caching with cachetools&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For data that fits in memory and changes infrequently:&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;cachetools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;TTLCache&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;cachetools.func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ttl_cache&lt;/span&gt;
&lt;span class="n"&gt;cache&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TTLCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# 1000 items, 5-minute TTL&lt;/span&gt;
&lt;span class="nd"&gt;@ttl_cache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;maxsize&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_country_list&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Redis for Distributed Caching&lt;/strong&gt; &lt;/p&gt;
&lt;p&gt;When you have multiple workers or machines, use Redis so all instances share the same cache:&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;redis.asyncio&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;redis&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;json&lt;/span&gt;
&lt;span class="n"&gt;redis_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;redis://localhost:6379&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decode_responses&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/products/&lt;/span&gt;&lt;span class="si"&gt;{product_id}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_product&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;cache_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;product:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;
    &lt;span class="n"&gt;cached&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;redis_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cached&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;fetch_product_from_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;redis_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;setex&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cache_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;HTTP-Level Caching&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;For public, read-heavy endpoints, add Cache-Control headers so CDNs and browsers cache the response upstream:&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;
&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/public/catalog&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;get_catalog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Cache-Control&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;public, max-age=3600&amp;quot;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;fetch_catalog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;em&gt;Optimize Serialization&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;Pydantic v2 (the default in FastAPI &amp;gt;= 0.100) is dramatically faster than v1 — if you haven’t upgraded, do so. Beyond that:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Use response_model wisely.&lt;/strong&gt; FastAPI validates and serializes the full response object. For large datasets, this validation overhead matters.&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;#Only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;serialize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;actually&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;need&lt;/span&gt;
&lt;span class="nv"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;/users&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;response_model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;list&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;UserSummary&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;Not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;UserFull&lt;/span&gt;
&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list_users&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use orjson for faster JSON encoding:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi.responses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ORJSONResponse&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;default_response_class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ORJSONResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;orjson is typically 2–3× faster than the standard json library and natively handles datetime, UUID, and numpy types.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Background Tasks for Non-Critical Work&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;Don’t make the user wait for things that don’t need to happen before sending a response — like sending emails, logging analytics events, or triggering downstream webhooks.&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;fastapi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BackgroundTasks&lt;/span&gt;
&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/orders&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;OrderCreate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
&lt;span class="n"&gt;BackgroundTasks&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;new_order&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;db_create_order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send_confirmation_email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;background_tasks&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_task&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;notify_warehouse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;new_order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;order_id&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;new_order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For heavier workloads, move to a dedicated task queue like Celery (with Redis or RabbitMQ as a broker) or ARQ (async-native, Redis-backed).&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Rate Limiting and Request Throttling&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;Under high traffic, a small number of clients can monopolize resources. Rate limiting protects your infrastructure and ensures fair access.&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;slowapi&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Limiter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_rate_limit_exceeded_handler&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;slowapi.util&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_remote_address&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;slowapi.errors&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RateLimitExceeded&lt;/span&gt;
&lt;span class="n"&gt;limiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Limiter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key_func&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;get_remote_address&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;limiter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;limiter&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_exception_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;RateLimitExceeded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_rate_limit_exceeded_handler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/search&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@limiter&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;30/minute&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;perform_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For more sophisticated rate limiting (per user, per tier, sliding windows), implement it at the API gateway layer (NGINX, Kong, AWS API Gateway) so it intercepts traffic before it reaches your application.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Efficient Dependency Injection&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;FastAPI’s Depends system is powerful but can become a bottleneck if you’re creating expensive objects (like database sessions or HTTP client connections) on every request. Use yield-based dependencies with proper lifecycle management:&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;contextlib&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asynccontextmanager&lt;/span&gt;
&lt;span class="nd"&gt;@asynccontextmanager&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;lifespan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Startup: create shared resources&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http_client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;httpx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AsyncClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;from_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;redis://localhost&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt;
    &lt;span class="c1"&gt;# Shutdown: clean up&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;http_client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;aclose&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;redis&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FastAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lifespan&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;lifespan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Avoid re-creating clients inside request handlers. A single httpx.AsyncClient shared across requests is far more efficient than creating a new one per request.&lt;/p&gt;
&lt;h1&gt;&lt;em&gt;Database Query Optimization&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;The application layer rarely is the true bottleneck — the database usually is. Profile your queries before optimizing application code.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Avoid N+1 queries&lt;/strong&gt; by using joinedload or selectinload:&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;❌&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;queries&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;
&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Triggers another query each time&lt;/span&gt;
&lt;span class="err"&gt;✅&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Single&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;eager&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;loading&lt;/span&gt;
&lt;span class="n"&gt;orders&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;joinedload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Order&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Use database indexes&lt;/strong&gt; on columns that appear in WHERE, ORDER BY, and JOIN clauses. A missing index on a high-traffic query is almost always the single most impactful fix available.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Paginate large result sets&lt;/strong&gt; rather than fetching everything:&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;&amp;quot;/events&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;list_events&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;page&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;await&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Event&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;scalars&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="ow"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;&lt;em&gt;Observability: Measure Before You Optimize&lt;/em&gt;&lt;/h1&gt;
&lt;p&gt;Premature optimization without measurement leads to effort in the wrong places. Instrument your application before tuning.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prometheus metrics&lt;/strong&gt; via prometheus-fastapi-instrumentator:&lt;/p&gt;
&lt;p&gt;python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;prometheus_fastapi_instrumentator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Instrumentator&lt;/span&gt;
&lt;span class="n"&gt;Instrumentator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instrument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;expose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This exposes request duration histograms, response codes, and throughput — exactly what you need to spot slow endpoints.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Structured logging&lt;/strong&gt; with structlog or Python’s logging module in JSON format makes it easy to correlate requests across services and detect patterns in errors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Distributed tracing&lt;/strong&gt; with OpenTelemetry lets you trace a request across FastAPI, database calls, Redis, and downstream services — invaluable for diagnosing latency in complex systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Putting It All Together&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There’s no single silver bullet for high-traffic FastAPI performance. The optimizations that matter most depend on your specific bottleneck — and the only way to know your bottleneck is to measure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;That said, here’s a general priority order for most applications:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Make all I/O non-blocking (async libraries, no sync calls in async handlers)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add connection pooling for databases and external services&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cache aggressively at the right layer (in-memory → Redis → CDN)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use multiple workers to exploit all CPU cores&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Switch to ORJSONResponse and Pydantic v2 for faster serialization&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Move non-critical work to background tasks or a task queue&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Add rate limiting and throttling at the gateway&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Profile and optimize database queries — indexes, eager loading, paginatio&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Instrument with metrics and tracing to validate improvements&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;FastAPI gives you an excellent starting point. These practices take you the rest of the way — to an application that handles serious traffic with room to grow.&lt;/p&gt;</content><category term="Article"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/></entry><entry><title>FastAPI vs Django vs Flask: Which Should You Choose?</title><link href="https://athiraraghu-blr.github.io/fastpai-djanho-flask.html" rel="alternate"/><published>2026-06-18T00:00:00+05:30</published><updated>2026-06-18T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-06-18:/fastpai-djanho-flask.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;FastAPI&lt;/strong&gt; vs &lt;strong&gt;Django&lt;/strong&gt; vs &lt;strong&gt;Flask&lt;/strong&gt;: Which Should You Choose?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Django&lt;/strong&gt; is full-featured, &lt;strong&gt;Flask&lt;/strong&gt; is lightweight, and &lt;strong&gt;FastAPI&lt;/strong&gt; is modern and fast. The best choice depends on your project needs.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Django&lt;/strong&gt;: The Batteries-Included Framework&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Django&lt;/strong&gt; has been around since 2005 and has earned its reputation as the framework for building full-featured …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;FastAPI&lt;/strong&gt; vs &lt;strong&gt;Django&lt;/strong&gt; vs &lt;strong&gt;Flask&lt;/strong&gt;: Which Should You Choose?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Django&lt;/strong&gt; is full-featured, &lt;strong&gt;Flask&lt;/strong&gt; is lightweight, and &lt;strong&gt;FastAPI&lt;/strong&gt; is modern and fast. The best choice depends on your project needs.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Django&lt;/strong&gt;: The Batteries-Included Framework&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Django&lt;/strong&gt; has been around since 2005 and has earned its reputation as the framework for building full-featured web applications quickly. It follows a “batteries included” philosophy, shipping with an ORM, an admin panel, authentication, form handling, templating, and a migration system already wired together.&lt;/p&gt;
&lt;p&gt;The biggest advantage of &lt;strong&gt;Django&lt;/strong&gt; is how much it does for you before you write a single line of business logic. Spin up a new project, run the migrations, and you already have a working admin interface for managing your data. This makes &lt;strong&gt;Django&lt;/strong&gt; especially strong for content-heavy sites, internal tools, and applications where the data model is central, like e-commerce platforms, CMSs, and SaaS products with traditional CRUD operations.&lt;/p&gt;
&lt;p&gt;The tradeoff is rigidity and weight. &lt;strong&gt;Django&lt;/strong&gt;’s conventions are opinionated, and bending the framework to a non-standard architecture (such as a pure API backend with no server-rendered pages) can feel like fighting the tool. &lt;strong&gt;Django&lt;/strong&gt; REST Framework helps a lot here and is genuinely excellent, but it’s an additional layer on top of an already substantial framework. &lt;strong&gt;Django&lt;/strong&gt; also defaults to a synchronous request-handling model, though async support has been improving with each release.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;Flask&lt;/strong&gt;: The Minimalist Toolkit&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Flask&lt;/strong&gt; takes the opposite approach. It gives you routing, request/response handling, and a templating engine, and basically nothing else. Everything beyond that, the ORM, authentication, validation, is something you choose and wire in yourself through extensions like &lt;strong&gt;Flask&lt;/strong&gt;-SQLAlchemy or &lt;strong&gt;Flask&lt;/strong&gt;-Login.&lt;/p&gt;
&lt;p&gt;This minimalism is &lt;strong&gt;Flask&lt;/strong&gt;’s defining strength. It’s easy to learn, easy to reason about, and gives you full control over your application’s structure. For small services, prototypes, internal scripts that need a web interface, or projects with unusual architectural requirements, &lt;strong&gt;Flask&lt;/strong&gt; gets out of your way. Many developers also use &lt;strong&gt;Flask&lt;/strong&gt; as a teaching tool precisely because there’s so little “magic” hidden behind the scenes.&lt;/p&gt;
&lt;p&gt;The cost of that flexibility is that you, or your team, have to make every architectural decision yourself: which ORM, which validation library, how to structure a larger codebase. On bigger projects this can lead to inconsistency between contributors, since &lt;strong&gt;Flask&lt;/strong&gt; doesn’t enforce a particular project layout the way &lt;strong&gt;Django&lt;/strong&gt; does. &lt;strong&gt;Flask&lt;/strong&gt; also remained synchronous-only for a long time; native async support exists in &lt;strong&gt;Flask&lt;/strong&gt; 2.0+ but feels added-on rather than foundational.&lt;/p&gt;
&lt;h1&gt;&lt;strong&gt;FastAPI&lt;/strong&gt;: Modern, Async-First, and Type-Driven&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;FastAPI&lt;/strong&gt; is the youngest of the three, released in 2018, and it was built around two ideas that didn’t exist when &lt;strong&gt;Django&lt;/strong&gt; and &lt;strong&gt;Flask&lt;/strong&gt; were designed: Python’s type hints and native async/await syntax. It uses type annotations to automatically validate request data, serialize responses, and generate interactive API documentation (via Swagger UI and ReDoc) with essentially no extra configuration.&lt;/p&gt;
&lt;p&gt;This makes &lt;strong&gt;FastAPI&lt;/strong&gt; extremely well-suited to building APIs, particularly ones that need to be fast, well-documented, and type-safe. Its async-first design, built on Starlette and Uvicorn, allows it to handle high levels of concurrency efficiently, which matters for I/O-heavy workloads like calling external APIs, querying databases, or serving machine learning models. It has become a popular choice in the ML/AI space for exactly this reason: wrapping a model in a fast, well-typed API is a common need, and &lt;strong&gt;FastAPI&lt;/strong&gt; does it with very little boilerplate.&lt;/p&gt;
&lt;p&gt;The limitation is scope. &lt;strong&gt;FastAPI&lt;/strong&gt; is focused on APIs; it doesn’t include an admin panel, a built-in ORM, or server-side templating in the way &lt;strong&gt;Django&lt;/strong&gt; does (though templating can be added). For a full web application with HTML pages, forms, and user-facing UI, you’ll typically pair &lt;strong&gt;FastAPI&lt;/strong&gt; with a separate frontend or add the missing pieces yourself, similar to &lt;strong&gt;Flask&lt;/strong&gt;. It’s also a younger ecosystem, so while its core is mature and battle-tested in production, you’ll find fewer third-party packages than &lt;strong&gt;Django&lt;/strong&gt; has accumulated over two decades.&lt;/p&gt;
&lt;h1&gt;Comparing the Three Directly&lt;/h1&gt;
&lt;p&gt;On performance, &lt;strong&gt;FastAPI&lt;/strong&gt; generally outperforms &lt;strong&gt;Django&lt;/strong&gt; and &lt;strong&gt;Flask&lt;/strong&gt; in raw throughput, mainly because of its async foundation and the efficiency of Starlette/Uvicorn under concurrent load. &lt;strong&gt;Flask&lt;/strong&gt; and &lt;strong&gt;Django&lt;/strong&gt; can both adopt async patterns now, but neither was designed around async from day one, so the gains are less consistent.&lt;/p&gt;
&lt;p&gt;On learning curve, &lt;strong&gt;Flask&lt;/strong&gt; is the easiest to pick up if you already know Python, since there’s so little framework-specific knowledge required upfront. &lt;strong&gt;FastAPI&lt;/strong&gt; has a moderate curve: you’ll want to be comfortable with type hints and ideally async concepts to use it well. &lt;strong&gt;Django&lt;/strong&gt; has the steepest initial learning curve because there’s more to learn (the ORM, the admin, the settings system, the project structure), but that investment pays off quickly for the right kind of project.&lt;/p&gt;
&lt;p&gt;On built-in features, &lt;strong&gt;Django&lt;/strong&gt; wins decisively, an ORM, admin, auth, and forms ship by default. &lt;strong&gt;FastAPI&lt;/strong&gt; and &lt;strong&gt;Flask&lt;/strong&gt; both leave most of that to you, though &lt;strong&gt;FastAPI&lt;/strong&gt;’s automatic validation and documentation generation save real time on the API side specifically.&lt;/p&gt;
&lt;p&gt;On ideal use case, &lt;strong&gt;Django&lt;/strong&gt; suits full-stack applications with complex data models and a need for an admin interface, things like marketplaces, content platforms, and internal business tools. &lt;strong&gt;Flask&lt;/strong&gt; suits small services, prototypes, and projects where you want maximum control over architecture. &lt;strong&gt;FastAPI&lt;/strong&gt; suits APIs and microservices, especially ones with performance requirements, heavy I/O, or integration with data science and ML pipelines.&lt;/p&gt;
&lt;h1&gt;A Practical Way to Decide&lt;/h1&gt;
&lt;p&gt;If you’re building something with a database-backed admin interface, user accounts, and multiple interconnected models, where most of the “API” work has already been solved by countless other &lt;strong&gt;Django&lt;/strong&gt; apps, start with &lt;strong&gt;Django&lt;/strong&gt;. You’ll move faster by leaning on what it already provides.&lt;/p&gt;
&lt;p&gt;If you’re building a backend API, particularly one that needs to be fast, well-typed, and self-documenting, or one that’s serving a machine learning model or doing a lot of concurrent I/O, &lt;strong&gt;FastAPI&lt;/strong&gt; is the more natural fit and will save you time on validation and docs you’d otherwise write by hand.&lt;/p&gt;
&lt;p&gt;If you need something small, want full control over every architectural decision, or are building a prototype where you don’t yet know what the application will become, &lt;strong&gt;Flask&lt;/strong&gt;’s minimalism is an asset rather than a limitation. It’s also a reasonable choice if your team has specific library preferences that don’t mesh well with &lt;strong&gt;Django&lt;/strong&gt;’s conventions.&lt;/p&gt;
&lt;p&gt;It’s also worth noting these aren’t always mutually exclusive choices within an organization. It’s common to see &lt;strong&gt;Django&lt;/strong&gt; power an admin-heavy backend while a separate &lt;strong&gt;FastAPI&lt;/strong&gt; service handles a specific high-throughput API endpoint, or a team start a project in &lt;strong&gt;Flask&lt;/strong&gt; and migrate pieces to &lt;strong&gt;FastAPI&lt;/strong&gt; as performance needs grow. The frameworks solve overlapping but distinct problems, and the right answer depends less on which one is “better” and more on which one matches what you’re actually building.&lt;/p&gt;</content><category term="Article"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/></entry><entry><title>Setting Up Dev Tools on Ubuntu - llama.cpp, Slack, Git and JupyterLab</title><link href="https://athiraraghu-blr.github.io/setting-up-dev-tools-ubuntu-llamacpp-slack-git-jupyterlab.html" rel="alternate"/><published>2026-04-16T00:00:00+05:30</published><updated>2026-04-16T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-04-16:/setting-up-dev-tools-ubuntu-llamacpp-slack-git-jupyterlab.html</id><summary type="html">&lt;p&gt;A practical walkthrough of setting up a local AI development environment on Ubuntu — covering llama.cpp installation via Homebrew, running local LLMs with LangChain, fixing common Slack conflicts, Git branch management, and JupyterLab. Hard-won lessons from real terminal errors.&lt;/p&gt;
&lt;h2&gt;Installing llama.cpp via Homebrew on Ubuntu&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Homebrew on Linux&lt;/strong&gt; — Homebrew …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A practical walkthrough of setting up a local AI development environment on Ubuntu — covering llama.cpp installation via Homebrew, running local LLMs with LangChain, fixing common Slack conflicts, Git branch management, and JupyterLab. Hard-won lessons from real terminal errors.&lt;/p&gt;
&lt;h2&gt;Installing llama.cpp via Homebrew on Ubuntu&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Homebrew on Linux&lt;/strong&gt; — Homebrew is primarily a macOS package manager but works on Linux too. Install it with the official script and add it to your PATH via &lt;code&gt;~/.zshrc&lt;/code&gt; using &lt;code&gt;eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;brew install llama.cpp&lt;/strong&gt; — Installs llama.cpp and its dependencies including ggml (the tensor/ML backend) and openssl@3. The binaries land in &lt;code&gt;/home/linuxbrew/.linuxbrew/bin/&lt;/code&gt; and won't be accessible until Homebrew is added to PATH.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PATH fix is mandatory&lt;/strong&gt; — After install, running &lt;code&gt;llama-cli&lt;/code&gt; gives &lt;code&gt;command not found&lt;/code&gt; because &lt;code&gt;/home/linuxbrew/.linuxbrew/bin/&lt;/code&gt; is not in PATH by default. Add &lt;code&gt;eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"&lt;/code&gt; to &lt;code&gt;~/.zshrc&lt;/code&gt; and source it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Available binaries&lt;/strong&gt; — llama.cpp ships with 35+ tools including &lt;code&gt;llama-cli&lt;/code&gt; (inference), &lt;code&gt;llama-server&lt;/code&gt; (OpenAI-compatible REST API), &lt;code&gt;llama-bench&lt;/code&gt; (benchmarking), &lt;code&gt;llama-quantize&lt;/code&gt; (model quantization), &lt;code&gt;llama-tts&lt;/code&gt; (text-to-speech), and &lt;code&gt;llama-diffusion-cli&lt;/code&gt; (diffusion models).&lt;/p&gt;
&lt;h2&gt;Running Local LLMs with llama-server and LangChain&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;llama-server&lt;/strong&gt; — Starts a local OpenAI-compatible REST API server on &lt;code&gt;localhost:8080&lt;/code&gt;. Point any OpenAI SDK or LangChain app at it by setting &lt;code&gt;BASE_URL=http://localhost:8080/v1&lt;/code&gt; in your &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;LangChain + ChatOpenAI&lt;/strong&gt; — LangChain's &lt;code&gt;ChatOpenAI&lt;/code&gt; class works with local llama-server by overriding &lt;code&gt;base_url&lt;/code&gt;. The &lt;code&gt;api_key&lt;/code&gt; is just a placeholder — llama.cpp doesn't validate it. Temperature range is &lt;code&gt;0.0&lt;/code&gt; to &lt;code&gt;2.0&lt;/code&gt;; setting it to &lt;code&gt;5&lt;/code&gt; causes gibberish or errors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;GGUF models are required&lt;/strong&gt; — llama-server needs a real &lt;code&gt;.gguf&lt;/code&gt; model file. Download models via &lt;code&gt;huggingface-cli download&lt;/code&gt;. Good starter models: Phi-3.5-mini-Q4 (~2.2GB for 4GB RAM), Mistral-7B-Q4 (~4.1GB for 16GB RAM).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Port conflict fix&lt;/strong&gt; — If llama-server fails with &lt;code&gt;couldn't bind HTTP server socket&lt;/code&gt;, port 8080 is already in use. Use &lt;code&gt;sudo lsof -i :8080&lt;/code&gt; to find the process and &lt;code&gt;sudo kill -9 &amp;lt;PID&amp;gt;&lt;/code&gt; to free it, or start the server on a different port with &lt;code&gt;--port 8081&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;lsof -i explained&lt;/strong&gt; — &lt;code&gt;lsof&lt;/code&gt; means "List Open Files." The &lt;code&gt;-i&lt;/code&gt; flag filters results to show only internet/network connections. &lt;code&gt;lsof -i :8080&lt;/code&gt; shows exactly which process is occupying a specific port.&lt;/p&gt;
&lt;h2&gt;The Slack Name Conflict on Ubuntu&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Two different programs named slack&lt;/strong&gt; — Ubuntu has a sysadmin configuration management tool called &lt;code&gt;slack&lt;/code&gt; at &lt;code&gt;/usr/sbin/slack&lt;/code&gt;. It tries to rsync config from a server called &lt;code&gt;slack-master&lt;/code&gt; and fails with a DNS error. This is NOT the Slack chat app.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;snap install is the cleanest route&lt;/strong&gt; — &lt;code&gt;sudo snap install slack&lt;/code&gt; installs Slack chat app version 4.49.81 to &lt;code&gt;/snap/bin/slack&lt;/code&gt;. Always launch via &lt;code&gt;snap run slack&lt;/code&gt; or add &lt;code&gt;/snap/bin&lt;/code&gt; before &lt;code&gt;/usr/sbin&lt;/code&gt; in PATH to avoid calling the wrong binary.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Outdated versions get blocked&lt;/strong&gt; — Slack versions older than a certain threshold show "This version of the app is no longer supported." The &lt;code&gt;.deb&lt;/code&gt; at version 4.38 or 4.40 will be blocked on login. Use snap for the latest version automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;deb conflict with sysadmin slack&lt;/strong&gt; — Installing &lt;code&gt;slack-desktop&lt;/code&gt; via &lt;code&gt;.deb&lt;/code&gt; fails with &lt;code&gt;trying to overwrite '/usr/share/lintian/overrides/slack'&lt;/code&gt; because the sysadmin &lt;code&gt;slack&lt;/code&gt; package owns that file. Fix with &lt;code&gt;sudo dpkg -i --force-overwrite&lt;/code&gt; followed by &lt;code&gt;sudo apt install -f&lt;/code&gt;.&lt;/p&gt;
&lt;h2&gt;Git Branch Management&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;git init before anything&lt;/strong&gt; — Running &lt;code&gt;git add&lt;/code&gt; or &lt;code&gt;git status&lt;/code&gt; outside a Git repo gives &lt;code&gt;fatal: not a git repository&lt;/code&gt;. Always run &lt;code&gt;git init&lt;/code&gt; first in the project root.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nested .git folders break git add&lt;/strong&gt; — If a subfolder has its own &lt;code&gt;.git&lt;/code&gt; directory, Git treats it as a submodule and refuses to add it: &lt;code&gt;error: 'folder/' does not have a commit checked out&lt;/code&gt;. Fix by removing the nested &lt;code&gt;.git&lt;/code&gt; with &lt;code&gt;rm -rf subfolder/.git&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;master vs main mismatch&lt;/strong&gt; — Git still defaults to &lt;code&gt;master&lt;/code&gt; as the initial branch name. GitHub defaults to &lt;code&gt;main&lt;/code&gt;. Push fails with &lt;code&gt;src refspec main does not match any&lt;/code&gt; if you push to the wrong branch name. Fix: &lt;code&gt;git branch -m master main&lt;/code&gt; then &lt;code&gt;git push -u origin main&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;--set-upstream explained&lt;/strong&gt; — When you create a new local branch, Git doesn't know where to push it. &lt;code&gt;git push --set-upstream origin branch-name&lt;/code&gt; (or &lt;code&gt;-u&lt;/code&gt;) creates the branch on GitHub and links the local branch to track it. After that, plain &lt;code&gt;git push&lt;/code&gt; works with no extra flags.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;--set-upstream vs --set-remote&lt;/strong&gt; — These are different. &lt;code&gt;--set-remote&lt;/code&gt; changes which server (GitHub vs GitLab) a branch points to. &lt;code&gt;--set-upstream&lt;/code&gt; links a local branch to a specific branch on a remote server. Remote = the post office. Upstream = the specific PO box.&lt;/p&gt;
&lt;h2&gt;JupyterLab and Conda&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;jupyter lab not python lab&lt;/strong&gt; — The correct command to launch JupyterLab is &lt;code&gt;jupyter lab&lt;/code&gt;, not &lt;code&gt;python lab&lt;/code&gt; or &lt;code&gt;pythonlab&lt;/code&gt;. It opens a browser interface at &lt;code&gt;http://localhost:8888&lt;/code&gt; automatically.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;conda activate first&lt;/strong&gt; — Always run &lt;code&gt;conda activate &amp;lt;env-name&amp;gt;&lt;/code&gt; before launching JupyterLab to ensure the correct Python environment and installed packages are used inside notebooks.&lt;/p&gt;
&lt;h2&gt;Ubuntu Dock and Font Customization&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Move dock to horizontal&lt;/strong&gt; — Go to Settings → Appearance → Dock → Position on screen → Bottom. Or via terminal: &lt;code&gt;gsettings set org.gnome.shell.extensions.dash-to-dock dock-position BOTTOM&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Increase font size&lt;/strong&gt; — Settings → Accessibility → Large Text toggle, or install &lt;code&gt;gnome-tweaks&lt;/code&gt; (&lt;code&gt;sudo apt install gnome-tweaks&lt;/code&gt;) and adjust Fonts → Scaling Factor. Terminal shortcut: &lt;code&gt;gsettings set org.gnome.desktop.interface text-scaling-factor 1.5&lt;/code&gt;. Valid range is 1.0 (default) to 2.0.&lt;/p&gt;</content><category term="Linux"/><category term="Ubuntu"/><category term="llama.cpp"/><category term="Slack"/><category term="Git"/><category term="JupyterLab"/><category term="LangChain"/><category term="Linux"/><category term="DevTools"/></entry><entry><title>AI Agent Directory - Few Shots LLM Models</title><link href="https://athiraraghu-blr.github.io/ai-agent-directory-few-shots-llm-models.html" rel="alternate"/><published>2026-04-10T00:00:00+05:30</published><updated>2026-04-10T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-04-10:/ai-agent-directory-few-shots-llm-models.html</id><summary type="html">&lt;p&gt;The AI agent ecosystem is growing fast. Here's a quick directory of notable AI startups and a couple of few-shot LLM models worth knowing about. Two lines each — just enough to know what they do and why they matter.&lt;/p&gt;
&lt;h2&gt;AI Agent Directory (Test)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Can of Soup&lt;/strong&gt; — An AI-powered app that …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The AI agent ecosystem is growing fast. Here's a quick directory of notable AI startups and a couple of few-shot LLM models worth knowing about. Two lines each — just enough to know what they do and why they matter.&lt;/p&gt;
&lt;h2&gt;AI Agent Directory (Test)&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Can of Soup&lt;/strong&gt; — An AI-powered app that lets you create fictional photos of you and your friends in imaginary scenarios. Built during Y Combinator, it uses generative AI to place people into any meme, outfit, or movie scene.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deepgram&lt;/strong&gt; — A foundational voice AI platform offering speech-to-text, text-to-speech, and voice agent APIs. Their Nova models deliver high accuracy and low latency, supporting 30+ languages for real-time transcription.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Diffuse Bio&lt;/strong&gt; — Building generative AI for protein design, using diffusion models to engineer new proteins with control and accuracy. Their foundation model DSG-1 can generate 3D protein structures and design binders from user prompts.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Draftaid&lt;/strong&gt; — An AI-powered CAD tool that converts 3D models into precise 2D manufacturing drawings automatically. It reduces manual drafting time by up to 90%, acting like a copilot for mechanical engineers.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Edgetrace&lt;/strong&gt; — A YC-backed AI video analytics platform that lets users search camera networks using natural language. Primarily used by law enforcement and transportation for real-time threat detection and suspect identification.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;EzDubz&lt;/strong&gt; — A real-time AI dubbing tool that translates videos, livestreams, and phone calls while preserving the original speaker's voice. Their proprietary models clone voices on the fly and even replicate emotions across 20+ languages.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Exa&lt;/strong&gt; — An AI-powered search engine and API built for developers and AI agents. Unlike traditional keyword search, Exa uses neural embeddings for semantic understanding, powering tools like Cursor and Lovable.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Guide Labs&lt;/strong&gt; — Building interpretable AI foundation models that can explain their reasoning and are easy to audit. Their open-source Steerling-8B is an 8-billion-parameter LLM designed for transparency and debuggability.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Infinity AI&lt;/strong&gt; — Now known as Lemon Slice, they build a video foundation model for human motion and emotion. Their tech generates expressive, talking characters across styles from photorealistic to cartoon.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;K-Scale&lt;/strong&gt; — Building open-source humanoid robots for developers, with models starting at $999. Their integrated software, hardware, and ML stack lets developers focus on building applications for embodied AI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sevn&lt;/strong&gt; — A generative design startup using AI to automate and optimize the creative design process. Users define parameters and constraints, and Sevn generates a range of design options to explore.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Linux Inc&lt;/strong&gt; — An AI startup focused on bringing intelligent tooling to the Linux ecosystem. They aim to simplify Linux administration and development workflows through AI-powered automation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Metalware&lt;/strong&gt; — A copilot for firmware engineers that automates low-level programming for embedded systems. Their binary analysis tool fuzzes ARM-based software to detect defects earlier in the development lifecycle.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Naiver AI&lt;/strong&gt; — Navier AI provides a web-based platform for running CFD (computational fluid dynamics) simulations at scale. Their AI agents handle geometry cleanup, meshing, solver configuration, and cloud resource management autonomously.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Osium AI&lt;/strong&gt; — An AI-powered platform that accelerates materials and chemicals R&amp;amp;D for industry leaders. Their software helps engineers design new materials faster, spanning alloys, polymers, textiles, and bio-based materials.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phind&lt;/strong&gt; — An AI search engine purpose-built for developers that generates direct, code-inclusive answers to technical questions. It combines real-time web search with specialized models trained on programming languages and frameworks.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Piramidal&lt;/strong&gt; — Building a foundation model for the brain, trained on a massive corpus of EEG brainwave data. Their AI interprets neural signals for neurological diagnostics, already being deployed in ICU settings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Playground&lt;/strong&gt; — A browser-based AI image generation and design platform used by over 9 million users. It combines text-to-image generation with a full graphic design suite for logos, social media posts, and more.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PlayHT&lt;/strong&gt; — An AI voice generation platform that offered ultra-realistic text-to-speech with 900+ voices in 142 languages. Known for voice cloning and custom voice creation through deep learning algorithms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sonauto&lt;/strong&gt; — An AI music editor that turns prompts, lyrics, or melodies into full songs in any style. It supports thousands of styles with full-length songs up to 4.5 minutes, complete with vocals and instrumentation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tavus&lt;/strong&gt; — An AI video personalization platform that creates hyper-personalized videos at scale from a single recording. It uses deep learning for voice synthesis and face cloning to generate thousands of unique video variations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;YonduAI&lt;/strong&gt; — Building the robotic workforce of the future, starting with logistics automation in warehouses. They deploy humanoid robots with remote teleoperation that gradually transitions to full AI-driven automation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Yoneda Labs&lt;/strong&gt; — Building a foundation model for chemical reactions to help chemists optimize drug discovery. Their AI defines parameters like temperature, concentration, and catalyst to make synthesis faster and cheaper.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;SyncLabs&lt;/strong&gt; — An AI lip-sync video generator that creates perfectly synchronized mouth movements from any audio track. Their zero-shot model handles any face in any video context without prior training on specific individuals.&lt;/p&gt;
&lt;h2&gt;Few-Shot LLM Models&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Llama 3.1&lt;/strong&gt; — Meta's open-source large language model available in 8B, 70B, and 405B parameter sizes. It supports 128K context length and multilingual capabilities, making it one of the most versatile open-weight models for fine-tuning and deployment.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Mixtral&lt;/strong&gt; — Mistral AI's open-source mixture-of-experts (MoE) model that activates only a subset of parameters per token for efficient inference. It delivers performance comparable to much larger dense models while being significantly faster and more cost-effective to run.&lt;/p&gt;</content><category term="GenAI"/><category term="GenAI"/><category term="AI-agents"/><category term="LLM"/><category term="startups"/><category term="directory"/></entry><entry><title>My ChatOpenAI Blogs</title><link href="https://athiraraghu-blr.github.io/my-ChatOpenAI-blogs.html" rel="alternate"/><published>2026-01-18T00:00:00+05:30</published><updated>2026-01-18T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-01-18:/my-ChatOpenAI-blogs.html</id><summary type="html">&lt;h1&gt;ChatOpenAI: the conversational backbone of LangChain&lt;/h1&gt;
&lt;p&gt;A deep dive into the class that bridges your Python application with OpenAI's chat models — what it is, how it works, and when to use it.&lt;/p&gt;
&lt;p&gt;If LangChain is the framework for building AI-powered applications, then ChatOpenAI is its most-used engine — a clean, powerful …&lt;/p&gt;</summary><content type="html">&lt;h1&gt;ChatOpenAI: the conversational backbone of LangChain&lt;/h1&gt;
&lt;p&gt;A deep dive into the class that bridges your Python application with OpenAI's chat models — what it is, how it works, and when to use it.&lt;/p&gt;
&lt;p&gt;If LangChain is the framework for building AI-powered applications, then ChatOpenAI is its most-used engine — a clean, powerful wrapper that lets you talk to OpenAI's chat models in just a few lines of code.&lt;/p&gt;
&lt;p&gt;What is ChatOpenAI?
ChatOpenAI is a class in the LangChain library that wraps OpenAI's chat completion API (the same one powering GPT-4, GPT-3.5-turbo, etc.). Instead of manually writing HTTP requests to OpenAI, you create a ChatOpenAI object and call it like a function.&lt;/p&gt;
&lt;p&gt;Think of it as a pre-built phone — you don't wire up the network yourself, you just pick up and talk.&lt;/p&gt;
&lt;p&gt;from langchain_openai import ChatOpenAI # Create the model llm = ChatOpenAI(model="gpt-4o", temperature=0.7) # Invoke it response = llm.invoke("Explain recursion in one sentence.") print(response.content)
Key parameters
When creating a ChatOpenAI instance, you can configure it with several important parameters:&lt;/p&gt;
&lt;p&gt;Parameter   Type    What it does
model   str Which OpenAI model to use (e.g. "gpt-4o", "gpt-3.5-turbo")
temperature float 0–2   Controls randomness. 0 = focused, 1+ = creative
max_tokens  int Maximum length of the response
api_key str Your OpenAI API key (or set via env variable)
streaming   bool    Stream tokens back in real-time as they generate
Using it with messages
Chat models expect a conversation history — not just a single string. LangChain provides message types to structure this naturally:&lt;/p&gt;
&lt;p&gt;from langchain_openai import ChatOpenAI from langchain_core.messages import SystemMessage, HumanMessage llm = ChatOpenAI(model="gpt-4o") messages = [ SystemMessage(content="You are a helpful Python tutor."), HumanMessage(content="What is a decorator?"), ] response = llm.invoke(messages) print(response.content)
SystemMessage sets the AI's persona or rules. HumanMessage is what the user says. AIMessage is what the model replied previously — useful when passing conversation history.
Chaining with PromptTemplate
The real power unlocks when you chain ChatOpenAI with a PromptTemplate using LangChain Expression Language (LCEL):&lt;/p&gt;
&lt;p&gt;from langchain_openai import ChatOpenAI from langchain_core.prompts import ChatPromptTemplate prompt = ChatPromptTemplate.from_template( "Explain {topic} to a 10-year-old." ) llm = ChatOpenAI(model="gpt-4o") # Build a chain: prompt → model chain = prompt | llm result = chain.invoke({"topic": "recursion"}) print(result.content)
Streaming responses
For real-time output (like a typewriter effect), enable streaming:&lt;/p&gt;
&lt;p&gt;llm = ChatOpenAI(model="gpt-4o", streaming=True) for chunk in llm.stream("Write a haiku about Python."): print(chunk.content, end="", flush=True)
ChatOpenAI is the starting point for almost every LangChain application — once you understand it, chains, agents, and RAG pipelines all follow naturally.&lt;/p&gt;
&lt;p&gt;LangChain docs · langchain.com  |  OpenAI API reference · platform.openai.com&lt;/p&gt;</content><category term="Announcement"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/><category term="ChatOpenAI"/></entry><entry><title>My GenAI Blogs</title><link href="https://athiraraghu-blr.github.io/my-genai-blogs.html" rel="alternate"/><published>2026-01-10T00:00:00+05:30</published><updated>2026-01-10T00:00:00+05:30</updated><author><name>Athira</name></author><id>tag:athiraraghu-blr.github.io,2026-01-10:/my-genai-blogs.html</id><summary type="html">&lt;h2&gt;Why GenAI?&lt;/h2&gt;
&lt;p&gt;Generative AI has completely changed how I think about software, creativity, and problem-solving. Over the past year, I've gone deep into the world of large language models, prompt engineering, retrieval-augmented generation, fine-tuning, and AI agents. The pace of change is incredible, and I wanted a place to document …&lt;/p&gt;</summary><content type="html">&lt;h2&gt;Why GenAI?&lt;/h2&gt;
&lt;p&gt;Generative AI has completely changed how I think about software, creativity, and problem-solving. Over the past year, I've gone deep into the world of large language models, prompt engineering, retrieval-augmented generation, fine-tuning, and AI agents. The pace of change is incredible, and I wanted a place to document what I'm learning as I go.&lt;/p&gt;
&lt;p&gt;This blog is that place. I'll be writing about my hands-on experiences with GenAI, the tools I'm experimenting with, things that worked, things that didn't, and the lessons I've picked up along the way.&lt;/p&gt;
&lt;h2&gt;What I've Been Exploring&lt;/h2&gt;
&lt;p&gt;My GenAI journey started with using ChatGPT and Claude for day-to-day coding tasks. That quickly evolved into deeper exploration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Prompt engineering&lt;/strong&gt; — learning how to get consistent, high-quality outputs from LLMs by structuring prompts effectively.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAG (Retrieval-Augmented Generation)&lt;/strong&gt; — building pipelines that ground LLM responses in real data using vector databases and embeddings.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fine-tuning&lt;/strong&gt; — adapting pre-trained models for specific tasks and domains.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AI agents&lt;/strong&gt; — creating autonomous workflows where LLMs can use tools, reason through multi-step problems, and take actions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Local models&lt;/strong&gt; — running open-source models like LLaMA and Mistral locally to understand how they work under the hood.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I'm not just reading about these topics. I'm building with them, breaking things, and learning from the results.&lt;/p&gt;
&lt;h2&gt;What to Expect&lt;/h2&gt;
&lt;p&gt;I plan to post at least one article a week covering topics like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Practical tutorials on building GenAI applications&lt;/li&gt;
&lt;li&gt;Comparisons of different models and frameworks&lt;/li&gt;
&lt;li&gt;Deep dives into concepts like embeddings, tokenization, and attention mechanisms&lt;/li&gt;
&lt;li&gt;Real-world use cases and project walkthroughs&lt;/li&gt;
&lt;li&gt;Opinions on where GenAI is heading and what matters for developers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some posts will be short and focused, others will be longer walkthroughs. The goal is to share useful, honest content from a developer's perspective.&lt;/p&gt;
&lt;h2&gt;Let's Go&lt;/h2&gt;
&lt;p&gt;I'm excited to start writing and sharing. GenAI is moving fast, and the best way to keep up is to build, experiment, and document. That's exactly what this blog is for.&lt;/p&gt;</content><category term="Announcement"/><category term="GenAI"/><category term="LLM"/><category term="machine-learning"/><category term="deep-learning"/><category term="announcement"/></entry></feed>