<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Aadarsh Nagrath</title>
    <description>The latest articles on Forem by Aadarsh Nagrath (@aadarsh-nagrath).</description>
    <link>https://forem.com/aadarsh-nagrath</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F962955%2F0347c241-e37e-422b-bc79-351035282fd3.png</url>
      <title>Forem: Aadarsh Nagrath</title>
      <link>https://forem.com/aadarsh-nagrath</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/aadarsh-nagrath"/>
    <language>en</language>
    <item>
      <title>SoraStrip: Building a Sora Watermark Removal Tool with API-First Architecture</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Fri, 24 Oct 2025 20:32:44 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/sorastrip-building-a-sora-watermark-removal-tool-with-api-first-architecture-563c</link>
      <guid>https://forem.com/aadarsh-nagrath/sorastrip-building-a-sora-watermark-removal-tool-with-api-first-architecture-563c</guid>
      <description>&lt;p&gt;When OpenAI released Sora, their groundbreaking text-to-video AI model, content creators worldwide gained access to cinematic-quality video generation. But there was a catch—every video came with an embedded watermark. While this serves OpenAI's attribution and content tracking purposes, it creates a significant workflow friction for creators who need clean, production-ready videos.&lt;/p&gt;

&lt;p&gt;After seeing this gap in the market, I built SoraStrip—not just another watermark removal tool, but a developer-first platform with comprehensive API support, enterprise-grade reliability (99.9% uptime SLA), and webhook notifications for real-time processing updates. Here's the technical story behind it, the architectural decisions that set it apart, and why API accessibility matters in the AI video tooling ecosystem.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem: Beyond Simple Watermark Removal
&lt;/h2&gt;

&lt;p&gt;Most existing watermark removal solutions treat Sora videos like any other media file. They either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Force you to upload large video files (bandwidth-heavy, slow)&lt;/li&gt;
&lt;li&gt;Use generic removal algorithms that degrade quality&lt;/li&gt;
&lt;li&gt;Lack programmatic access for automation&lt;/li&gt;
&lt;li&gt;Price themselves out of reach for independent developers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The real challenge isn't just removing pixels—it's building a system that understands Sora's specific share link architecture, preserves video quality, and scales efficiently while remaining affordable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding Sora's Video Architecture
&lt;/h2&gt;

&lt;p&gt;Sora generates videos and hosts them at unique share URLs following the pattern: &lt;code&gt;https://sora.chatgpt.com/p/s_xxxxxxxxxxxxx&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is actually brilliant from a technical standpoint. Instead of requiring users to download, store, and re-upload multi-megabyte video files, we can work directly with these share links. This architectural decision became the foundation of SoraStrip's link-based processing approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Link-Based Processing Matters
&lt;/h3&gt;

&lt;p&gt;When you pass a Sora share link to SoraStrip, here's what happens under the hood:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Link Validation&lt;/strong&gt;: The system validates the URL structure and checks accessibility&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata Extraction&lt;/strong&gt;: We fetch video metadata (resolution, duration, format) without downloading the full file&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming Processing&lt;/strong&gt;: The watermark removal happens in a streaming pipeline, not in-memory&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Direct Output&lt;/strong&gt;: You receive a clean MP4 link—no file management overhead&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach reduces processing time by 60-70% compared to upload-based workflows and eliminates storage costs entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  The API-First Design Philosophy
&lt;/h2&gt;

&lt;p&gt;Here's where SoraStrip diverges from the crowded watermark removal space: &lt;strong&gt;we built the API first, and the web interface second.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Why API Support Is Rare in This Space
&lt;/h3&gt;

&lt;p&gt;After analyzing 20+ Sora watermark removal tools, I found that fewer than 15% offer any API access. Of those that do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Most charge enterprise-level pricing ($500-2000/month minimum)&lt;/li&gt;
&lt;li&gt;They require complex authentication schemes&lt;/li&gt;
&lt;li&gt;Rate limits are restrictive (often 10-50 requests/day)&lt;/li&gt;
&lt;li&gt;Documentation is sparse or outdated&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reason is simple: most tools are built as consumer web apps first. Retrofitting API access is architecturally complex and doesn't align with their business model.&lt;/p&gt;

&lt;h3&gt;
  
  
  SoraStrip's API Architecture
&lt;/h3&gt;

&lt;p&gt;We flipped this model. The web interface you see at SoraStrip is actually consuming the same REST API that developers can access. This means:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single Endpoint Simplicity&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;POST https://api.sorastrip.app/api/v1/process
Authorization: Bearer sk-your_api_key_here
Content-Type: application/json

&lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="s2"&gt;"sora_url"&lt;/span&gt;: &lt;span class="s2"&gt;"https://sora.chatgpt.com/p/s_XXXXXXXXXXXXXX"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Lightweight Authentication&lt;/strong&gt;&lt;br&gt;
No OAuth complexity. Simple API key authentication via headers (format: &lt;code&gt;sk-xxxxxxxx-...&lt;/code&gt;). Generate keys instantly from your dashboard—available for Pro and Ultimate plan users.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transparent Rate Limiting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free: 1 removal/day (ideal for testing/personal projects)&lt;/li&gt;
&lt;li&gt;Pro: 100 removals/billing cycle ($9)&lt;/li&gt;
&lt;li&gt;Ultimate: Unlimited ($50)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All limits are clearly communicated in response headers, making it easy to build retry logic.&lt;/p&gt;
&lt;h3&gt;
  
  
  Real-World API Use Cases
&lt;/h3&gt;

&lt;p&gt;The API support unlocks scenarios that web-only tools can't address:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Automated Social Media Publishing Pipelines&lt;/strong&gt;&lt;br&gt;
Generate Sora videos → Remove watermark → Auto-post to Instagram/TikTok&lt;br&gt;
All without manual intervention.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Batch Processing for Marketing Agencies&lt;/strong&gt;&lt;br&gt;
Process 50+ client videos overnight with our distributed infrastructure. Submit multiple requests simultaneously and receive webhook callbacks as each video completes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Integration with Video Editing Workflows&lt;/strong&gt;&lt;br&gt;
Pull clean videos directly into DaVinci Resolve, Premiere Pro, or CapCut via custom scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. SaaS Product Integration&lt;/strong&gt;&lt;br&gt;
Build watermark removal into your own video editing SaaS without reinventing the wheel. Our API handles the heavy lifting.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Economics: Why Affordable API Pricing Matters
&lt;/h2&gt;

&lt;p&gt;Let's talk numbers. Here's what comparable API-enabled watermark removal typically costs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image watermark APIs&lt;/strong&gt; (Dewatermark, PicWish): $0.10 per credit&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generic video APIs&lt;/strong&gt;: $0.50-2.00 per minute processed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise video APIs&lt;/strong&gt;: $500+ monthly minimums&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Sora-specific processing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kie AI API&lt;/strong&gt;: $0.05 per use (10 credits)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Most competitors&lt;/strong&gt;: No API, or "Contact Sales" pricing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;SoraStrip's API pricing&lt;/strong&gt; (Pro tier):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;$9/month for 100 removals/billing cycle = &lt;strong&gt;$0.09 per video&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Unlimited tier: $50/month = &lt;strong&gt;unlimited usage&lt;/strong&gt; (~$0.016 per video at 3000/month)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This isn't just cheaper—it's &lt;strong&gt;3-5x more affordable&lt;/strong&gt; than comparable services, and the only Sora-specific tool offering genuine unlimited API access with a 99.9% uptime SLA.&lt;/p&gt;
&lt;h2&gt;
  
  
  Technical Deep-Dive: How Watermark Removal Actually Works
&lt;/h2&gt;

&lt;p&gt;Without revealing proprietary algorithms, here's the high-level technical approach:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Watermark Detection
&lt;/h3&gt;

&lt;p&gt;Sora embeds watermarks with specific characteristics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Position: Dynamic (can move within frames)&lt;/li&gt;
&lt;li&gt;Opacity: Semi-transparent (15-30% typically)&lt;/li&gt;
&lt;li&gt;Type: Text + logo combination&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  2. Content-Aware Removal
&lt;/h3&gt;

&lt;p&gt;This is where quality preservation happens. We use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Context prediction&lt;/strong&gt;: ML models predict what pixels should exist behind the watermark&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Temporal consistency&lt;/strong&gt;: Ensure frame-to-frame coherence (no flickering)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edge preservation&lt;/strong&gt;: Maintain sharp details around removal regions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Distributed processing&lt;/strong&gt;: Our infrastructure can handle hundreds of concurrent requests for enterprise-scale batch processing&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  3. Quality Preservation
&lt;/h3&gt;

&lt;p&gt;Unlike tools that re-encode at lower bitrates, SoraStrip:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Maintains original resolution (up to 4K)&lt;/li&gt;
&lt;li&gt;Preserves frame rate&lt;/li&gt;
&lt;li&gt;Keeps original color profiles&lt;/li&gt;
&lt;li&gt;Uses minimal re-encoding (only affected regions)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Result: Output videos are perceptually identical in quality to input.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Developer Experience (DX) Focus
&lt;/h2&gt;

&lt;p&gt;Good DX isn't just about documentation—it's about removing friction:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Instant Onboarding&lt;/strong&gt;&lt;br&gt;
Sign in with Google → Get 1 free removal/day → Test immediately.&lt;br&gt;
No credit card, no approval process. Upgrade to Pro or Ultimate to unlock API access.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Clear Upgrade Paths&lt;/strong&gt;&lt;br&gt;
Polar integration means one-click upgrades with automatic API key provisioning. API keys follow the &lt;code&gt;sk-xxxxxxxx-...&lt;/code&gt; format for easy identification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. RESTful API + SDKs Coming&lt;/strong&gt;&lt;br&gt;
Our RESTful API works with any programming language and framework today. Python, JavaScript, and Ruby SDKs launching soon to abstract away HTTP calls entirely.&lt;/p&gt;
&lt;h2&gt;
  
  
  Roadmap: What's Coming Next
&lt;/h2&gt;

&lt;p&gt;Based on user feedback and technical feasibility:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Already Shipped:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Batch processing via API (process multiple videos simultaneously)&lt;/li&gt;
&lt;li&gt;✅ Webhook support for real-time processing notifications&lt;/li&gt;
&lt;li&gt;✅ 99.9% uptime SLA with distributed infrastructure&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Coming Soon:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python and JavaScript SDKs&lt;/li&gt;
&lt;li&gt;Team accounts with shared usage pools&lt;/li&gt;
&lt;li&gt;White-label API for agencies&lt;/li&gt;
&lt;li&gt;Video editing features (trim, crop, merge) post-removal&lt;/li&gt;
&lt;li&gt;Support for other AI video platforms (Runway, Pika)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Getting Started: From First Test to Production
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Free Trial&lt;/strong&gt;&lt;br&gt;
Visit SoraStrip, sign in with Google, paste a Sora link. See results in seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Upgrade Based on Volume&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Personal projects: Pro ($9/month)&lt;/li&gt;
&lt;li&gt;Agencies/high-volume: Ultimate ($50/month unlimited)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 3: API Integration&lt;/strong&gt;&lt;br&gt;
Grab your API key from the dashboard (Pro/Ultimate plans only). Start with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SORASTRIP_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"sk-your_api_key_here"&lt;/span&gt;

curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.sorastrip.app/api/v1/process &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$SORASTRIP_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "sora_url": "https://sora.chatgpt.com/p/s_XXXXXXXXXXXXXX"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Response:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"processed_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://cdn.sorastrip.com/xyz123.mp4"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"processing_time"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.3s"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Scale&lt;/strong&gt;&lt;br&gt;
Monitor usage, upgrade tiers as needed, and explore bulk processing features.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Broader Lesson: Building Developer Tools in the AI Era
&lt;/h2&gt;

&lt;p&gt;SoraStrip is a case study in a broader trend: &lt;strong&gt;AI tools need API-first architectures from day one.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As AI capabilities proliferate (text-to-video, image generation, audio synthesis), the creators who win won't just build powerful algorithms—they'll build platforms that other developers can integrate into.&lt;/p&gt;

&lt;p&gt;Key principles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;API-first design&lt;/strong&gt; (not an afterthought)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transparent, predictable pricing&lt;/strong&gt; (no "contact sales")&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Developer experience focus&lt;/strong&gt; (docs, SDKs, examples)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ethical considerations&lt;/strong&gt; (clear responsible use policies)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion: Why SoraStrip Exists
&lt;/h2&gt;

&lt;p&gt;OpenAI's Sora democratized cinematic video creation. SoraStrip democratizes access to clean, production-ready Sora videos—especially for developers building the next generation of content tools.&lt;/p&gt;

&lt;p&gt;If you're:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A content creator tired of manual watermark editing&lt;/li&gt;
&lt;li&gt;A developer building video automation pipelines&lt;/li&gt;
&lt;li&gt;An agency processing client Sora videos at scale&lt;/li&gt;
&lt;li&gt;A founder integrating AI video into your product&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SoraStrip's combination of simple web interface, robust API, and affordable pricing was built for you.&lt;/p&gt;

&lt;p&gt;The future of AI video tools isn't just about generation—it's about seamless post-processing workflows. And that future needs to be accessible, affordable, and developer-friendly.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Try SoraStrip&lt;/strong&gt;: &lt;a href="https://sorastrip.app" rel="noopener noreferrer"&gt;sorastrip.app&lt;/a&gt; (Sign in with Google for 1 free daily removal)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;API Documentation&lt;/strong&gt;: &lt;a href="https://sorastrip.app/api-docs" rel="noopener noreferrer"&gt;sorastrip.app/api-docs&lt;/a&gt; (Pro/Ultimate plans)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Questions?&lt;/strong&gt; Email: &lt;a href="mailto:sorastrip@gmail.com"&gt;sorastrip@gmail.com&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Frequently Asked Questions (Technical Edition)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Q: How does link-based processing compare to upload-based tools?&lt;/strong&gt;&lt;br&gt;
Link-based eliminates 200-500MB file transfers per video. Processing starts immediately, and outputs are served via CDN links—no re-downloading needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I process private/unlisted Sora videos?&lt;/strong&gt;&lt;br&gt;
Only publicly shared links work. Regenerate your share link with public visibility in Sora.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What's the API response time SLA?&lt;/strong&gt;&lt;br&gt;
P95 latency: &amp;lt;5 seconds for typical Sora videos (3-5 seconds duration). 99.9% uptime SLA on Pro and Ultimate tiers with automatic failover.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I get API access?&lt;/strong&gt;&lt;br&gt;
API keys are available exclusively for Pro ($9/month) and Ultimate ($50/month) plan users. Generate keys instantly from your dashboard after upgrading—no approval process or waiting period.&lt;/p&gt;




&lt;h3&gt;
  
  
  Keywords for SEO:
&lt;/h3&gt;

&lt;p&gt;Sora watermark removal, SoraStrip API, remove Sora watermark, OpenAI Sora video, Sora video API, watermark remover API, AI video editing, Sora share link processing, affordable video API, developer video tools, Sora video clean, text-to-video AI, ChatGPT Sora, remove OpenAI watermark, video watermark API, programmatic watermark removal&lt;/p&gt;




&lt;p&gt;&lt;em&gt;This article was written to share the technical journey behind building SoraStrip. If you're building in the AI video space, I'd love to connect and hear what you're working on.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>api</category>
      <category>ai</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Picking Your Automation: Zapier, Make, or n8n?</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Tue, 07 Oct 2025 19:31:09 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/picking-your-automation-zapier-make-or-n8n-3h0a</link>
      <guid>https://forem.com/aadarsh-nagrath/picking-your-automation-zapier-make-or-n8n-3h0a</guid>
      <description>&lt;p&gt;Hey, if you're knee-deep in apps and feeling like your workflow's a tangled mess, automation tools aren't just nice-to-haves—they're the quiet heroes keeping things from falling apart. &lt;/p&gt;

&lt;p&gt;Solo hustler? Small team grinding? Or enterprise trying not to drown in tabs? Zapier, Make (ex-Integromat), and n8n are the heavy hitters here, each with its own vibe for stitching services together without the headache.&lt;/p&gt;

&lt;p&gt;As of October 2025, I've dug into the latest—fresh pricing pulls, user chatter on X and Reddit, and those deep-dive comparisons floating around. &lt;/p&gt;

&lt;p&gt;We'll cover the basics like cost and connections, plus deeper cuts on security, support, real use cases, and even switching between 'em. Goal? Arm you to pick without second-guessing. No hype, just straight talk.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick Hits (TL;DR)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: Easiest entry for non-coders, massive app library (8,000+), but costs add up quick on volume. Great for quick AI tweaks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: Visual wizard for complex no-code flows, solid mid-range pricing, handles data like a champ. Balanced pick for teams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: Dev's dream—open-ish, self-hostable, crazy flexible for AI and custom stuff. Cheapest long-term if you manage your own setup.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwnjvr1jadmzci4cev53j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwnjvr1jadmzci4cev53j.png" alt="." width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Newbie or hate code? Zapier. Visual power without scripts? Make. Tinkerer or budget hawk? n8n. Test 'em free and see what clicks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing: Where Your Wallet Feels It
&lt;/h2&gt;

&lt;p&gt;Costs evolve, so here's the October 2025 rundown—pulled straight from their sites. They bill on usage (tasks, ops, executions), but models vary. Annual saves 15-20% usually.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Free Tier&lt;/th&gt;
&lt;th&gt;Starter Paid (Annual Mo. Est.)&lt;/th&gt;
&lt;th&gt;Scaling Model &amp;amp; Mid-Tier&lt;/th&gt;
&lt;th&gt;High-Volume/Enterprise&lt;/th&gt;
&lt;th&gt;Gotchas&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Zapier&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100 tasks/mo; basic Zaps, Tables, Interfaces&lt;/td&gt;
&lt;td&gt;Pro: $20/mo (2K tasks)&lt;/td&gt;
&lt;td&gt;Tasks per action (e.g., $49/mo Pro for 10K); pay-as-you-go overage at 1.25x&lt;/td&gt;
&lt;td&gt;Custom (2M+ tasks); dedicated support&lt;/td&gt;
&lt;td&gt;Tasks count per successful step—multi-step eats quota fast. AI calls (via MCP) = 2 tasks each.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Make&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1K ops/mo; 2 scenarios, 512MB data&lt;/td&gt;
&lt;td&gt;Core: $9/mo (10K ops)&lt;/td&gt;
&lt;td&gt;Ops per module (Pro $16/mo 10K ops; Teams $29/mo); unlimited scenarios&lt;/td&gt;
&lt;td&gt;Custom; overage protection&lt;/td&gt;
&lt;td&gt;Ops include filters/transfers—predictable for chains. AI agents beta included higher up.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;n8n&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Community: Unlimited self-host (your server costs ~$5-20/mo)&lt;/td&gt;
&lt;td&gt;Cloud Starter: €20/mo (2.5K execs)&lt;/td&gt;
&lt;td&gt;Executions per full workflow (Pro €50/mo 10K); unlimited steps&lt;/td&gt;
&lt;td&gt;Business €667/mo (40K self-host); Enterprise custom&lt;/td&gt;
&lt;td&gt;Executions = whole run, not per step—huge win for complex. Startup discount if &amp;lt;20 folks.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;n8n wins for heavy users (10-50x cheaper on intricate stuff), Make for steady mid-volume without infra hassle, Zapier if you value simplicity over savings. Recent n8n tweak: Dropped workflow caps, but cloud bumped slightly for concurrency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrations: Hooking Up Your Stack
&lt;/h2&gt;

&lt;p&gt;It's all about breadth vs. bendiness—how many apps, and can you Frankenstein the rest?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gpavxeuic69906rxxy6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8gpavxeuic69906rxxy6.png" alt="." width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: 8,000+ pre-builts, from Slack to obscure CRMs. If it's SaaS-y, it's there. Recent adds: 73 in Sept '25 alone. Killer for off-the-shelf.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: 3,000+ apps, plus HTTP magic for APIs. Visual drag-drop shines for chaining weird combos, like custom webhooks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: 350+ core nodes, but HTTP/GraphQL/cURL imports let you build anything. Community nodes push it to 1,000+ effective. Devs rave about extending it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Zapier for volume, n8n for "anything goes," Make in the middle with pretty diagrams. X users echo: n8n's snappier for custom APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dev Tools: Code If You Want, Skip If You Don't
&lt;/h2&gt;

&lt;p&gt;From snippets to full scripts—depends on your comfort.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: JS/Python in "Code Steps," but timed out quick, no libs. Good for light math or fetches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: JS customs on Enterprise; otherwise, modules for logic. No-code first, code as add-on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: Native JS/Python nodes, npm installs (self-host), bash runs. Import cURL, debug live—feels like VS Code lite.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;n8n laps 'em for coders; others keep it visual.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Handling: Bouncing Back from Glitches
&lt;/h2&gt;

&lt;p&gt;Shit hits the fan—how do they recover?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: Retries, basic notifications, error paths in Zaps. Solid but shallow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: Ignore/resume/rollback per module, full logs/search. Dashboards flag issues early.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: Node-specific catches, error workflows, replays. Alerts to anywhere, unlimited logs self-hosted.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Make/n8n tie for pros; Zapier's fine for starters.&lt;/p&gt;

&lt;h2&gt;
  
  
  AI Smarts: Leveling Up with Bots and Agents
&lt;/h2&gt;

&lt;p&gt;AI's everywhere now—summaries, agents, RAGs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: MCP for 8K+ AI actions (2 tasks/call), Copilot builder, beta chatbots. 800K daily AI tasks automated. Easy for enrichment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: 350+ AI apps, beta Agents with your LLM key, Vision/Text tools. Visual agent mapping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: 70+ nodes, LangChain deep-dive for RAG/agents/vectors. Local models, full pipelines—build products, not just tasks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;n8n for AI builders, Zapier for plug-in ease, Make for no-code agents.&lt;/p&gt;

&lt;h2&gt;
  
  
  Team Play: Sharing Without the Chaos
&lt;/h2&gt;

&lt;p&gt;Collab keeps it smooth.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: Shared workspaces Team+ ($69/mo), basic roles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: Unlimited users, roles/templates on Teams ($29/mo), API limits scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: Unlimited users all tiers, RBAC/Git sync. Projects segment access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;n8n/Make flex better; Zapier catches up at scale.&lt;/p&gt;

&lt;h2&gt;
  
  
  Scaling: From Side Gig to Beast Mode
&lt;/h2&gt;

&lt;p&gt;Growth test: High volume? Complex?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxi47r80w354gdckkt7r0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxi47r80w354gdckkt7r0.png" alt="." width="680" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: Handles 2M tasks easy, but costs/logic branches strain.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: Unlimited scenarios, 1GB files Enterprise, API bursts to 1K/min.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: Kubernetes/queues for infinite, 200+ concurrent Enterprise. Self-host = your limits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;n8n for infinite tweak, Make for managed growth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pros &amp;amp; Cons: At a Glance
&lt;/h2&gt;

&lt;p&gt;Quick gut-check.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Zapier&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: Dead simple UI, huge integrations, managed everything.&lt;/li&gt;
&lt;li&gt;Cons: Pricey at volume, less dev depth, cloud-only.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Make&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: Visual flows rock, affordable ops, strong monitoring.&lt;/li&gt;
&lt;li&gt;Cons: Code locked high-tier, fewer apps than Zapier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;n8n&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pros: Cheap/flexible, AI/dev heaven, self-host privacy.&lt;/li&gt;
&lt;li&gt;Cons: Setup curve if hosting, smaller out-of-box library.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;p&gt;From recent chats: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Marketing team&lt;/strong&gt;: Zapier for lead Slack pings + email nurtures. Quick, no fuss.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;E-com ops&lt;/strong&gt;: Make routing orders to inventory/shipping, with error rollbacks. Handles spikes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev startup&lt;/strong&gt;: n8n self-hosted for AI agent scraping + vector DB, under $20/mo infra. Scaled to 10K runs/day.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;X buzz: n8n extensions like Vibe for chat-building flows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security, Privacy &amp;amp; Compliance: Trust Factor
&lt;/h2&gt;

&lt;p&gt;Data's gold—don't skimp.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Zapier&lt;/strong&gt;: SOC 2 Type II, GDPR, encrypted transit/storage. Enterprise governance, no self-host.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Make&lt;/strong&gt;: SOC 2/GDPR, SSO/SAML, audit logs (60 days Enterprise). On-prem agents for sensitive.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;n8n&lt;/strong&gt;: Self-host = full control (your firewalls). Cloud: Encrypted, but fair-code license. No HIPAA native, but extensible.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All solid for most; n8n if privacy's paramount, Zapier/Make for certs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support &amp;amp; Community: When You Get Stuck
&lt;/h2&gt;

&lt;p&gt;Help matters.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: Huge community forums, docs, Premier chat (Team+). Active updates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: Tiered email (high Enterprise), templates sharing, analytics help.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: Forum/GitHub vibrant, email Pro+, dedicated Enterprise. Devs love the openness.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;n8n's crowd-sourced edge; others more hand-holding.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learning Curve: Jump In Time
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Zapier&lt;/strong&gt;: 10 mins to first Zap—intuitive.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make&lt;/strong&gt;: Hour for visuals, day for routers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;n8n&lt;/strong&gt;: Day for basics, week for customs. Templates speed it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start simple, scale skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  Switching Gears: Migration Tips
&lt;/h2&gt;

&lt;p&gt;From Zapier? Export JSON, rebuild in visual (Make) or nodes (n8n). Make to n8n: Scenarios map easy to workflows. Tools like n8n's importer help. Test parallel first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping It: Your Move
&lt;/h2&gt;

&lt;p&gt;Zapier if you want set-it-forget-it bliss. Make for that sweet no-code power without vendor lock. n8n if you're building the future—cost, control, AI all in one.&lt;/p&gt;

&lt;p&gt;Long-term? n8n's momentum (X hype on agents) feels right. Grab free tiers, mock a flow, and run. Your stack will thank you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick FAQs
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Best for pure AI agents?&lt;/strong&gt; n8n—LangChain nodes let you chain LLMs wild. Make's beta close second.&lt;br&gt;
&lt;strong&gt;Self-hosting worth it?&lt;/strong&gt; For n8n, yeah if privacy/scale matter; ~$10/mo AWS. Skip for Zapier/Make (cloud-only).&lt;br&gt;
&lt;strong&gt;HIPAA compliant?&lt;/strong&gt; Make/Zapier Enterprise yes; n8n via self-host tweaks.&lt;br&gt;
&lt;strong&gt;Free forever viable?&lt;/strong&gt; Zapier/Make for light (100-1K runs); n8n unlimited if you host.&lt;br&gt;
&lt;strong&gt;Team of 1 vs. 10?&lt;/strong&gt; Solo: Any. Growing: Make/n8n for unlimited users cheap.&lt;/p&gt;

</description>
      <category>nocode</category>
      <category>automation</category>
      <category>tooling</category>
      <category>productivity</category>
    </item>
    <item>
      <title>N8N: The Workflow Automation Tool Worth Knowing About</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Tue, 07 Oct 2025 13:28:10 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/n8n-the-workflow-automation-tool-worth-knowing-about-44gd</link>
      <guid>https://forem.com/aadarsh-nagrath/n8n-the-workflow-automation-tool-worth-knowing-about-44gd</guid>
      <description>&lt;p&gt;I've been using n8n for a while now, and it's one of those tools that just makes sense once you get into it.&lt;/p&gt;

&lt;p&gt;It's a workflow automation platform, kind of like Zapier or Make, but with some differences that actually matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  What n8n Actually Does
&lt;/h2&gt;

&lt;p&gt;The name is a bit weird - it's pronounced "n-eight-n" because if you count the letters between 'n' and 'n' in "automation," there are eight. Anyway, it lets you connect different apps and automate tasks between them. Pretty standard stuff on the surface.&lt;/p&gt;

&lt;p&gt;The interesting part is that it's open-source (technically "fair-code"), which means you can run it on your own server if you want. No one's forcing you to, but the option's there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why People Like It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;You can host it yourself&lt;/strong&gt;. This matters more to some people than others. If you're dealing with customer data or anything sensitive, keeping everything on your own infrastructure is kind of nice. Plus you're not worrying about some SaaS company changing their pricing or getting acquired.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The pricing makes sense&lt;/strong&gt;. Most automation tools charge you per "task" or "operation," and those costs add up fast. With n8n, if you self-host, it's free. Their cloud version is reasonably priced too, and they don't nickel-and-dime you with weird limits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It's actually flexible&lt;/strong&gt;. You get a visual interface for building workflows, which is great. But when you need to do something custom, you can write JavaScript right in there. Or connect to any API. Or build your own integrations. It doesn't box you in.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It Works
&lt;/h2&gt;

&lt;p&gt;The interface is node-based. You drag boxes (nodes) onto a canvas, connect them with lines, and each box does something - pull data from a spreadsheet, send a message, process information, whatever.&lt;/p&gt;

&lt;p&gt;It's visual enough to understand what's happening but powerful enough to do complex stuff.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgh71g0gt8hnrns4cepme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgh71g0gt8hnrns4cepme.png" alt="." width="800" height="232"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One thing I appreciate is that you can test each step as you build. You're not just hoping it works when you hit "save" - you can see exactly what data is flowing through at each point.&lt;/p&gt;

&lt;h2&gt;
  
  
  What People Build With It
&lt;/h2&gt;

&lt;p&gt;Some common patterns I've seen:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Content teams&lt;/strong&gt; use it to publish once and distribute everywhere. Write a blog post, and it automatically creates social media posts, adds it to the newsletter, updates various platforms. Saves a ton of time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Support teams&lt;/strong&gt; build smart ticket routing. New support request comes in, it checks if they're an important customer, looks for relevant help docs, sends an initial response, and notifies the right person. Response times improve significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Developers&lt;/strong&gt; connect all their tools together. When code gets merged, it deploys to staging. When errors happen, it creates detailed tickets. When builds fail, it notifies the team. It's the glue between different systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Marketing folks&lt;/strong&gt; seem to love it. They build lead scoring systems, automated follow-ups based on user behavior, social listening tools, and reporting dashboards that pull from multiple ad platforms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting It Running
&lt;/h2&gt;

&lt;p&gt;Three ways to go about it:&lt;/p&gt;

&lt;p&gt;Use their cloud version - easiest option, works immediately, they handle everything.&lt;/p&gt;

&lt;p&gt;Run it with Docker - takes maybe 15 minutes if you're comfortable with that kind of thing. Good middle ground.&lt;/p&gt;

&lt;p&gt;Full custom setup - deploy it however you want, integrate with whatever infrastructure you have.&lt;/p&gt;

&lt;p&gt;Most people either start with the cloud version to try it out, or jump straight to Docker if they're technical.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Integration Situation
&lt;/h2&gt;

&lt;p&gt;They've got 400+ integrations built in. All the usual suspects - Google services, Slack, databases, cloud platforms, CRM tools, e-commerce stuff, AI services. &lt;/p&gt;

&lt;p&gt;If what you need isn't there, you can still connect to it using their HTTP request node. Basically anything with an API works. And the community keeps building new integrations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9f3bvtg0j67equ5hoybz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9f3bvtg0j67equ5hoybz.png" alt="." width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Some Handy Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Sub-workflows&lt;/strong&gt; let you build reusable pieces. Make something once, use it in multiple workflows. Keeps things organized.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Error handling&lt;/strong&gt; means your workflows don't just break and fail silently. You can set up retries, fallbacks, notifications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scheduling&lt;/strong&gt; is built in. Run things hourly, daily, weekly, whatever schedule you need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Database connections&lt;/strong&gt; let you query and update databases directly. Sometimes you just need to work with data where it lives.&lt;/p&gt;

&lt;h2&gt;
  
  
  Things to Know
&lt;/h2&gt;

&lt;p&gt;If you want to self-host, you need some technical comfort. Not expert-level, but you should know your way around Docker and servers at least a bit.&lt;/p&gt;

&lt;p&gt;The interface is really made for desktop. Using it on a phone would be awkward.&lt;/p&gt;

&lt;p&gt;Some integrations are more polished than others. Popular services have everything you'd want. Niche ones might need you to use the HTTP node for certain features.&lt;/p&gt;

&lt;p&gt;You can build really complex workflows, which is great until you need to debug them six months later. Good documentation habits help.&lt;/p&gt;

&lt;h2&gt;
  
  
  When It Makes Sense
&lt;/h2&gt;

&lt;p&gt;N8n works well if you want control over your automation setup, if you're hitting pricing limits elsewhere, or if you need to keep data in-house. It's also good if you like having the option to customize things when needed.&lt;/p&gt;

&lt;p&gt;If you just need super basic automation and don't care about cost or control, something simpler might be fine. But if you're reading a comprehensive guide about automation tools, you're probably past that point.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Community
&lt;/h2&gt;

&lt;p&gt;There's an active community around it. People share workflow templates, help each other out in forums and Discord, contribute code. The company (they're based in Berlin) does a good job maintaining it and being transparent about what they're working on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Worth Trying?
&lt;/h2&gt;

&lt;p&gt;If you're doing any serious automation work, it's at least worth a look. The cloud version is easy to try out, and you can always move to self-hosting later if you want.&lt;/p&gt;

&lt;p&gt;It's one of those tools that grows with you. Start simple, add complexity when you need it. That's kind of the sweet spot for this type of software.&lt;/p&gt;

&lt;p&gt;The workflow automation space has a lot of options, but n8n hits a good balance between being accessible and being powerful. Plus the whole open-source angle means you're not locked into someone's ecosystem if things change down the road.&lt;/p&gt;

&lt;p&gt;Anyway, that's n8n. It does what it says it does, and does it pretty well.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>n8nbrightdatachallenge</category>
      <category>automation</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Yo, Wanna Surf the Dark Web? Here’s How to Do It Without Getting Hacked!</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Sat, 27 Sep 2025 07:57:37 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/yo-wanna-surf-the-dark-web-heres-how-to-do-it-without-getting-hacked-2g7h</link>
      <guid>https://forem.com/aadarsh-nagrath/yo-wanna-surf-the-dark-web-heres-how-to-do-it-without-getting-hacked-2g7h</guid>
      <description>&lt;p&gt;Alright, let’s talk about the dark web—that mysterious corner of the internet that feels like a secret club. Before you jump in, I’m gonna show you three ways to access it safely, from the “you’re begging to get hacked” method to the “you’re basically a ghost” level of stealth. Think top-tier, can’t-touch-me security. &lt;/p&gt;

&lt;p&gt;First off, the dark web isn’t &lt;em&gt;all&lt;/em&gt; bad. It was created with good vibes—think journalists protecting their sources or folks dodging oppressive governments. You can even play chess on there without anyone snooping! Big names like the New York Times, BBC, and even the CIA have dark web sites.&lt;/p&gt;

&lt;p&gt;Pretty cool, right? But that same anonymity makes it a hotspot for sketchy stuff too. Like, your email, passwords, and logins? They’re probably being sold there &lt;em&gt;right now&lt;/em&gt;. Scary, I know.&lt;/p&gt;

&lt;p&gt;That’s why I use a password manager with dark web monitoring to keep my info safe. It alerts me if my data’s out there and generates super-secure passwords that are basically unhackable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqikn6ug6ggnvcjtcrt82.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqikn6ug6ggnvcjtcrt82.png" alt="." width="728" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I use it for all my accounts, and it’s a game-changer. Trust me, most hacks happen ‘cause someone used a weak password or clicked a shady link. Don’t be that person.&lt;/p&gt;

&lt;p&gt;Now, let’s dive into the three ways to access the dark web without ending up in a hacker’s trap.&lt;/p&gt;

&lt;p&gt;Before that feel free to follow me on &lt;a href="https://x.com/aadarsh_nagrath" rel="noopener noreferrer"&gt;X&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Level 1: The “Please Don’t Do This” Way
&lt;/h2&gt;

&lt;p&gt;I know some of you are gonna try this anyway, but this is the &lt;em&gt;least&lt;/em&gt; secure way to hit the dark web. All you need is the &lt;strong&gt;Tor Browser&lt;/strong&gt;. It’s like Chrome or Firefox, but for the dark web (aka the Onion Network—yep, onions everywhere). Here’s how it goes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Head to the Tor Project website.&lt;/li&gt;
&lt;li&gt;Download the Tor Browser for your operating system (iOS users, hang tight, we’ll get to you).&lt;/li&gt;
&lt;li&gt;Install it, click “Connect,” and bam—you’re on the dark web.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sounds simple, right? Too simple. The Tor Browser sends your data through three “onion routers,” each adding a layer of encryption to keep you anonymous. But this basic setup is like walking into a shady alley with no backup. You &lt;em&gt;can&lt;/em&gt; access regular sites (the “clearnet”) with Tor, but dark web sites? They’re hidden, ending in “.onion.”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjd2gcg1khmibfrhjxul.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbjd2gcg1khmibfrhjxul.png" alt="." width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For example, the New York Times has a dark web version, but you’d need the exact address to find it. No Google here—those sites are &lt;em&gt;dark&lt;/em&gt; for a reason. There’s a site called the Hidden Wiki that lists some dark web sites, and a search engine called Ahmia, but even those can’t index everything. &lt;/p&gt;

&lt;p&gt;This method? It’s risky. You’re exposed with default settings, so let’s move on to something safer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Level 2: A Bit Safer, But Still Not Great
&lt;/h2&gt;

&lt;p&gt;This is a step up, but still not the &lt;em&gt;best&lt;/em&gt; way to browse the dark web. You’ll use the same Tor Browser, but with some extra protection—like adding another layer to your onion. Here’s the deal:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Before connecting to the Tor network, fire up a &lt;strong&gt;VPN&lt;/strong&gt; you trust. This hides your activity from your internet provider, who can totally see you’re using Tor otherwise. &lt;/li&gt;
&lt;li&gt;Launch the Tor Browser and tweak some settings. Go to “Configure Connection,” then “Privacy and Security,” and set the security level to “Safest.” This disables JavaScript and other features hackers could exploit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Why the VPN? Without it, your internet provider and the first onion router you connect to can see your IP address. That’s a weak spot where leaks happen—yep, that’s how the FBI and CIA track people. A VPN encrypts your connection &lt;em&gt;before&lt;/em&gt; it hits the Tor network, adding a solid layer of protection. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F887a91fekigy75ovenhb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F887a91fekigy75ovenhb.png" alt="." width="800" height="511"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With these tweaks, you’re safer than Level 1, but it’s still not bulletproof. Let’s level up to the real deal.&lt;/p&gt;




&lt;h2&gt;
  
  
  Level 3: The “You’re Basically Invisible” Way
&lt;/h2&gt;

&lt;p&gt;This is the &lt;em&gt;most&lt;/em&gt; secure way to access the dark web, and it’s the only method I’d recommend. You’re gonna create a portable computer on a USB drive using &lt;strong&gt;Tails Linux&lt;/strong&gt;—a super-secure operating system that forgets everything you do. It’s like a goldfish with amnesia. Even Edward Snowden trusts this setup, and he’s still chilling in Russia, so you know it’s legit.&lt;/p&gt;

&lt;p&gt;Here’s what you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A USB drive with at least 8GB of space (super cheap on Amazon).&lt;/li&gt;
&lt;li&gt;A computer (almost any will do).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07li1ien2bgwes77udm0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F07li1ien2bgwes77udm0.png" alt="." width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s how to set it up:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;tails.net&lt;/strong&gt; and download the Tails USB image.&lt;/li&gt;
&lt;li&gt;Grab &lt;strong&gt;Balena Etcher&lt;/strong&gt; (free software) to write the Tails image to your USB drive.&lt;/li&gt;
&lt;li&gt;Plug in your USB, open Etcher, select the Tails image, choose your USB as the target, and hit “Flash.”&lt;/li&gt;
&lt;li&gt;Once it’s done, shut down your computer, plug in the USB, and boot from it. You might need to hit a key like F12, F10, or Delete to access the boot menu (depends on your computer).&lt;/li&gt;
&lt;li&gt;Boom—you’re running Tails Linux. Connect to Wi-Fi (or use an Ethernet cable if Wi-Fi’s finicky), and Tails automatically routes everything through the Tor network.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tails is a full-blown operating system that leaves &lt;em&gt;no trace&lt;/em&gt;. When you’re done, shut it down, pull the USB, and it’s like you were never there. Want extra security? Connect to a VPN &lt;em&gt;before&lt;/em&gt; launching the Tor Browser in Tails. That’s VPN + Tor + Tails—a fortress of anonymity.&lt;/p&gt;

&lt;p&gt;Pro tip: You can set up persistent storage on Tails to save files, but if you’re going for max security, skip it. The default setup is designed to keep you untraceable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Level 3.75 – The Cloud Browser
&lt;/h2&gt;

&lt;p&gt;There’s one more way that’s arguably as secure as Tails, maybe even more. It’s a &lt;strong&gt;cloud browser&lt;/strong&gt;—a remote computer somewhere else in the world that runs the Tor Browser for you.&lt;/p&gt;

&lt;p&gt;Just pick a location (Europe, US, wherever), click to launch, and you’re browsing the dark web from a machine that’s not yours. It’s super secure, and bonus: it works on your phone too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg2eshwa4s8vp4wkbrmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg2eshwa4s8vp4wkbrmm.png" alt="." width="690" height="406"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Stay Safe Out There
&lt;/h2&gt;

&lt;p&gt;Even with Level 3 or 3.75, the dark web is no joke. It’s a wild place with no oversight, so take extra precautions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don’t download anything unless you’re &lt;em&gt;sure&lt;/em&gt; it’s safe. Disconnect from the internet before opening files—they could phone home and expose you.&lt;/li&gt;
&lt;li&gt;Stick to known sites like the Hidden Wiki or legit dark web versions of mainstream sites.&lt;/li&gt;
&lt;li&gt;Always assume someone’s watching, even if you’re super secure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dark web can be cool, but it’s also a minefield. Use Tails or a cloud browser, keep your passwords locked down with a solid password manager, and don’t become one of those scary dark web stories. Stay safe, and happy (anonymous) surfing!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Keep Using Cursor for FREE on MacOS/Linux 🖥️</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Tue, 23 Sep 2025 15:09:38 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/how-to-keep-using-cursor-for-free-on-macoslinux-31pj</link>
      <guid>https://forem.com/aadarsh-nagrath/how-to-keep-using-cursor-for-free-on-macoslinux-31pj</guid>
      <description>&lt;p&gt;Hey there, coder! 😎 So, you’ve been loving &lt;strong&gt;Cursor&lt;/strong&gt;, that sweet AI-powered code editor, but your free trial just ended, and you’re not ready to commit to a paid plan. No stress! &lt;/p&gt;

&lt;p&gt;Here’s a chill, step-by-step guide to keep using Cursor for free on your MacOS/Linux machine. We’ll use a simple script and a disposable email to reset your trial like a pro. Don’t worry, I’ll explain what the script does, why it’s safe, and how to make it all work. &lt;/p&gt;

&lt;p&gt;Later I'll update this blog to make it usefull in windows as well&lt;br&gt;
I haven't tried it on linux but i speculate it will work there as well go give it a try&lt;/p&gt;

&lt;p&gt;Let’s dive in! 🚀&lt;/p&gt;

&lt;p&gt;Follow me on &lt;a href="https://x.com/aadarsh_nagrath" rel="noopener noreferrer"&gt;X&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  What You’ll Need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A MacOS computer (Intel or Apple Silicon, doesn’t matter, we got you covered).&lt;/li&gt;
&lt;li&gt;Basic familiarity with the Terminal (don’t worry, it’s super easy).&lt;/li&gt;
&lt;li&gt;An internet connection to grab a temporary email and download the script’s goodies.&lt;/li&gt;
&lt;li&gt;A vibe for keeping things simple and free. 😎&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step-by-Step Guide to Keep Cursor Free
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Step 1: Sign Out of Cursor
&lt;/h3&gt;

&lt;p&gt;Once your free trial is over, open the Cursor app and &lt;strong&gt;sign out&lt;/strong&gt; of your account. This clears the slate for a fresh start. Close the app completely when you’re done.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Clear Cursor’s Data
&lt;/h3&gt;

&lt;p&gt;To reset the trial, we need to remove some local data Cursor stores on your Mac. Open your &lt;strong&gt;Terminal&lt;/strong&gt; (you can find it in Applications &amp;gt; Utilities or search for it with Spotlight). Run these commands one by one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/Cursor
&lt;span class="nb"&gt;sudo rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; ~/Library/Application&lt;span class="se"&gt;\ &lt;/span&gt;Support/cursor-updater
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What’s happening here?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
These commands delete Cursor’s local data, like cached settings and trial info. The &lt;code&gt;sudo&lt;/code&gt; part means you’re running it with admin privileges, so you’ll need to enter your Mac password. Don’t worry, this is totally safe—it’s just clearing out app-specific files, not touching anything critical to your system. It’s like wiping the app’s memory so it thinks it’s being installed fresh.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: Close Cursor
&lt;/h3&gt;

&lt;p&gt;Make sure the Cursor app is fully closed. You can do this by right-clicking its icon in the Dock and selecting &lt;strong&gt;Quit&lt;/strong&gt;, or use &lt;code&gt;Command + Q&lt;/code&gt; when the app is active.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: Create the Magic Script
&lt;/h3&gt;

&lt;p&gt;Now, we’re gonna create a script called &lt;code&gt;install.sh&lt;/code&gt; that automates downloading and setting up a fresh Cursor install. Open Terminal and create the file by typing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy and paste the following script into the Terminal window:&lt;/p&gt;

&lt;p&gt;You can get the script form here as well -&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;https://github.com/yeongpin/cursor-free-vip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# Color definitions&lt;/span&gt;
&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;31m'&lt;/span&gt;
&lt;span class="nv"&gt;GREEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;32m'&lt;/span&gt;
&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[1;33m'&lt;/span&gt;
&lt;span class="nv"&gt;BLUE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;34m'&lt;/span&gt;
&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0;36m'&lt;/span&gt;
&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'\033[0m'&lt;/span&gt; &lt;span class="c"&gt;# No Color&lt;/span&gt;

&lt;span class="c"&gt;# Logo&lt;/span&gt;
print_logo&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt;"
   ██████╗██╗   ██╗██████╗ ███████╗ ██████╗ ██████╗      ██████╗ ██████╗  ██████╗   
  ██╔════╝██║   ██║██╔══██╗██╔════╝██╔═══██╗██╔══██╗     ██╔══██╗██╔══██╗██╔═══██╗  
  ██║     ██║   ██║██████╔╝███████╗██║   ██║██████╔╝     ██████╔╝██████╔╝██║   ██║  
  ██║     ██║   ██║██╔══██╗╚════██║██║   ██║██╔══██╗     ██╔═══╝ ██╔══██╗██║   ██║  
  ╚██████╗╚██████╔╝██║  ██║███████║╚██████╔╝██║  ██║     ██║     ██║  ██║╚██████╔╝  
   ╚═════╝ ╚═════╝ ╚═╝  ╚═╝╚══════╝ ╚═════╝ ╚═╝  ╚═╝     ╚═╝     ╚═╝  ╚═╝ ╚═════╝  
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Get download folder path&lt;/span&gt;
get_downloads_dir&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Darwin"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Downloads"&lt;/span&gt;
    &lt;span class="k"&gt;else
        if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.config/user-dirs.dirs"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.config/user-dirs.dirs"&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;XDG_DOWNLOAD_DIR&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="p"&gt;/Downloads&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;else
            &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/Downloads"&lt;/span&gt;
        &lt;span class="k"&gt;fi
    fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Get latest version&lt;/span&gt;
get_latest_version&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Checking latest version...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nv"&gt;latest_release&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-s&lt;/span&gt; https://api.github.com/repos/yeongpin/cursor-free-vip/releases/latest&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;❌ Cannot get latest version information&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$latest_release&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s1"&gt;'"tag_name": ".*"'&lt;/span&gt; | &lt;span class="nb"&gt;cut&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="s1"&gt;'"'&lt;/span&gt; &lt;span class="nt"&gt;-f4&lt;/span&gt; | &lt;span class="nb"&gt;tr&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'v'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-z&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$VERSION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;❌ Failed to parse version from GitHub API response:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;latest_release&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GREEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;✅ Found latest version: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Detect system type and architecture&lt;/span&gt;
detect_os&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Darwin"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="c"&gt;# Detect macOS architecture&lt;/span&gt;
        &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ARCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"arm64"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mac_arm64"&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Detected macOS ARM64 architecture&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;else
            &lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mac_intel"&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Detected macOS Intel architecture&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;fi
    elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"Linux"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="c"&gt;# Detect Linux architecture&lt;/span&gt;
        &lt;span class="nv"&gt;ARCH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;uname&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ARCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"aarch64"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ARCH&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"arm64"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"linux_arm64"&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Detected Linux ARM64 architecture&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;else
            &lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"linux_x64"&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Detected Linux x64 architecture&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;fi
    else&lt;/span&gt;
        &lt;span class="c"&gt;# Assume Windows&lt;/span&gt;
        &lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"windows"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Detected Windows system&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Install and download&lt;/span&gt;
install_cursor_free_vip&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;downloads_dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;get_downloads_dir&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;binary_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"CursorFreeVIP_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;downloads_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;download_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/yeongpin/cursor-free-vip/releases/download/v&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# Check if file already exists&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GREEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;✅ Found existing installation file&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Location: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

        &lt;span class="c"&gt;# Check if running as root&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$EUID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-ne&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;⚠️ Requesting administrator privileges...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;/dev/null 2&amp;gt;&amp;amp;1&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
                &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Starting program with sudo...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="nb"&gt;sudo chmod&lt;/span&gt; +x &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="nb"&gt;sudo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="k"&gt;else
                &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;⚠️ sudo not found, trying to run normally...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="nb"&gt;chmod&lt;/span&gt; +x &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="k"&gt;fi
        else&lt;/span&gt;
            &lt;span class="c"&gt;# Already running as root&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Already running as root, starting program...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="nb"&gt;chmod&lt;/span&gt; +x &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;fi
        return
    fi

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ No existing installation file found, starting download...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Downloading to &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;downloads_dir&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Download link: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;download_url&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# Check if file exists&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;curl &lt;span class="nt"&gt;--output&lt;/span&gt; /dev/null &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--head&lt;/span&gt; &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$download_url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GREEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;✅ File exists, starting download...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;❌ Download link does not exist: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;download_url&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;⚠️ Trying without architecture...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

        &lt;span class="c"&gt;# Try without architecture&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"mac_arm64"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"mac_intel"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mac"&lt;/span&gt;
            &lt;span class="nv"&gt;binary_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"CursorFreeVIP_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="nv"&gt;download_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/yeongpin/cursor-free-vip/releases/download/v&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ New download link: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;download_url&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; curl &lt;span class="nt"&gt;--output&lt;/span&gt; /dev/null &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--head&lt;/span&gt; &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$download_url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
                &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;❌ New download link does not exist&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="nb"&gt;exit &lt;/span&gt;1
            &lt;span class="k"&gt;fi
        elif&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"linux_x64"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OS&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"linux_arm64"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
            &lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"linux"&lt;/span&gt;
            &lt;span class="nv"&gt;binary_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"CursorFreeVIP_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OS&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="nv"&gt;download_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://github.com/yeongpin/cursor-free-vip/releases/download/v&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;VERSION&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_name&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ New download link: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;download_url&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; curl &lt;span class="nt"&gt;--output&lt;/span&gt; /dev/null &lt;span class="nt"&gt;--silent&lt;/span&gt; &lt;span class="nt"&gt;--head&lt;/span&gt; &lt;span class="nt"&gt;--fail&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$download_url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
                &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;❌ New download link does not exist&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
                &lt;span class="nb"&gt;exit &lt;/span&gt;1
            &lt;span class="k"&gt;fi
        else
            &lt;/span&gt;&lt;span class="nb"&gt;exit &lt;/span&gt;1
        &lt;span class="k"&gt;fi
    fi&lt;/span&gt;

    &lt;span class="c"&gt;# Download file&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$download_url&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;❌ Download failed&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;# Check downloaded file size&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;&lt;span class="nv"&gt;file_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;stat&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt;%z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;stat&lt;/span&gt; &lt;span class="nt"&gt;-c&lt;/span&gt;%s &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; 2&amp;gt;/dev/null&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Downloaded file size: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;file_size&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; bytes&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="c"&gt;# If file is too small, it might be an error message&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$file_size&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-lt&lt;/span&gt; 1000 &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;⚠️ Warning: Downloaded file is too small, possibly not a valid executable file&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;YELLOW&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;⚠️ File content:&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;❌ Download failed, please check version and operating system&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi

    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Setting executable permissions...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GREEN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;✅ Installation completed!&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Program downloaded to: &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CYAN&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;ℹ️ Starting program...&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

        &lt;span class="c"&gt;# Run program directly&lt;/span&gt;
        &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;binary_path&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;else
        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;RED&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;❌ Installation failed&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;NC&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Main program&lt;/span&gt;
main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    print_logo
    get_latest_version
    detect_os
    install_cursor_free_vip
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Run main program&lt;/span&gt;
main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the file by pressing &lt;code&gt;Ctrl + O&lt;/code&gt;, hit &lt;code&gt;Enter&lt;/code&gt;, then &lt;code&gt;Ctrl + X&lt;/code&gt; to exit &lt;code&gt;nano&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does this script do?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
This &lt;code&gt;install.sh&lt;/code&gt; script is a helper that automates downloading the latest version of a free Cursor binary from a GitHub repo (&lt;code&gt;yeongpin/cursor-free-vip&lt;/code&gt;). Here’s the breakdown:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Prints a cool logo&lt;/strong&gt;: Just for vibes, it displays a fancy ASCII art logo.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Finds your Downloads folder&lt;/strong&gt;: It figures out where your Downloads folder is on your Mac.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checks the latest version&lt;/strong&gt;: It hits up GitHub’s API to grab the latest release version of the Cursor binary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Detects your Mac’s architecture&lt;/strong&gt;: It checks if you’re on an Apple Silicon (arm64) or Intel Mac to download the right file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Downloads the binary&lt;/strong&gt;: It pulls the correct Cursor binary for your Mac from GitHub and saves it to your Downloads folder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Makes it executable&lt;/strong&gt;: It sets permissions so you can run the downloaded file.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runs the app&lt;/strong&gt;: It launches the freshly downloaded Cursor app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Is it safe?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Totally! The script only deletes Cursor’s local data (nothing system-critical), downloads a file from a public GitHub repo, and runs it. It doesn’t mess with your system files, install malware, or do anything shady. Just make sure you’re cool with downloading from the &lt;code&gt;yeongpin/cursor-free-vip&lt;/code&gt; repo—check it out on GitHub if you wanna be extra sure. The script also checks the file size to ensure it’s a legit executable, not some random error message.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 5: Run the Script
&lt;/h3&gt;

&lt;p&gt;Now, let’s execute the script. In Terminal, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;bash install.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll need to enter your Mac password again because &lt;code&gt;sudo&lt;/code&gt; is used to set executable permissions. The script will download the Cursor binary, make it runnable, and launch it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 6: Interact with the Script
&lt;/h3&gt;

&lt;p&gt;When the script runs, it might prompt you with a menu (depending on the binary). When prompted, &lt;strong&gt;press 8&lt;/strong&gt; and hit &lt;code&gt;Enter&lt;/code&gt;. This likely selects an option to set up a free version of Cursor. After that, when prompted again, &lt;strong&gt;press 0&lt;/strong&gt; to exit the script.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 7: Reopen Cursor
&lt;/h3&gt;

&lt;p&gt;Open the Cursor app again (it should be in your Downloads folder or wherever the script saved it). It’ll act like a fresh install, ready for a new trial.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 8: Get a Disposable Email
&lt;/h3&gt;

&lt;p&gt;Head over to &lt;a href="https://temp-mail.org/en/" rel="noopener noreferrer"&gt;temp-mail.org&lt;/a&gt; in your browser. This site gives you a temporary, disposable email address that self-destructs after a while—perfect for signing up without spamming your real inbox.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Click to generate a new email address (it’s instant, no registration needed).&lt;/li&gt;
&lt;li&gt;Copy the temporary email address.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 9: Create a New Cursor Account
&lt;/h3&gt;

&lt;p&gt;In the Cursor app, sign up for a new account using the temporary email from temp-mail.org. Follow the prompts to create the account, and log in with it. Boom, you’re back in with a fresh trial! 🎉&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 10: Enjoy Cursor for Free
&lt;/h3&gt;

&lt;p&gt;You’re all set! You can now use Cursor as if it’s a brand-new install. Note that some features, like &lt;strong&gt;Cloud Sonnet 4&lt;/strong&gt;, might be locked to pro users, but you’ll still get the core Cursor experience—AI code suggestions, sleek editor, all the good stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Use a Disposable Email?
&lt;/h2&gt;

&lt;p&gt;Using a temp email (like from temp-mail.org) is clutch because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No spam&lt;/strong&gt;: Your real email stays clean from promotional emails or potential data breaches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy&lt;/strong&gt;: You don’t have to share your personal email with every service.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy resets&lt;/strong&gt;: If you need to reset your trial again, just grab another temp email and repeat the process.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Temp-mail.org is super user-friendly, anonymous, and doesn’t require any signup. It’s like a burner phone for your email—use it, ditch it, no strings attached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips for Smooth Sailing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repeat as needed&lt;/strong&gt;: If your trial runs out again, just repeat the steps: clear the data, run the script, get a new temp email, and sign up again.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the GitHub repo&lt;/strong&gt;: The script pulls from &lt;code&gt;yeongpin/cursor-free-vip&lt;/code&gt;. If you’re curious, peek at the repo to see what’s up.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stay safe&lt;/strong&gt;: Only run scripts from sources you trust. This one’s straightforward, but always double-check GitHub repos for sketchy stuff.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backup your work&lt;/strong&gt;: Cursor might reset settings or local data, so save your projects elsewhere before running the script.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Is This Ethical?
&lt;/h2&gt;

&lt;p&gt;This method is about resetting your trial by clearing local data and using a new account with a disposable email. It’s a gray area—technically, you’re not breaking anything, but you’re extending the trial beyond what the devs might expect. If you love Cursor and can afford it, consider supporting the devs with a paid plan. For now, this is a chill way to keep coding without spending a dime. 😎&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Get
&lt;/h2&gt;

&lt;p&gt;With this setup, you’ll get Cursor’s core features—AI-powered code completion, error detection, and a slick VS Code-like interface. Some premium features (like advanced AI models) might be locked, but you’ll still have plenty to work with for coding, debugging, and building dope projects.&lt;/p&gt;




&lt;p&gt;That’s it, fam! You’re now ready to keep rocking Cursor for free on your Mac. Hit up the Terminal, run that script, grab a temp email, and code like a boss. If you run into any snags, lemme know, and I’ll help you sort it out. Happy coding! 🚀✨&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tutorial</category>
      <category>tooling</category>
      <category>linux</category>
    </item>
    <item>
      <title>How to host a website locally and let other users use it — super-elaborate</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Wed, 17 Sep 2025 19:44:25 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/how-to-host-a-website-locally-and-let-other-users-use-it-super-elaborate-43kk</link>
      <guid>https://forem.com/aadarsh-nagrath/how-to-host-a-website-locally-and-let-other-users-use-it-super-elaborate-43kk</guid>
      <description>&lt;p&gt;Below is a complete, practical guide that covers everything from “quick demo in 2 minutes” to “production-grade, secure, and resilient”. &lt;br&gt;
Read the whole thing for interview depth; use the quick sections when you need speed.&lt;/p&gt;


&lt;h2&gt;
  
  
  TL;DR (one-minute pitch)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Run your app and bind to &lt;code&gt;0.0.0.0&lt;/code&gt; so it’s reachable on the LAN.&lt;/li&gt;
&lt;li&gt;Open the port in your firewall and (optionally) reserve a static local IP.&lt;/li&gt;
&lt;li&gt;For LAN-only access: share &lt;code&gt;http://&amp;lt;local_ip&amp;gt;:&amp;lt;port&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For Internet access: either set up router port-forwarding + dynamic DNS / domain + TLS, &lt;strong&gt;or&lt;/strong&gt; use a tunnel service (ngrok / cloudflared) for ease.&lt;/li&gt;
&lt;li&gt;For production: put Nginx/Traefik as a reverse proxy, get Let’s Encrypt TLS, run the app as a systemd/docker service, enable firewall, monitoring, and fail2ban.&lt;/li&gt;
&lt;/ol&gt;


&lt;h1&gt;
  
  
  Full walkthrough
&lt;/h1&gt;
&lt;h3&gt;
  
  
  Assumptions
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;OS: Linux example (Ubuntu). I’ll also give Windows/macOS commands where relevant.&lt;/li&gt;
&lt;li&gt;App runs on port &lt;code&gt;3000&lt;/code&gt; (adjust if different).&lt;/li&gt;
&lt;li&gt;You control your home/office router (or you’ll use a tunnel).&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  1) Local server — make the app reachable on your machine and LAN
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Static files (quick)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Python 3 (static files)&lt;/span&gt;
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; http.server 3000  &lt;span class="c"&gt;# serves current dir&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Dynamic apps — examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Node / Express&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// server.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;static&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;public&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0.0.0.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Listening on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start: &lt;code&gt;node server.js&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flask&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# dev server (not for production)&lt;/span&gt;
&lt;span class="nv"&gt;FLASK_APP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;app.py flask run &lt;span class="nt"&gt;--host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0.0.0.0 &lt;span class="nt"&gt;--port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Django&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python manage.py runserver 0.0.0.0:8000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why &lt;code&gt;0.0.0.0&lt;/code&gt;?&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;localhost&lt;/code&gt;/&lt;code&gt;127.0.0.1&lt;/code&gt; only listens on loopback. &lt;code&gt;0.0.0.0&lt;/code&gt; listens on all interfaces so other LAN machines can reach you.&lt;/p&gt;


&lt;h2&gt;
  
  
  2) Find your local IP and test from another machine on the same network
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Find IP&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux/macOS: &lt;code&gt;ip addr show&lt;/code&gt; or &lt;code&gt;ifconfig&lt;/code&gt;
e.g. you'll see &lt;code&gt;192.168.1.5&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Windows: &lt;code&gt;ipconfig&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Test from another device on same Wi-Fi&lt;/strong&gt;&lt;br&gt;
Open &lt;code&gt;http://192.168.1.5:3000&lt;/code&gt; in their browser.&lt;/p&gt;

&lt;p&gt;If it works — great. If not, continue debugging below.&lt;/p&gt;


&lt;h2&gt;
  
  
  3) Open the firewall and check listening sockets
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Linux (ufw)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 3000/tcp
&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Iptables (example)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;iptables &lt;span class="nt"&gt;-I&lt;/span&gt; INPUT &lt;span class="nt"&gt;-p&lt;/span&gt; tcp &lt;span class="nt"&gt;--dport&lt;/span&gt; 3000 &lt;span class="nt"&gt;-j&lt;/span&gt; ACCEPT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Windows (PowerShell)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;New-NetFirewallRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-DisplayName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow3000"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Direction&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Inbound&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LocalPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;3000&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Protocol&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TCP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Allow&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Verify server is listening&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ss &lt;span class="nt"&gt;-tulpn&lt;/span&gt; | &lt;span class="nb"&gt;grep&lt;/span&gt; :3000
&lt;span class="c"&gt;# or&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;lsof &lt;span class="nt"&gt;-i&lt;/span&gt; :3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4) Make your local IP stable (DHCP reservation or static IP)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Easiest/robust: configure &lt;strong&gt;DHCP reservation&lt;/strong&gt; on your router (bind your machine MAC → fixed IP).&lt;/li&gt;
&lt;li&gt;Alternative: set a static IP on the OS; avoid conflicts by choosing outside DHCP range.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why? Router port forwards and DNS point to a local IP; if it changes, forwarding breaks.&lt;/p&gt;




&lt;h2&gt;
  
  
  5) Letting people on the &lt;strong&gt;Internet&lt;/strong&gt; access your site
&lt;/h2&gt;

&lt;p&gt;You have four common options. Pick by tradeoffs:&lt;/p&gt;

&lt;h3&gt;
  
  
  Option A — Router port forwarding + domain or dynamic DNS (more “own infra”)
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Steps&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;In router admin, forward TCP port &lt;code&gt;80&lt;/code&gt; (HTTP) and &lt;code&gt;443&lt;/code&gt; (HTTPS) to &lt;code&gt;192.168.1.5&lt;/code&gt; (your machine).&lt;/li&gt;
&lt;li&gt;Check your public IP: &lt;code&gt;curl ifconfig.me&lt;/code&gt; (from your machine).&lt;/li&gt;
&lt;li&gt;If you have a domain: create an &lt;strong&gt;A&lt;/strong&gt; record pointing to the public IP. If IP is dynamic, use a DDNS provider (DuckDNS, No-IP, DynDNS).&lt;/li&gt;
&lt;li&gt;Obtain TLS with Let’s Encrypt (certbot) — see section on SSL.&lt;/li&gt;
&lt;li&gt;Test from outside (mobile data or ask a friend).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; full control, no third-party tunnel.&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; ISP might block 80/443, NAT complexity, exposes home network — needs hardening.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; If your ISP blocks 80, forward a high port (e.g., 8080) externally and use a VPS reverse proxy or a tunnel for TLS.&lt;/p&gt;


&lt;h3&gt;
  
  
  Option B — Tunnel services (fast, safe for demos)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;ngrok&lt;/strong&gt;: &lt;code&gt;ngrok http 3000&lt;/code&gt; → gives &lt;code&gt;https://&amp;lt;random&amp;gt;.ngrok.io&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sign up for token, can get stable subdomain on paid plan.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;localtunnel&lt;/strong&gt;: &lt;code&gt;npx localtunnel --port 3000 --subdomain mydemo&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cloudflare Tunnel (cloudflared)&lt;/strong&gt;: persistent, integrates with your Cloudflare DNS and supports production use.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; no router changes, works behind CGNAT, quick, TLS handled.&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; external dependency; free plans may be limited.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example ngrok&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# install ngrok, then&lt;/span&gt;
ngrok authtoken &amp;lt;your-token&amp;gt;
ngrok http 3000
&lt;span class="c"&gt;# copy the https URL and share&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Option C — VPS reverse proxy + SSH reverse tunnel (robust, low-cost)
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Spin a cheap VPS (DigitalOcean, AWS Lightsail) with a public IP and domain.&lt;/li&gt;
&lt;li&gt;On the VPS run Nginx and point your domain to the VPS IP.&lt;/li&gt;
&lt;li&gt;From your local machine open an SSH reverse tunnel:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh &lt;span class="nt"&gt;-R&lt;/span&gt; 8080:localhost:3000 user@vps.example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then in the VPS Nginx config, reverse proxy &lt;code&gt;/&lt;/code&gt; to &lt;code&gt;http://127.0.0.1:8080&lt;/code&gt;. Use &lt;code&gt;autossh&lt;/code&gt; to keep tunnel persistent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pros:&lt;/strong&gt; You control the domain &amp;amp; TLS on VPS; only outbound SSH from home (safer).&lt;br&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; More setup, cost of VPS.&lt;/p&gt;


&lt;h3&gt;
  
  
  Option D — Host on a cloud provider (recommended for production)
&lt;/h3&gt;

&lt;p&gt;If the goal is stable public hosting, deploy to a cloud server or platform (VPS, Heroku, Vercel, Netlify, AWS/GCP/Azure) rather than exposing a home machine.&lt;/p&gt;


&lt;h2&gt;
  
  
  6) Domain names and TLS (Let’s Encrypt example)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Install certbot and nginx plugin (Ubuntu)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;nginx certbot python3-certbot-nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Nginx server block example&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kn"&gt;listen&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;server_name&lt;/span&gt; &lt;span class="s"&gt;example.com&lt;/span&gt; &lt;span class="s"&gt;www.example.com&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kn"&gt;location&lt;/span&gt; &lt;span class="n"&gt;/&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_pass&lt;/span&gt; &lt;span class="s"&gt;http://127.0.0.1:3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;Host&lt;/span&gt; &lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Real-IP&lt;/span&gt; &lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="kn"&gt;proxy_set_header&lt;/span&gt; &lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt; &lt;span class="nv"&gt;$proxy_add_x_forwarded_for&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;p&gt;&lt;strong&gt;Obtain certificate&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;certbot &lt;span class="nt"&gt;--nginx&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; example.com &lt;span class="nt"&gt;-d&lt;/span&gt; www.example.com
&lt;span class="c"&gt;# Certbot will configure nginx and set up automatic renew&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;If behind NAT / using tunnel:&lt;/strong&gt; terminate TLS at the tunnel (ngrok/cloudflare) or at VPS reverse proxy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cloudflare note:&lt;/strong&gt; If using Cloudflare proxy, set SSL/TLS to “Full (strict)” with origin certs for security.&lt;/p&gt;




&lt;h2&gt;
  
  
  7) Run your app as a service (reliability)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;systemd service for Node app&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="c"&gt;# /etc/systemd/system/myapp.service
&lt;/span&gt;&lt;span class="nn"&gt;[Unit]&lt;/span&gt;
&lt;span class="py"&gt;Description&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;My Node App&lt;/span&gt;
&lt;span class="py"&gt;After&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network.target&lt;/span&gt;

&lt;span class="nn"&gt;[Service]&lt;/span&gt;
&lt;span class="py"&gt;User&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;ubuntu&lt;/span&gt;
&lt;span class="py"&gt;WorkingDirectory&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/home/ubuntu/myapp&lt;/span&gt;
&lt;span class="py"&gt;ExecStart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/node server.js&lt;/span&gt;
&lt;span class="py"&gt;Restart&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;
&lt;span class="py"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;NODE_ENV=production PORT=3000&lt;/span&gt;

&lt;span class="nn"&gt;[Install]&lt;/span&gt;
&lt;span class="py"&gt;WantedBy&lt;/span&gt;&lt;span class="p"&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl daemon-reload
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; myapp
&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl status myapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Alternative:&lt;/strong&gt; Use &lt;code&gt;pm2&lt;/code&gt; for Node, or Docker + docker-compose. For containers, use restart policies.&lt;/p&gt;




&lt;h2&gt;
  
  
  8) Reverse proxy and load balancing (Nginx / Traefik)
&lt;/h2&gt;

&lt;p&gt;Use Nginx to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terminate TLS.&lt;/li&gt;
&lt;li&gt;Serve static assets directly.&lt;/li&gt;
&lt;li&gt;Proxy traffic to the app on &lt;code&gt;localhost&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add rate limiting, IP blocklists, gzip, caching.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Simple Nginx proxy (see above).&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you have multiple app instances, create an upstream block and load balance.&lt;/p&gt;




&lt;h2&gt;
  
  
  9) Docker approach (portable reproducible stack)
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile (example Node)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:20-alpine&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci &lt;span class="nt"&gt;--production&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;docker-compose.yml&lt;/strong&gt; (Nginx + app)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;always&lt;/span&gt;
  &lt;span class="na"&gt;nginx&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx:stable&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;80:80"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;443:443"&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./nginx.conf:/etc/nginx/conf.d/default.conf:ro&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;docker-compose up -d&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  10) Security checklist (MUST for Internet exposure)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use HTTPS only (redirect HTTP → HTTPS).&lt;/li&gt;
&lt;li&gt;Don’t expose databases or admin ports to the public network.&lt;/li&gt;
&lt;li&gt;Use firewall: only open necessary ports (80/443, ssh limited to known IPs).&lt;/li&gt;
&lt;li&gt;Use fail2ban to ban repeated failed login attempts.&lt;/li&gt;
&lt;li&gt;Keep OS and dependencies updated.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use a reverse proxy to enforce security headers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Strict-Transport-Security&lt;/code&gt;, &lt;code&gt;X-Frame-Options&lt;/code&gt;, &lt;code&gt;X-Content-Type-Options&lt;/code&gt;, CSP.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Use environment variables or secret manager for credentials — don’t commit &lt;code&gt;.env&lt;/code&gt; to VCS.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;For staging/demos: put a simple auth gate (basic auth) or IP allowlist.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;For team-only access: prefer VPN (WireGuard) or private tunnel.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  11) Monitoring and logging
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Logs: Nginx access/error logs, app logs (&lt;code&gt;journalctl -u myapp&lt;/code&gt; or Docker logs).&lt;/li&gt;
&lt;li&gt;Health checks: expose &lt;code&gt;/healthz&lt;/code&gt; which returns 200 for monitoring.&lt;/li&gt;
&lt;li&gt;Uptime monitoring: UptimeRobot / Pingdom or custom Prometheus + Alertmanager.&lt;/li&gt;
&lt;li&gt;Performance: enable gzip, cache static assets, use CDN for large public assets.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  12) Troubleshooting checklist (if not reachable)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Is the app running? &lt;code&gt;systemctl status&lt;/code&gt; / &lt;code&gt;ps aux&lt;/code&gt; / &lt;code&gt;docker ps&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Is it listening on correct interface? &lt;code&gt;ss -tulpn | grep 3000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Firewall open? &lt;code&gt;sudo ufw status&lt;/code&gt; or Windows firewall rules.&lt;/li&gt;
&lt;li&gt;From local machine: &lt;code&gt;curl http://127.0.0.1:3000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;From another LAN machine: &lt;code&gt;curl http://192.168.1.5:3000&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If public: is port forwarding set up? Check router settings.&lt;/li&gt;
&lt;li&gt;Is ISP blocking ports? Test with a remote port scan or try an alternate external port.&lt;/li&gt;
&lt;li&gt;DNS propagation issues: &lt;code&gt;dig +short example.com&lt;/code&gt; and compare to expected IP.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;traceroute&lt;/code&gt; and &lt;code&gt;tcpdump&lt;/code&gt; to debug network hops and packets.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  13) Example: full step-by-step (Ubuntu) — Node app, public access via ngrok (quick, safe demo)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Clone and start app:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://.../myapp.git
&lt;span class="nb"&gt;cd &lt;/span&gt;myapp
npm &lt;span class="nb"&gt;install
&lt;/span&gt;node server.js &lt;span class="nt"&gt;--port&lt;/span&gt; 3000 &lt;span class="nt"&gt;--host&lt;/span&gt; 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Allow firewall:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;ufw allow 3000/tcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Install ngrok, authenticate, and start tunnel:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ngrok authtoken &amp;lt;token&amp;gt;
ngrok http 3000
&lt;span class="c"&gt;# ngrok prints a public https://... url — share that&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;(Optional) Make Node run as a service with systemd (see earlier).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why this flow?&lt;/strong&gt; Fast, secure for demos, no router fiddling or DNS changes required.&lt;/p&gt;




&lt;h2&gt;
  
  
  14) Example: production checklist (if you mean “others” = many users)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use a cloud VM or managed platform (AWS/GCP/DigitalOcean). Don’t host high-traffic production on a home connection.&lt;/li&gt;
&lt;li&gt;Use a reverse proxy with TLS (Nginx/Traefik), autoscaling/load balancing, CDN for static content.&lt;/li&gt;
&lt;li&gt;Use managed databases and secrets. Regular backups, monitoring, and incident response plan.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  15) Interview talking points — how to present this answer (concise)
&lt;/h2&gt;

&lt;p&gt;If asked in an interview, structure your answer:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Goal &amp;amp; constraints&lt;/strong&gt; (LAN vs Internet, security, budget).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quick demo solution&lt;/strong&gt;: serve on &lt;code&gt;0.0.0.0&lt;/code&gt; and use ngrok for external demos.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production solution&lt;/strong&gt;: deploy to a cloud VM / container platform, front with Nginx/Traefik, secure with Let’s Encrypt, use monitoring &amp;amp; CI/CD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Risks &amp;amp; mitigations&lt;/strong&gt;: ISP blocks, security exposure, scaling, backups.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why decisions&lt;/strong&gt;: choose tunnels for quick demos, VPS/prod for stability and long-term control.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  16) Common gotchas to mention (shows depth)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CGNAT:&lt;/strong&gt; Some home ISPs use carrier NAT — port forwarding won’t work. Use a tunnel or VPS reverse proxy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ISP blocks:&lt;/strong&gt; Residential ISPs sometimes block 80/443. Use alternative ports or VPS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Router UPnP security risk:&lt;/strong&gt; Avoid enabling UPnP for automatic port opening on untrusted networks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Certificates &amp;amp; local hostnames:&lt;/strong&gt; Let’s Encrypt requires a publicly resolvable domain. For internal names use self-signed certs or a private CA.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy:&lt;/strong&gt; Be mindful of exposing development credentials or debug endpoints.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  17) Example artifacts to prepare for interview (optional)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Small diagram: local machine → router (NAT) → Internet. Or local machine → ngrok → public URL.&lt;/li&gt;
&lt;li&gt;A sample systemd service file, nginx block, and certbot command snippet ready to paste.&lt;/li&gt;
&lt;li&gt;A short script to create a DDNS update (or &lt;code&gt;ddclient&lt;/code&gt; configuration).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final summary (what I would do)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For a quick demo: bind to &lt;code&gt;0.0.0.0&lt;/code&gt;, open firewall, run &lt;code&gt;ngrok http &amp;lt;port&amp;gt;&lt;/code&gt;. Share ngrok URL.&lt;/li&gt;
&lt;li&gt;For short-term public hosting: use a cheap VPS + reverse proxy + Let’s Encrypt + systemd/docker + monitoring.&lt;/li&gt;
&lt;li&gt;For production: use cloud hosting/managed services, TLS, CDN, autoscaling, proper secrets and monitoring.&lt;/li&gt;
&lt;li&gt;Always secure: firewall, do not expose internal services, keep software current.&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>devops</category>
      <category>networking</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Setting Up HTTPS on Kubernetes with cert-manager and Let's Encrypt</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Wed, 17 Sep 2025 08:28:01 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/setting-up-https-on-kubernetes-with-cert-manager-and-lets-encrypt-45e6</link>
      <guid>https://forem.com/aadarsh-nagrath/setting-up-https-on-kubernetes-with-cert-manager-and-lets-encrypt-45e6</guid>
      <description>&lt;p&gt;In today's digital landscape, securing your web applications with HTTPS is non-negotiable. It ensures data privacy, builds user trust, and aligns with modern security standards. If you're running a Kubernetes cluster and want to enable HTTPS for your ingress using Let's Encrypt SSL certificates, cert-manager is your go-to tool for automating certificate management.&lt;/p&gt;

&lt;p&gt;This blog post provides a comprehensive, step-by-step guide to configuring HTTPS on a Kubernetes cluster with cert-manager and Let's Encrypt. We'll walk through the entire process, from verifying your setup to troubleshooting common issues, ensuring your domain (e.g., platform-dev.example.ai) is secured with a valid SSL certificate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview: What We're Building
&lt;/h2&gt;

&lt;p&gt;This guide outlines how to set up HTTPS for a Kubernetes ingress using cert-manager, a powerful Kubernetes add-on that automates the issuance and renewal of SSL certificates from Let's Encrypt. By the end of this tutorial, you'll have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Kubernetes cluster with an nginx ingress controller.&lt;/li&gt;
&lt;li&gt;A domain (e.g., platform-dev.example.ai) mapped to your cluster's external IP (e.g., 34.75.54.5).&lt;/li&gt;
&lt;li&gt;An ingress configured for HTTPS with automatic SSL certificate management.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Initial Setup Status
&lt;/h3&gt;

&lt;p&gt;Before diving in, let's clarify the starting point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cluster&lt;/strong&gt;: A Kubernetes cluster with an nginx ingress controller already deployed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domain&lt;/strong&gt;: A domain (e.g., platform-dev.example.ai) mapped to the external IP 34.75.54.5.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ingress&lt;/strong&gt;: An existing ingress with a TLS section, but the certificate isn't functioning correctly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Goal&lt;/strong&gt;: Enable HTTPS with automated SSL certificate issuance and renewal using cert-manager and Let's Encrypt.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;To follow this guide, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Kubernetes cluster with an nginx ingress controller installed.&lt;/li&gt;
&lt;li&gt;A registered domain name pointing to your cluster's external IP.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kubectl&lt;/code&gt; configured with access to your cluster.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s get started with the setup process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Verify cert-manager Installation
&lt;/h2&gt;

&lt;p&gt;The first step is to confirm whether cert-manager is installed in your Kubernetes cluster. cert-manager is a Kubernetes-native tool that simplifies certificate management by automating the process of obtaining, renewing, and managing SSL certificates.&lt;/p&gt;

&lt;p&gt;Run the following command to check for existing cert-manager pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; cert-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If cert-manager is installed, you should see three running pods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;cert-manager-xxxxx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cert-manager-cainjector-xxxxx&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cert-manager-webhook-xxxxx&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If these pods are not present, you need to install cert-manager. Use the following command to deploy the latest stable version (v1.13.0 at the time of writing):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; https://github.com/cert-manager/cert-manager/releases/download/v1.13.0/cert-manager.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After applying the manifest, re-run the &lt;code&gt;kubectl get pods -n cert-manager&lt;/code&gt; command to verify that the three cert-manager pods are running. This ensures cert-manager is ready to manage certificates for your cluster.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Create a ClusterIssuer for Let's Encrypt
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;ClusterIssuer&lt;/code&gt; is a Kubernetes resource that defines how cert-manager should obtain certificates. In this case, we'll configure a &lt;code&gt;ClusterIssuer&lt;/code&gt; to communicate with Let's Encrypt's production ACME server for issuing valid SSL certificates.&lt;/p&gt;

&lt;p&gt;First, check if a &lt;code&gt;ClusterIssuer&lt;/code&gt; named &lt;code&gt;letsencrypt-prod&lt;/code&gt; already exists:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get clusterissuer letsencrypt-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If it doesn't exist or isn't configured correctly, create one with the correct ACME server URL. &lt;strong&gt;Important&lt;/strong&gt;: Many tutorials mistakenly use an incorrect ACME server URL. The correct URL is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Correct&lt;/strong&gt;: &lt;code&gt;https://acme-v02.api.letsencrypt.org/directory&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Incorrect&lt;/strong&gt;: &lt;code&gt;https://acme-v2.api.letsencrypt.org/directory&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create the &lt;code&gt;ClusterIssuer&lt;/code&gt;, apply the following configuration, replacing &lt;code&gt;your-email@company.com&lt;/code&gt; with your actual email address (used for Let's Encrypt notifications):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOF&lt;/span&gt;&lt;span class="sh"&gt; | kubectl apply -f -
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: your-email@company.com
    privateKeySecretRef:
      name: letsencrypt-prod
    solvers:
    - http01:
        ingress:
          class: nginx
&lt;/span&gt;&lt;span class="no"&gt;EOF
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After applying, verify that the &lt;code&gt;ClusterIssuer&lt;/code&gt; is ready:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get clusterissuer letsencrypt-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output should show &lt;code&gt;READY: True&lt;/code&gt;. If it’s not ready, we'll cover troubleshooting in Step 5.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Configure the Ingress for HTTPS
&lt;/h2&gt;

&lt;p&gt;Your Kubernetes ingress resource needs specific annotations and configurations to work with cert-manager and enable HTTPS. Below is the complete ingress configuration for your domain (e.g., platform-dev.example.ai), which routes traffic to two services: &lt;code&gt;platform-ui&lt;/code&gt; and &lt;code&gt;platform-api&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Apply the following ingress configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;networking.k8s.io/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Ingress&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;annotations&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;cert-manager.io/cluster-issuer&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;letsencrypt-prod&lt;/span&gt;
    &lt;span class="na"&gt;nginx.ingress.kubernetes.io/enable-rewrite-log&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
    &lt;span class="na"&gt;nginx.ingress.kubernetes.io/use-regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example-ingress&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform-namespace&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ingressClassName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;nginx&lt;/span&gt;
  &lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform-dev.example.ai&lt;/span&gt;
    &lt;span class="na"&gt;http&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform-ui&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
        &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;backend&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;platform-api&lt;/span&gt;
            &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;80&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/api&lt;/span&gt;
        &lt;span class="na"&gt;pathType&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Prefix&lt;/span&gt;
  &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;hosts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;platform-dev.example.ai&lt;/span&gt;
    &lt;span class="na"&gt;secretName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;example-tls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Points in the Configuration:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Annotation&lt;/strong&gt;: &lt;code&gt;cert-manager.io/cluster-issuer: letsencrypt-prod&lt;/code&gt; tells cert-manager to use the &lt;code&gt;letsencrypt-prod&lt;/code&gt; ClusterIssuer to issue a certificate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TLS Section&lt;/strong&gt;: Specifies the domain (&lt;code&gt;platform-dev.example.ai&lt;/code&gt;) and the secret (&lt;code&gt;example-tls&lt;/code&gt;) where cert-manager will store the SSL certificate.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paths&lt;/strong&gt;: Routes &lt;code&gt;/&lt;/code&gt; to the &lt;code&gt;platform-ui&lt;/code&gt; service and &lt;code&gt;/api&lt;/code&gt; to the &lt;code&gt;platform-api&lt;/code&gt; service, both on port 80.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Namespace&lt;/strong&gt;: Ensure the ingress is created in the correct namespace (&lt;code&gt;platform-namespace&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This configuration triggers cert-manager to request a certificate from Let's Encrypt and store it in the &lt;code&gt;example-tls&lt;/code&gt; secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Verify Certificate Creation
&lt;/h2&gt;

&lt;p&gt;Once the ingress is configured, cert-manager will automatically request a certificate from Let's Encrypt. To monitor the certificate creation process, use the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check certificate status&lt;/span&gt;
kubectl get certificate &lt;span class="nt"&gt;-n&lt;/span&gt; platform-namespace

&lt;span class="c"&gt;# Get detailed certificate information&lt;/span&gt;
kubectl describe certificate example-tls &lt;span class="nt"&gt;-n&lt;/span&gt; platform-namespace

&lt;span class="c"&gt;# Check certificate requests (for troubleshooting)&lt;/span&gt;
kubectl get certificaterequest &lt;span class="nt"&gt;-n&lt;/span&gt; platform-namespace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a successful certificate, the output of &lt;code&gt;kubectl get certificate&lt;/code&gt; should look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME         READY   SECRET       AGE
example-tls  True    example-tls  5m
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;READY: True&lt;/code&gt; status indicates that the certificate was issued successfully and is stored in the &lt;code&gt;example-tls&lt;/code&gt; secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Troubleshooting Common Issues
&lt;/h2&gt;

&lt;p&gt;If something goes wrong, here are common issues and their solutions:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. ClusterIssuer Not Ready
&lt;/h3&gt;

&lt;p&gt;If the &lt;code&gt;ClusterIssuer&lt;/code&gt; status is not &lt;code&gt;READY: True&lt;/code&gt;, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe clusterissuer letsencrypt-prod
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the events or status for errors. The most common issue is an incorrect ACME server URL (e.g., using &lt;code&gt;acme-v2&lt;/code&gt; instead of &lt;code&gt;acme-v02&lt;/code&gt;). Ensure the URL is &lt;code&gt;https://acme-v02.api.letsencrypt.org/directory&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Certificate Stuck in Pending
&lt;/h3&gt;

&lt;p&gt;If the certificate status shows as pending, investigate with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl describe certificate example-tls &lt;span class="nt"&gt;-n&lt;/span&gt; platform-namespace
kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; cert-manager deployment/cert-manager
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Look for errors related to the ACME challenge process, such as HTTP-01 challenge failures.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. DNS Issues
&lt;/h3&gt;

&lt;p&gt;Ensure your domain resolves correctly to your cluster's external IP. Test DNS resolution from within the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run test-dns &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;busybox &lt;span class="nt"&gt;--&lt;/span&gt; nslookup platform-dev.example.ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify connectivity to the Let's Encrypt ACME server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl run test-connectivity &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;--restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;Never &lt;span class="nt"&gt;--image&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;curlimages/curl &lt;span class="nt"&gt;--&lt;/span&gt; curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://acme-v02.api.letsencrypt.org/directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 6: Verify HTTPS is Working
&lt;/h2&gt;

&lt;p&gt;Once the certificate is issued, test your HTTPS endpoint to confirm it’s working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Test HTTPS response&lt;/span&gt;
curl &lt;span class="nt"&gt;-I&lt;/span&gt; https://platform-dev.example.ai

&lt;span class="c"&gt;# Check certificate details&lt;/span&gt;
openssl s_client &lt;span class="nt"&gt;-connect&lt;/span&gt; platform-dev.example.ai:443 &lt;span class="nt"&gt;-servername&lt;/span&gt; platform-dev.example.ai
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Success Indicators
&lt;/h3&gt;

&lt;p&gt;Your setup is successful if:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Certificate status is &lt;code&gt;READY: True&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;✅ ClusterIssuer status is &lt;code&gt;READY: True&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;✅ Ingress shows both ports 80 and 443.&lt;/li&gt;
&lt;li&gt;✅ The &lt;code&gt;example-tls&lt;/code&gt; secret exists with certificate data.&lt;/li&gt;
&lt;li&gt;✅ The site is accessible via HTTPS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Certificate Lifecycle
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Validity&lt;/strong&gt;: Let's Encrypt certificates are valid for 90 days.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auto-Renewal&lt;/strong&gt;: cert-manager automatically renews certificates 30 days before expiration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: Check the certificate’s renewal time in its status with &lt;code&gt;kubectl describe certificate example-tls -n platform-namespace&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Security Best Practices
&lt;/h2&gt;

&lt;p&gt;To ensure a secure and reliable setup:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Email Configuration&lt;/strong&gt;: Use a monitored email address for Let's Encrypt notifications to stay informed about certificate issues or renewals.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Management&lt;/strong&gt;: cert-manager automatically manages TLS secrets, so avoid manual modifications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HTTP to HTTPS Redirect&lt;/strong&gt;: Add the following annotation to your ingress to enforce HTTPS:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;nginx.ingress.kubernetes.io/ssl-redirect&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Configuration Summary
&lt;/h2&gt;

&lt;p&gt;For a successful HTTPS setup, ensure:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;cert-manager is installed and running.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ClusterIssuer&lt;/code&gt; uses the correct ACME server URL.&lt;/li&gt;
&lt;li&gt;The ingress includes the cert-manager annotation and TLS section.&lt;/li&gt;
&lt;li&gt;DNS is properly configured to point to your cluster’s external IP.&lt;/li&gt;
&lt;li&gt;Domain validation completes successfully.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Troubleshooting Commands Reference
&lt;/h2&gt;

&lt;p&gt;For quick diagnostics, use these commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Check cert-manager components&lt;/span&gt;
kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; cert-manager
kubectl logs &lt;span class="nt"&gt;-n&lt;/span&gt; cert-manager deployment/cert-manager

&lt;span class="c"&gt;# Check certificates&lt;/span&gt;
kubectl get certificate &lt;span class="nt"&gt;-A&lt;/span&gt;
kubectl describe certificate example-tls &lt;span class="nt"&gt;-n&lt;/span&gt; platform-namespace

&lt;span class="c"&gt;# Check ClusterIssuer&lt;/span&gt;
kubectl get clusterissuer
kubectl describe clusterissuer letsencrypt-prod

&lt;span class="c"&gt;# Check ingress&lt;/span&gt;
kubectl get ingress &lt;span class="nt"&gt;-A&lt;/span&gt;
kubectl describe ingress example-ingress &lt;span class="nt"&gt;-n&lt;/span&gt; platform-namespace

&lt;span class="c"&gt;# Check secrets&lt;/span&gt;
kubectl get secret example-tls &lt;span class="nt"&gt;-n&lt;/span&gt; platform-namespace &lt;span class="nt"&gt;-o&lt;/span&gt; yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By following this guide, you’ve successfully configured HTTPS for your Kubernetes ingress using cert-manager and Let's Encrypt.&lt;/p&gt;

&lt;p&gt;Your domain (e.g., platform-dev.example.ai) is now secured with an automatically managed SSL certificate, ensuring secure communication for your users. With cert-manager handling renewals, you can focus on building your application while maintaining robust security.&lt;/p&gt;

&lt;p&gt;If you encounter any issues, refer to the troubleshooting commands or reach out to the Kubernetes or cert-manager community for support. Happy securing!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How Big Titans Swipe Through Billions of usernames when you press Submit</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Sat, 13 Sep 2025 12:03:20 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/how-big-titans-swipe-through-billions-of-usernames-when-you-press-submit-3c53</link>
      <guid>https://forem.com/aadarsh-nagrath/how-big-titans-swipe-through-billions-of-usernames-when-you-press-submit-3c53</guid>
      <description>&lt;p&gt;Hey there, fellow tech wanderer! &lt;/p&gt;

&lt;p&gt;Picture this: You're hyped about a new app, fingers flying across the keyboard as you type in your dream username—"PixelPirate42." Hit submit... and bam! "Username already taken." It's that tiny gut-punch moment that happens to all of us. &lt;/p&gt;

&lt;p&gt;But here's the wild part: Behind that snappy rejection is a high-stakes engineering ballet involving data structures smarter than a chess grandmaster, caches that remember everything, and databases that span the globe. We're talking systems that handle &lt;em&gt;billions&lt;/em&gt; of users without flinching—think Google, Amazon, Meta, and their ilk.&lt;/p&gt;

&lt;p&gt;In this blog, I'll unpack the wizardry they use to make username checks lightning-fast. We'll geek out over Redis hashmaps, Tries for that autocomplete magic, B+ trees for sorted sleuthing, and Bloom filters for probabilistic punches. Plus, I'll throw in real-world examples, a handy comparison table, and even sketch out how it all orchestrates like a symphony.&lt;/p&gt;

&lt;h2&gt;
  
  
  First Stop: The Speed Demon – Redis Hashmaps
&lt;/h2&gt;

&lt;p&gt;Okay, let's start simple. When you're not dealing with planet-scale users, a quick database peek works fine. But slap billions into the mix? That query turns into a traffic jam on the info superhighway—latency spikes, servers sweat, and your app feels like it's on dial-up.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Redis hashmaps&lt;/strong&gt;, the unsung heroes of caching layers. Redis isn't just a database; it's an in-memory powerhouse that stores key-value pairs like a digital Rolodex on steroids. For usernames, think of it this way: The key is a bucket (say, "usernames"), and inside that bucket? A hashmap where each field is a username, and the value is something lightweight—like a user ID or just a "taken" flag.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example Time:&lt;/strong&gt; Say "PixelPirate42" gets queried. The system pings Redis: "Hey, is this field in the hashmap?" Boom—cache hit! Response in microseconds, no database drama. If it's a new one, it's a miss, and only &lt;em&gt;then&lt;/em&gt; do you hit the slower backend.&lt;/p&gt;

&lt;p&gt;But memory's not infinite, right? You can't hoard every username forever in one Redis instance. That's why these bad boys shine for hot data—recently checked or popular usernames. &lt;/p&gt;

&lt;p&gt;In the wild, Instagram or Twitter (er, X) might use this to slash 90% of database touches.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwcg0gcjxm7p64p720tc7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwcg0gcjxm7p64p720tc7.png" alt="." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Level Up: Tries – The Prefix Party Planners
&lt;/h2&gt;

&lt;p&gt;What if "PixelPirate42" is taken, but you want suggestions? Like, "PixelPirate43" or "PixelNinja42"? A plain hashmap says "yes/no" and ghosts you. Time for &lt;strong&gt;Tries (or prefix trees)&lt;/strong&gt;—tree-like structures that dissect strings character by character, turning lookups into a choose-your-own-adventure game.&lt;/p&gt;

&lt;p&gt;Here's the magic: Instead of flat storage, a Trie builds branches for shared prefixes. Root node for the first letter, kids for the second, and so on. Lookup time? O(M), where M is your string's length (say, 15 chars). Doesn't care if you've got a billion entries—it's all about the path, not the forest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real-World Example:&lt;/strong&gt; Imagine usernames "bite_monkey," "biteme_io," and "biting_wit." The Trie shares a "b-i-t-e-" trunk, then splits: "-m-o-n-k-e-y" vs. "-m-e-&lt;em&gt;-i-o." Query "bite&lt;/em&gt;"? It traverses to that node in seconds and suggests completions. Autocomplete gold! Meta uses Trie-like structures for Facebook's handle suggestions, saving users from rage-quitting signups.&lt;/p&gt;

&lt;p&gt;Trade-off? Memory muncher if prefixes don't overlap much (e.g., all unique snowflakes). Fix: Compressed Tries (like Radix Tries) squash single-child paths, or limit to "hot" usernames. &lt;/p&gt;

&lt;p&gt;Pro tip: Netflix swears by them for title searches too.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmiclzgs28x1dmu7n0ha4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmiclzgs28x1dmu7n0ha4.png" alt="." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Sorted Sleuth: B+ Trees for Ordered Ops
&lt;/h2&gt;

&lt;p&gt;Tries are prefix pros, but what about full sorted searches or "find the next available after PixelPirate"? Hashmaps flop here—they're unordered chaos. Cue &lt;strong&gt;B+ trees&lt;/strong&gt; (and their B-tree cousins), the backbone of database indexes everywhere.&lt;/p&gt;

&lt;p&gt;These balanced beasts keep keys sorted in leaf nodes, with internal nodes as signposts. High fan-out (hundreds of kids per node) means shallow trees—even a billion usernames might need just 3-4 hops (O(log N) time, baby!).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example in Action:&lt;/strong&gt; In a relational DB like MySQL (or NoSQL like MongoDB), usernames are indexed in a B+ tree. Query "PixelPirate42"? Traverse sorted leaves—maybe 30 comparisons max for billions of entries. Want the next free one? Range scan from there: "PixelPirate43... available!"&lt;/p&gt;

&lt;p&gt;Google Cloud Spanner distributes these across machines, blending sorted magic with horizontal scale for millions of QPS. FoundationDB does the same. &lt;/p&gt;

&lt;p&gt;Downside? Updates in distributed setups get fiddly, but hey, trade-offs build character.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09pr04inzc3w437znj4n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F09pr04inzc3w437znj4n.png" alt="." width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Probabilistic Powerhouse: Bloom Filters – The Memory-Saving Gatekeepers
&lt;/h2&gt;

&lt;p&gt;We've got speed, prefixes, and sorting. Now, for sheer efficiency? &lt;strong&gt;Bloom filters&lt;/strong&gt;—probabilistic rockstars that scream "definitely not there!" without storing squat.&lt;/p&gt;

&lt;p&gt;It's a bit array + k hash functions. Add a username? Hash it k ways, flip those bits to 1. Check? Hash again—if &lt;em&gt;any&lt;/em&gt; bit's 0, it's absent (no false negatives!). All 1s? &lt;em&gt;Maybe&lt;/em&gt; there—double-check elsewhere.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Crunch the Numbers Example:&lt;/strong&gt; For 1B usernames at 1% false positives, ~1.2 GB memory. Vs. storing full strings? A fraction! Cassandra slaps these on SSTables to skip disk reads. Amazon might run a global one across shards—most "nope" queries die here, slashing DB load by 80-90%.&lt;/p&gt;

&lt;p&gt;False positives? Rare enough to shrug off. If it says "maybe," hit the cache. Genius for "is this taken?" without the bloat.&lt;/p&gt;

&lt;h2&gt;
  
  
  Showdown: Data Structures Face-Off
&lt;/h2&gt;

&lt;p&gt;To glue it all together, here's a quick comparison table. (Because who doesn't love a good showdown?)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data Structure&lt;/th&gt;
&lt;th&gt;Lookup Time&lt;/th&gt;
&lt;th&gt;Memory Usage&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;th&gt;Drawbacks&lt;/th&gt;
&lt;th&gt;Real-World User&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redis Hashmap&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;O(1)&lt;/td&gt;
&lt;td&gt;High (full keys)&lt;/td&gt;
&lt;td&gt;Exact matches, hot data&lt;/td&gt;
&lt;td&gt;Memory limits, no prefixes/ranges&lt;/td&gt;
&lt;td&gt;Instagram caches for recent checks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Trie (Prefix Tree)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;O(M)&lt;/td&gt;
&lt;td&gt;Medium-High (shared paths)&lt;/td&gt;
&lt;td&gt;Prefix searches, autocomplete&lt;/td&gt;
&lt;td&gt;Bloats on unique strings&lt;/td&gt;
&lt;td&gt;Facebook handle suggestions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;B+ Tree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;O(log N)&lt;/td&gt;
&lt;td&gt;Medium (sorted nodes)&lt;/td&gt;
&lt;td&gt;Sorted lookups, ranges&lt;/td&gt;
&lt;td&gt;Update complexity in distrib. setups&lt;/td&gt;
&lt;td&gt;Google Spanner for ordered scans&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Bloom Filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;O(k) (hashes)&lt;/td&gt;
&lt;td&gt;Low (bits only)&lt;/td&gt;
&lt;td&gt;Probabilistic "not present"&lt;/td&gt;
&lt;td&gt;False positives, no retrieval&lt;/td&gt;
&lt;td&gt;Cassandra to filter disk I/O&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;N = total entries, M = string length, k = hashes.&lt;/p&gt;

&lt;h2&gt;
  
  
  How It All Harmonizes in the Wild
&lt;/h2&gt;

&lt;p&gt;Solo acts are cool, but big tech? They layer like a gourmet lasagna. Let's trace "PixelPirate42" through the gauntlet:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Load Balancer Warm-Up:&lt;/strong&gt; Global (Route 53 DNS) routes you to the nearest data center (EU for you Europeans). Local (Nginx/ELB) fans traffic to backend servers. No bottlenecks—traffic flows like a well-oiled highway.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bloom Filter Bouncer:&lt;/strong&gt; App server checks its in-memory Bloom (synced from DB periodically). "Definitely not?" Respond "available!" instantly. Saves the day 70% of the time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cache Dash:&lt;/strong&gt; Miss? Ping Redis/Memcached. Hit? Microsecond win. (Pro: LRU eviction keeps it fresh.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DB Deep Dive:&lt;/strong&gt; Still no? Hit the distributed beast—Cassandra (Instagram's pick) or DynamoDB (Amazon's). Consistent hashing shards data across nodes; B+ trees or SSTables nail the exact check.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Response Relay:&lt;/strong&gt; Truth bubbles back through balancers. Total time? Under 100ms, even at planetary scale.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Meta mixes Tries for suggestions post-check; Google Spanner adds ACID guarantees. It's not one tool—it's a ecosystem flexing computer science muscle.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Beauty of Invisible Speed
&lt;/h2&gt;

&lt;p&gt;Next time that "taken" message flashes, tip your hat to the invisible orchestra—Bloom's quick jabs, Redis's recall, Tries' foresight, B+ trees' precision. &lt;/p&gt;

&lt;p&gt;It's engineering poetry: Fast, scalable, and oh-so-satisfying.&lt;/p&gt;

&lt;p&gt;Loved this? Drop a comment—what system design puzzle should I tackle next? AI ethics? Sharding secrets?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(P.S. All examples inspired by real tech stacks; no actual heists were committed in writing this.)&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>The Deep Dive: Why and How Projects Use Multiple Programming Languages</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Thu, 07 Aug 2025 18:49:38 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/the-deep-dive-why-and-how-projects-use-multiple-programming-languages-ej8</link>
      <guid>https://forem.com/aadarsh-nagrath/the-deep-dive-why-and-how-projects-use-multiple-programming-languages-ej8</guid>
      <description>&lt;p&gt;Programming languages are like specialized tools in a craftsman’s workshop—each designed for specific tasks. Some excel at rapid development and high-level abstractions (Python, JavaScript), while others provide fine-grained control over hardware and memory (C, Rust, Assembly). But why do some projects combine multiple languages? How do they work together under the hood?  &lt;/p&gt;

&lt;p&gt;This blog will explore:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The compilation pipeline&lt;/strong&gt; – How source code becomes executable binaries.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linking (static vs. dynamic)&lt;/strong&gt; – The glue that binds different languages.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-world examples&lt;/strong&gt; – How projects like Linux, FFmpeg, and OpenSSL mix languages.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ABI (Application Binary Interface)&lt;/strong&gt; – Why calling conventions matter.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practical use cases&lt;/strong&gt; – When and why you should mix languages.
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;1. The Compilation Pipeline: More Than Just "Code → Binary"&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When you compile a program, the process is far more complex than just converting source code into an executable. Modern compilers follow a &lt;strong&gt;multi-stage pipeline&lt;/strong&gt;, and understanding this is key to mixing languages.  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;The Four Key Phases (Using GCC as an Example)&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;1. Preprocessing&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Removes comments.
&lt;/li&gt;
&lt;li&gt;Expands macros (&lt;code&gt;#define&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;Handles &lt;code&gt;#include&lt;/code&gt; directives (pasting header files into the source).
&lt;/li&gt;
&lt;li&gt;Output: &lt;strong&gt;Preprocessed C code&lt;/strong&gt; (still human-readable).
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;2. Compilation (to Assembly)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Translates high-level code (C, C++, Rust) into &lt;strong&gt;assembly language&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Myth Busted:&lt;/strong&gt; Compilers don’t always go straight to machine code—many use intermediate representations (IR) like assembly.
&lt;/li&gt;
&lt;li&gt;Output: &lt;strong&gt;Assembly file&lt;/strong&gt; (&lt;code&gt;.s&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;3. Assembly (to Machine Code)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;strong&gt;assembler&lt;/strong&gt; converts assembly into &lt;strong&gt;machine code&lt;/strong&gt; (binary).
&lt;/li&gt;
&lt;li&gt;Output: &lt;strong&gt;Object file&lt;/strong&gt; (&lt;code&gt;.o&lt;/code&gt; or &lt;code&gt;.obj&lt;/code&gt;).
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;4. Linking (Combining Object Files)&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Merges multiple object files (your code + libraries).
&lt;/li&gt;
&lt;li&gt;Resolves function calls between them.
&lt;/li&gt;
&lt;li&gt;Output: &lt;strong&gt;Final executable&lt;/strong&gt; (&lt;code&gt;.exe&lt;/code&gt;, &lt;code&gt;.out&lt;/code&gt;, etc.).
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Key Insight:&lt;/strong&gt; Since compilation is modular, we can compile different parts of a project in different languages and &lt;strong&gt;link them later&lt;/strong&gt;.  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;2. Linking: The Glue That Binds Languages&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Linking is where the magic happens. There are two main types:  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;A. Static Linking&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Library code is &lt;strong&gt;copied directly&lt;/strong&gt; into the executable.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Self-contained, no runtime dependencies.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Larger binary, harder to update libraries.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;B. Dynamic Linking&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Libraries (&lt;code&gt;.so&lt;/code&gt; on Linux, &lt;code&gt;.dll&lt;/code&gt; on Windows) are loaded &lt;strong&gt;at runtime&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Saves disk space, allows library updates without recompiling.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Requires the library to be present on the system.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Example: Calling C from Rust&lt;/strong&gt;
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;Write a function in C:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;   &lt;span class="c1"&gt;// lib.c&lt;/span&gt;
   &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;b&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="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="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Compile it as a static library:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   gcc &lt;span class="nt"&gt;-c&lt;/span&gt; lib.c &lt;span class="nt"&gt;-o&lt;/span&gt; lib.o  
   ar rcs libadd.a lib.o  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Call it from Rust:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;   &lt;span class="c1"&gt;// main.rs&lt;/span&gt;
   &lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;add&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;i32&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;i32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;i32&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;  
   &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;unsafe&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;add&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="mi"&gt;3&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;ol&gt;
&lt;li&gt;Compile &amp;amp; link:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   rustc main.rs &lt;span class="nt"&gt;-l&lt;/span&gt; add &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nb"&gt;.&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;This works because both C and Rust produce object files that the linker can merge.&lt;/strong&gt;  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;3. Real-World Examples of Multi-Language Projects&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;Languages Used&lt;/th&gt;
&lt;th&gt;Why?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Linux Kernel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C (core), Assembly (critical sections)&lt;/td&gt;
&lt;td&gt;Performance for low-level hardware control.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FFmpeg&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C (core), Assembly (SIMD optimizations)&lt;/td&gt;
&lt;td&gt;Speed for video encoding/decoding.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Python Interpreter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C (core), Python (standard library)&lt;/td&gt;
&lt;td&gt;C for speed, Python for flexibility.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node.js&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C++ (V8 engine), JavaScript (runtime)&lt;/td&gt;
&lt;td&gt;C++ for performance, JS for usability.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;4. The Big Challenge: ABI (Application Binary Interface)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Even if two languages compile to machine code, they might &lt;strong&gt;not work together&lt;/strong&gt; if they disagree on:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How function arguments are passed&lt;/strong&gt; (registers vs. stack).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How return values are handled&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Memory alignment of structures&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Example: ABI Mismatch Between Two Languages&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Suppose:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Language A&lt;/strong&gt; passes arguments in &lt;strong&gt;registers 0 and 1&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Language B&lt;/strong&gt; expects them in &lt;strong&gt;registers 1 and 2&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Result:&lt;/strong&gt; The function reads garbage values → &lt;strong&gt;Undefined behavior!&lt;/strong&gt;  &lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Solutions:&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;extern "C"&lt;/code&gt; in C++/Rust&lt;/strong&gt; – Forces C-style calling conventions.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;#[repr(C)]&lt;/code&gt; in Rust&lt;/strong&gt; – Ensures structs match C memory layout.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compiler flags&lt;/strong&gt; (&lt;code&gt;-fPIC&lt;/code&gt;, &lt;code&gt;-mabi&lt;/code&gt;) to enforce compatibility.
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;5. When Should You Mix Languages?&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Good Language Choices&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;High-performance computing&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C/Rust + Python (for scripting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Embedded systems&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C (firmware) + Assembly (critical loops)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Game development&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;C++ (engine) + Lua (scripting)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Web backends&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Go (API) + Python (ML components)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Pros of Mixing Languages&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;✅ &lt;strong&gt;Performance&lt;/strong&gt; – Optimize bottlenecks in a lower-level language.&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Reuse existing libraries&lt;/strong&gt; (e.g., TensorFlow in Python calls C++ under the hood).&lt;br&gt;&lt;br&gt;
✅ &lt;strong&gt;Flexibility&lt;/strong&gt; – Use the best tool for each part of the project.  &lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Cons&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;⚠ &lt;strong&gt;Build complexity&lt;/strong&gt; – Managing multiple compilers and linkers.&lt;br&gt;&lt;br&gt;
⚠ &lt;strong&gt;Debugging challenges&lt;/strong&gt; – Mixed-language stack traces.&lt;br&gt;&lt;br&gt;
⚠ &lt;strong&gt;ABI risks&lt;/strong&gt; – If calling conventions don’t match.  &lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;strong&gt;Final Thoughts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Mixing programming languages is &lt;strong&gt;not just possible—it’s common&lt;/strong&gt; in performance-critical and large-scale systems. The key lies in:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Understanding the compilation pipeline&lt;/strong&gt; (preprocessing → compilation → assembly → linking).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Using the linker effectively&lt;/strong&gt; (static vs. dynamic libraries).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ensuring ABI compatibility&lt;/strong&gt; (so functions can call each other correctly).
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Whether you're optimizing a game engine with C++ and Lua, speeding up Python with C extensions, or writing kernel modules in Rust and Assembly—knowing how languages interoperate unlocks &lt;strong&gt;new levels of performance and flexibility&lt;/strong&gt;.  &lt;/p&gt;

&lt;p&gt;In the next part, we’ll explore &lt;strong&gt;how compiled languages (C, Rust) interact with interpreted ones (Python, JavaScript)&lt;/strong&gt;—stay tuned!  &lt;/p&gt;




&lt;h3&gt;
  
  
  &lt;strong&gt;Follow for More Deep Dives&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Twitter (X):&lt;/strong&gt; &lt;a href="https://x.com/aadarsh_nagrath" rel="noopener noreferrer"&gt;@aadarsh_nagrath&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LinkedIn:&lt;/strong&gt; &lt;a href="https://www.linkedin.com/in/aadarsh-nagrath/" rel="noopener noreferrer"&gt;Aadarsh Nagrath&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Got questions? Drop them below! 🚀&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Comprehensive Guide to gRPC</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Wed, 23 Jul 2025 06:54:00 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/comprehensive-guide-to-grpc-33f</link>
      <guid>https://forem.com/aadarsh-nagrath/comprehensive-guide-to-grpc-33f</guid>
      <description>&lt;h2&gt;
  
  
  🧭 Guide to gRPC
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Written by:&lt;/strong&gt; Aadarsh Nagrath&lt;br&gt;
🔗 &lt;a href="https://github.com/aadarsh-nagratha" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; • &lt;a href="https://x.com/aadarsh_nagrath" rel="noopener noreferrer"&gt;X (Twitter)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Introduction to gRPC
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;gRPC&lt;/strong&gt; (gRPC Remote Procedure Calls) is a high-performance, open-source framework developed by Google for building scalable and efficient APIs. It leverages &lt;strong&gt;HTTP/2&lt;/strong&gt; as its transport protocol and &lt;strong&gt;Protocol Buffers (protobuf)&lt;/strong&gt; as its Interface Definition Language (IDL), enabling fast, type-safe, and language-agnostic communication between systems. gRPC is designed for modern distributed systems, particularly microservices, real-time applications, mobile apps, and IoT devices, where low latency, high throughput, and cross-language interoperability are critical.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features of gRPC
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;High Performance&lt;/strong&gt;: Uses HTTP/2 for multiplexing, header compression, and binary framing, reducing latency and bandwidth usage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strong Typing&lt;/strong&gt;: Protocol Buffers provide a schema-driven, type-safe way to define APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Language Support&lt;/strong&gt;: Generates client and server code for languages like Go, Java, Python, C++, TypeScript, and more.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Streaming&lt;/strong&gt;: Supports unary (single request/response), server streaming, client streaming, and bidirectional streaming.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in Features&lt;/strong&gt;: Includes authentication, load balancing, retries, and deadlines out of the box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Platform&lt;/strong&gt;: Works across cloud, mobile, web, and IoT environments.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why gRPC?
&lt;/h3&gt;

&lt;p&gt;gRPC addresses limitations of traditional REST APIs and older RPC frameworks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Compared to REST&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Faster: Binary protocol (protobuf) vs. text-based JSON/XML.&lt;/li&gt;
&lt;li&gt;Lower latency: HTTP/2 multiplexing vs. HTTP/1.1 sequential requests.&lt;/li&gt;
&lt;li&gt;Streaming: Native support for real-time communication vs. REST’s reliance on WebSockets or polling.&lt;/li&gt;
&lt;li&gt;Strict contracts: Protobuf ensures consistency vs. REST’s flexible but error-prone payloads.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Compared to Older RPC&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Modern protocol: HTTP/2 vs. proprietary protocols.&lt;/li&gt;
&lt;li&gt;Language-agnostic: Protobuf vs. language-specific stubs.&lt;/li&gt;
&lt;li&gt;Scalability: Designed for distributed systems vs. tightly coupled client-server models.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  📦 REST vs GraphQL
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;REST&lt;/th&gt;
&lt;th&gt;GraphQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Endpoint structure&lt;/td&gt;
&lt;td&gt;Multiple endpoints (&lt;code&gt;/users&lt;/code&gt;, &lt;code&gt;/posts&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Single endpoint (&lt;code&gt;/graphql&lt;/code&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data fetching&lt;/td&gt;
&lt;td&gt;Fixed response structure&lt;/td&gt;
&lt;td&gt;Client defines what data to fetch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Over-fetching / Under-fetching&lt;/td&gt;
&lt;td&gt;Common problem&lt;/td&gt;
&lt;td&gt;Avoided (fetch exactly what you want)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Versioning&lt;/td&gt;
&lt;td&gt;Needs versioning (v1, v2, etc.)&lt;/td&gt;
&lt;td&gt;Often no versioning needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response size&lt;/td&gt;
&lt;td&gt;May be large or incomplete&lt;/td&gt;
&lt;td&gt;Tailored to client's request&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h3&gt;
  
  
  🛠 GraphQL Operations
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Query&lt;/strong&gt; – to &lt;strong&gt;read&lt;/strong&gt; data
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;query&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;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&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="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="n"&gt;email&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mutation&lt;/strong&gt; – to &lt;strong&gt;create/update/delete&lt;/strong&gt; data
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;mutation&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;addPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"World"&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="n"&gt;id&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="n"&gt;title&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Subscription&lt;/strong&gt; – to get &lt;strong&gt;real-time updates&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="k"&gt;subscription&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;messageAdded&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;content&lt;/span&gt;&lt;span class="w"&gt;
       &lt;/span&gt;&lt;span class="n"&gt;sender&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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  🧩 Example Use Case
&lt;/h3&gt;

&lt;p&gt;You can request nested and related data in one query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight graphql"&gt;&lt;code&gt;&lt;span class="k"&gt;query&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;user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1"&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="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;posts&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;title&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="n"&gt;comments&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;content&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="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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This replaces what would be &lt;strong&gt;multiple REST requests&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protocol Buffers: The Heart of gRPC
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Protocol Buffers (protobuf)&lt;/strong&gt; is Google’s language-agnostic, extensible mechanism for serializing structured data. It serves as the IDL for gRPC, defining services, methods, and message types.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of Protocol Buffers
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Unified Source of Truth&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Protobuf files (&lt;code&gt;*.proto&lt;/code&gt;) define the API contract, ensuring consistency across clients, servers, and documentation.&lt;/li&gt;
&lt;li&gt;Example: A single &lt;code&gt;.proto&lt;/code&gt; file generates code for all supported languages, reducing discrepancies.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Type Safety&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Enforces strict typing (e.g., &lt;code&gt;string&lt;/code&gt;, &lt;code&gt;int32&lt;/code&gt;, &lt;code&gt;bool&lt;/code&gt;) and field validation at compile time.&lt;/li&gt;
&lt;li&gt;Example: A missing required field in a message triggers a compilation error, not a runtime failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Language Code Generation&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Generates consistent client/server stubs for languages like Go, Java, Python, C++, Ruby, etc.&lt;/li&gt;
&lt;li&gt;Example: A &lt;code&gt;UserService&lt;/code&gt; defined in protobuf generates a &lt;code&gt;UserServiceClient&lt;/code&gt; and &lt;code&gt;UserServiceServer&lt;/code&gt; in each language.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forward/Backward Compatibility&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Protobuf supports schema evolution with rules like:

&lt;ul&gt;
&lt;li&gt;Do not change field numbers.&lt;/li&gt;
&lt;li&gt;Add new fields with new numbers.&lt;/li&gt;
&lt;li&gt;Mark deprecated fields as &lt;code&gt;reserved&lt;/code&gt; to prevent reuse.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Example: Adding a new field to a message doesn’t break existing clients.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compact and Efficient&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Binary serialization is smaller and faster than JSON/XML.&lt;/li&gt;
&lt;li&gt;Example: A protobuf message is ~3-10x smaller than its JSON equivalent.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Readable Syntax&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Protobuf’s syntax is concise and human-readable compared to verbose OpenAPI JSON/YAML.&lt;/li&gt;
&lt;li&gt;Example:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt; &lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;id&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="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&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;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Protobuf Syntax
&lt;/h3&gt;

&lt;p&gt;A typical &lt;code&gt;.proto&lt;/code&gt; file includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Syntax&lt;/strong&gt;: Specifies the protobuf version (e.g., &lt;code&gt;syntax = "proto3"&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Package&lt;/strong&gt;: Defines a namespace to avoid naming conflicts (e.g., &lt;code&gt;package user&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Service&lt;/strong&gt;: Defines RPC methods (e.g., &lt;code&gt;rpc GetUser(GetUserRequest) returns (GetUserResponse)&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message&lt;/strong&gt;: Defines data structures with typed fields (e.g., &lt;code&gt;message GetUserRequest { string id = 1; }&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Options&lt;/strong&gt;: Customizes code generation or behavior (e.g., &lt;code&gt;option go_package = "./user"&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;go_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./user"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetUserRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetUserResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;AddUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AddUserRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AddUserResponse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;GetUserRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;id&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;GetUserResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;id&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="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;AddUserRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;AddUserResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;id&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  gRPC Communication Patterns
&lt;/h2&gt;

&lt;p&gt;gRPC supports four communication patterns, making it versatile for various use cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Unary RPC&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single request, single response.&lt;/li&gt;
&lt;li&gt;Similar to a traditional REST API call.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;rpc GetUser(GetUserRequest) returns (GetUserResponse);&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use Case: Fetching a user’s profile by ID.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Server Streaming RPC&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single request, stream of responses.&lt;/li&gt;
&lt;li&gt;Server sends multiple messages over a single connection.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;rpc ListUsers(ListUsersRequest) returns (stream User);&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use Case: Streaming real-time stock prices.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Client Streaming RPC&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stream of requests, single response.&lt;/li&gt;
&lt;li&gt;Client sends multiple messages, and the server responds once.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;rpc UploadFile(stream FileChunk) returns (UploadResponse);&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use Case: Uploading a large file in chunks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Bidirectional Streaming RPC&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stream of requests and responses.&lt;/li&gt;
&lt;li&gt;Both client and server send messages asynchronously over a single connection.&lt;/li&gt;
&lt;li&gt;Example: &lt;code&gt;rpc Chat(stream Message) returns (stream Message);&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use Case: Real-time chat applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  HTTP/2: The Transport Layer
&lt;/h2&gt;

&lt;p&gt;gRPC uses &lt;strong&gt;HTTP/2&lt;/strong&gt; as its transport protocol, offering significant advantages over HTTP/1.1 (used in most REST APIs):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Multiplexing&lt;/strong&gt;: Multiple requests/responses over a single TCP connection, reducing latency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header Compression&lt;/strong&gt;: HPACK reduces header size, improving efficiency.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary Framing&lt;/strong&gt;: Messages are sent as binary frames, not text, for faster parsing.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Persistent Connections&lt;/strong&gt;: Keeps connections alive, reducing overhead for frequent requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server Push&lt;/strong&gt;: Servers can proactively send data to clients (less common in gRPC).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  gRPC over HTTP/2 vs. REST over HTTP/1.1
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;gRPC (HTTP/2)&lt;/th&gt;
&lt;th&gt;REST (HTTP/1.1)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;Binary (protobuf)&lt;/td&gt;
&lt;td&gt;Text (JSON/XML)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Low (multiplexing, compression)&lt;/td&gt;
&lt;td&gt;Higher (sequential requests)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Streaming&lt;/td&gt;
&lt;td&gt;Native support&lt;/td&gt;
&lt;td&gt;Limited (WebSockets/polling)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type Safety&lt;/td&gt;
&lt;td&gt;Strong (protobuf)&lt;/td&gt;
&lt;td&gt;Weak (schema optional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bandwidth Usage&lt;/td&gt;
&lt;td&gt;Low (binary)&lt;/td&gt;
&lt;td&gt;Higher (text)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser Support&lt;/td&gt;
&lt;td&gt;Limited (requires proxy)&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  gRPC Ecosystem and Tools
&lt;/h2&gt;

&lt;p&gt;gRPC integrates with a robust ecosystem of tools and libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;protoc&lt;/strong&gt;: The Protocol Buffers compiler generates code from &lt;code&gt;.proto&lt;/code&gt; files.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;buf&lt;/strong&gt;: A modern tool for managing protobuf schemas, linting, and generating code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;gRPC Plugins&lt;/strong&gt;: Language-specific plugins (e.g., &lt;code&gt;protoc-gen-go&lt;/code&gt;, &lt;code&gt;protoc-gen-go-grpc&lt;/code&gt;) for code generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;gRPC Gateway&lt;/strong&gt;: Translates gRPC to REST/JSON for web clients.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: Tools like Prometheus and Grafana for observability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Testing&lt;/strong&gt;: Tools like &lt;code&gt;ghz&lt;/code&gt; for load testing and &lt;code&gt;grpcurl&lt;/code&gt; for CLI-based testing.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Implementing a gRPC Service
&lt;/h2&gt;

&lt;p&gt;Below is an expanded implementation based on the provided document, with additional features and best practices.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Install the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;protoc&lt;/strong&gt;: Protocol Buffers compiler (&lt;code&gt;protoc&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;buf&lt;/strong&gt;: Protobuf management tool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go Plugins&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  go &lt;span class="nb"&gt;install &lt;/span&gt;google.golang.org/protobuf/cmd/protoc-gen-go@latest
  go &lt;span class="nb"&gt;install &lt;/span&gt;google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
  go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/meshapi/grpc-api-gateway/codegen/cmd/protoc-gen-grpc-api-gateway@latest
  go &lt;span class="nb"&gt;install &lt;/span&gt;github.com/meshapi/grpc-api-gateway/codegen/cmd/protoc-gen-openapiv3@latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Set Up a buf Project
&lt;/h3&gt;

&lt;p&gt;Create a &lt;code&gt;buf.yaml&lt;/code&gt; to define the project and dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;deps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;buf.build/meshapi/grpc-api-gateway&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sync dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;buf mod update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;buf.gen.yaml&lt;/code&gt; for code generation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go&lt;/span&gt;
    &lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;opt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;paths=source_relative&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;go-grpc&lt;/span&gt;
    &lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;opt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;paths=source_relative&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grpc-api-gateway&lt;/span&gt;
    &lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;opt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;paths=source_relative&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;openapiv3&lt;/span&gt;
    &lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;opt&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;paths=source_relative&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Define the Protobuf Service
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;user.proto&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt;&lt;span class="na"&gt;syntax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"proto3"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="na"&gt;go_package&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"./user"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"meshapi/gateway/annotations.proto"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;service&lt;/span&gt; &lt;span class="n"&gt;UserService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Unary RPC: Add a new user&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;AddUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AddUserRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AddUserResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meshapi.gateway.http&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;post&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/v1/users"&lt;/span&gt;
      &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Server streaming RPC: List users&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;ListUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ListUsersRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&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;span class="k"&gt;option&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meshapi.gateway.http&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;get&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/v1/users"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Client streaming RPC: Bulk add users&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;BulkAddUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;AddUserRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BulkAddUsersResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meshapi.gateway.http&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;post&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/v1/users/bulk"&lt;/span&gt;
      &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="c1"&gt;// Bidirectional streaming RPC: Real-time chat&lt;/span&gt;
  &lt;span class="k"&gt;rpc&lt;/span&gt; &lt;span class="n"&gt;Chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;returns&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&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="k"&gt;option&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meshapi.gateway.http&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;get&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/v1/chat"&lt;/span&gt;
      &lt;span class="n"&gt;streaming&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WEBSOCKET&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="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;AddUserRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&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="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;AddUserResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;id&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;ListUsersRequest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;limit&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="kt"&gt;int32&lt;/span&gt; &lt;span class="na"&gt;offset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;User&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;id&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="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;BulkAddUsersResponse&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;repeated&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;ids&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="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;message&lt;/span&gt; &lt;span class="nc"&gt;Message&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;user_id&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="kt"&gt;string&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kt"&gt;int64&lt;/span&gt; &lt;span class="na"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&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;h3&gt;
  
  
  Step 3: Generate Code
&lt;/h3&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;buf generate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This generates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Go models (&lt;code&gt;user.pb.go&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;gRPC stubs (&lt;code&gt;user_grpc.pb.go&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;HTTP reverse proxy (&lt;code&gt;user_grpc_api_gateway.pb.go&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;OpenAPI v3 documentation (&lt;code&gt;user_openapiv3.yaml&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Step 4: Implement the gRPC Service and Gateway
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;main.go&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"context"&lt;/span&gt;
    &lt;span class="s"&gt;"log"&lt;/span&gt;
    &lt;span class="s"&gt;"net"&lt;/span&gt;
    &lt;span class="s"&gt;"net/http"&lt;/span&gt;
    &lt;span class="s"&gt;"github.com/meshapi/grpc-api-gateway/gateway"&lt;/span&gt;
    &lt;span class="s"&gt;"google.golang.org/grpc"&lt;/span&gt;
    &lt;span class="s"&gt;"google.golang.org/grpc/credentials/insecure"&lt;/span&gt;
    &lt;span class="n"&gt;pb&lt;/span&gt; &lt;span class="s"&gt;"path/to/user"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UserServiceServer&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnimplementedUserServiceServer&lt;/span&gt;
    &lt;span class="n"&gt;users&lt;/span&gt; &lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="c"&gt;// In-memory storage for demo&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;NewUserServiceServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserServiceServer&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;UserServiceServer&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&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;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserServiceServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;AddUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddUserRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddUserResponse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;generateID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c"&gt;// Implement ID generation&lt;/span&gt;
    &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&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="n"&gt;Id&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;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&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="n"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Email&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddUserResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Id&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserServiceServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ListUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListUsersRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserService_ListUsersServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&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="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Send&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&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="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserServiceServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;BulkAddUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserService_BulkAddUsersServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Recv&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EOF&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;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SendAndClose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BulkAddUsersResponse&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Ids&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ids&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="n"&gt;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;generateID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;pb&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="n"&gt;Id&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;Name&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&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="n"&gt;Email&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="o"&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;ids&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ids&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&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;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserServiceServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserService_ChatServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Recv&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c"&gt;// Echo back the message for simplicity&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;err&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;func&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Start gRPC server&lt;/span&gt;
    &lt;span class="n"&gt;lis&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;":40000"&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to listen: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;grpcServer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterUserServiceServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpcServer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;NewUserServiceServer&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gRPC server running on :40000"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpcServer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lis&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to serve gRPC: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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="c"&gt;// Start HTTP gateway&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":40000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTransportCredentials&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;insecure&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewCredentials&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to dial gRPC: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;restGateway&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;gateway&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServeMux&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RegisterUserServiceHandlerClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;restGateway&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewUserServiceClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"HTTP gateway running on :4000"&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenAndServe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;":4000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restGateway&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fatalf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to serve HTTP: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;func&lt;/span&gt; &lt;span class="n"&gt;generateID&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Implement unique ID generation (e.g., UUID)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"user-%d"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&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="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnixNano&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;h3&gt;
  
  
  Step 5: Run the Service
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;go mod init example
go mod tidy
go run &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 6: Test the Service
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;gRPC Client&lt;/strong&gt;: Use &lt;code&gt;grpcurl&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  grpcurl &lt;span class="nt"&gt;-plaintext&lt;/span&gt; localhost:40000 user.UserService.AddUser &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "Alice", "email": "alice@example.com"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HTTP Gateway&lt;/strong&gt;: Use &lt;code&gt;curl&lt;/code&gt;:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:4000/v1/users &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"name": "Alice", "email": "alice@example.com"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Streaming (WebSocket)&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Use a WebSocket client to connect to &lt;code&gt;ws://localhost:4000/v1/chat&lt;/code&gt; and send/receive messages.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  gRPC Gateway: Bridging gRPC and REST
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;gRPC API Gateway&lt;/strong&gt; (as described in the provided document) translates gRPC services into RESTful HTTP/JSON endpoints, enabling web browsers, legacy systems, and REST-based clients to interact with gRPC services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enhanced Configuration&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports query parameters, path parameter renaming, and custom OpenAPI fields.&lt;/li&gt;
&lt;li&gt;Allows external YAML/JSON configuration files for flexibility.&lt;/li&gt;
&lt;li&gt;Example: Map a gRPC method to a REST endpoint with annotations:
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class="highlight protobuf"&gt;&lt;code&gt; &lt;span class="k"&gt;option&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meshapi.gateway.http&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;post&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"/v1/users"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;body&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;OpenAPI 3.1 Support&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generates precise JSON Schema for validation and documentation.&lt;/li&gt;
&lt;li&gt;Optimizes model generation by including only relevant models.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Streaming Support&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server-Sent Events (SSE)&lt;/strong&gt;: For server-to-client streaming (e.g., real-time notifications).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;WebSocket&lt;/strong&gt;: For bidirectional streaming (e.g., chat applications).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Robust Error Handling&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separates gRPC and HTTP errors for customized responses.&lt;/li&gt;
&lt;li&gt;Example: A gRPC &lt;code&gt;NotFound&lt;/code&gt; error maps to HTTP &lt;code&gt;404&lt;/code&gt; with a JSON payload.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Custom Marshalling&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Supports custom content types (e.g., XML, YAML) via pluggable marshallers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Technical Architecture
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code Generation&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Analyzes &lt;code&gt;.proto&lt;/code&gt; files and annotations.&lt;/li&gt;
&lt;li&gt;Generates Go handlers for HTTP requests.&lt;/li&gt;
&lt;li&gt;Produces OpenAPI documentation.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Runtime&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;HTTP handlers translate REST requests to gRPC calls.&lt;/li&gt;
&lt;li&gt;Supports WebSocket/SSE for streaming.&lt;/li&gt;
&lt;li&gt;Customizes error responses and header mappings.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced gRPC Topics
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Authentication and Authorization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Transport Security&lt;/strong&gt;: gRPC uses TLS by default for encrypted communication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authentication&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;JWT&lt;/strong&gt;: Include tokens in metadata (e.g., &lt;code&gt;authorization: bearer &amp;lt;token&amp;gt;&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAuth 2.0&lt;/strong&gt;: Integrate with OAuth for secure access.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mutual TLS&lt;/strong&gt;: Authenticate both client and server using certificates.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Authorization&lt;/strong&gt;: Use interceptors to enforce role-based access control (RBAC).&lt;/li&gt;

&lt;li&gt;Example Interceptor (Go):
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;UnaryAuthInterceptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnaryServerInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnaryHandler&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;metadata&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromIncomingContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;md&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"authorization"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&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;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;codes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unauthenticated&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Missing auth token"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c"&gt;// Validate token&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&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;h3&gt;
  
  
  Error Handling
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;gRPC uses a structured error model with &lt;strong&gt;status codes&lt;/strong&gt; (e.g., &lt;code&gt;codes.NotFound&lt;/code&gt;, &lt;code&gt;codes.InvalidArgument&lt;/code&gt;) and details.&lt;/li&gt;
&lt;li&gt;Example: Return a &lt;code&gt;NotFound&lt;/code&gt; error:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&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;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;codes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NotFound&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"User %s not found"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&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;ul&gt;
&lt;li&gt;HTTP Gateway maps gRPC status codes to HTTP status codes (e.g., &lt;code&gt;codes.NotFound&lt;/code&gt; → &lt;code&gt;404&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Load Balancing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;gRPC supports client-side and server-side load balancing:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client-Side&lt;/strong&gt;: Use a resolver (e.g., DNS, Kubernetes) to distribute requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Server-Side&lt;/strong&gt;: Use a proxy like Envoy for advanced load balancing.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Example: Configure a round-robin balancer in Go:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"dns:///service.example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithBalancerName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"round_robin"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deadlines and Timeouts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;gRPC allows setting deadlines to prevent hanging requests.&lt;/li&gt;
&lt;li&gt;Example (Go client):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WithTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Background&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;cancel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;resp&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Interceptors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server Interceptors&lt;/strong&gt;: Intercept incoming requests for logging, metrics, or authentication.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Interceptors&lt;/strong&gt;: Modify outgoing requests (e.g., add headers, retry logic).&lt;/li&gt;
&lt;li&gt;Example: Logging interceptor (Go):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;LoggingInterceptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ClientConn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;invoker&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnaryInvoker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt; &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CallOption&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;start&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;invoker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Method: %s, Duration: %v, Error: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Since&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;err&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;err&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Streaming Best Practices
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Server Streaming&lt;/strong&gt;: Use for large datasets or real-time updates (e.g., stock tickers).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Streaming&lt;/strong&gt;: Ideal for uploading large data (e.g., file uploads).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bidirectional Streaming&lt;/strong&gt;: Use for interactive apps (e.g., chat, gaming).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error Handling&lt;/strong&gt;: Handle &lt;code&gt;io.EOF&lt;/code&gt; for stream closure and partial failures.&lt;/li&gt;
&lt;li&gt;Example: Handle stream errors:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UserServiceServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;ListUsers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;req&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListUsersRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="n"&gt;pb&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserService_ListUsersServer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&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="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;users&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;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Send&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&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;status&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;codes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Internal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Failed to send: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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="no"&gt;nil&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Monitoring and Observability
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use tools like &lt;strong&gt;Prometheus&lt;/strong&gt; and &lt;strong&gt;Grafana&lt;/strong&gt; for metrics (e.g., request latency, error rates).&lt;/li&gt;
&lt;li&gt;Enable &lt;strong&gt;gRPC tracing&lt;/strong&gt; with OpenTelemetry or Jaeger.&lt;/li&gt;
&lt;li&gt;Example: Export metrics in Go:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;  &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"github.com/grpc-ecosystem/go-grpc-prometheus"&lt;/span&gt;
  &lt;span class="n"&gt;grpcServer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NewServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnaryInterceptor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;grpc_prometheus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UnaryServerInterceptor&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Testing gRPC Services
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unit Testing&lt;/strong&gt;: Test individual RPC methods using mocks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Testing&lt;/strong&gt;: Test client-server interactions with a real gRPC server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tools&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;grpcurl&lt;/strong&gt;: CLI tool for sending gRPC requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ghz&lt;/strong&gt;: Load testing tool for gRPC.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postman&lt;/strong&gt;: Test HTTP gateway endpoints.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Example: Test with &lt;code&gt;grpcurl&lt;/code&gt;:
&lt;/li&gt;

&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  grpcurl &lt;span class="nt"&gt;-plaintext&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"id": "user1"}'&lt;/span&gt; localhost:40000 user.UserService.GetUser
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Security Considerations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TLS&lt;/strong&gt;: Always use TLS in production (e.g., &lt;code&gt;grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig))&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input Validation&lt;/strong&gt;: Validate protobuf messages to prevent invalid data.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rate Limiting&lt;/strong&gt;: Use interceptors to enforce rate limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata Security&lt;/strong&gt;: Sanitize gRPC metadata to prevent injection attacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Performance Optimization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Connection Pooling&lt;/strong&gt;: Reuse gRPC connections to reduce overhead.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compression&lt;/strong&gt;: Enable gRPC compression (e.g., &lt;code&gt;grpc.WithCompressor(grpc.NewGzipCompressor())&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batching&lt;/strong&gt;: Combine small requests to reduce network calls.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protobuf Optimization&lt;/strong&gt;: Use scalar types (e.g., &lt;code&gt;int32&lt;/code&gt; vs. &lt;code&gt;string&lt;/code&gt;) for smaller payloads.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Comparison with Other API Architectures
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;gRPC&lt;/th&gt;
&lt;th&gt;REST&lt;/th&gt;
&lt;th&gt;GraphQL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Protocol&lt;/td&gt;
&lt;td&gt;HTTP/2, binary (protobuf)&lt;/td&gt;
&lt;td&gt;HTTP/1.1, text (JSON/XML)&lt;/td&gt;
&lt;td&gt;HTTP/1.1, text (JSON)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Performance&lt;/td&gt;
&lt;td&gt;High (binary, multiplexing)&lt;/td&gt;
&lt;td&gt;Moderate (text, sequential)&lt;/td&gt;
&lt;td&gt;Moderate (text, single endpoint)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Type Safety&lt;/td&gt;
&lt;td&gt;Strong (protobuf)&lt;/td&gt;
&lt;td&gt;Weak (optional schemas)&lt;/td&gt;
&lt;td&gt;Strong (GraphQL schema)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Streaming&lt;/td&gt;
&lt;td&gt;Native (unary, bidirectional)&lt;/td&gt;
&lt;td&gt;Limited (WebSockets/polling)&lt;/td&gt;
&lt;td&gt;Limited (subscriptions)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Browser Support&lt;/td&gt;
&lt;td&gt;Limited (requires proxy)&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Flexibility&lt;/td&gt;
&lt;td&gt;Strict contracts&lt;/td&gt;
&lt;td&gt;Flexible payloads&lt;/td&gt;
&lt;td&gt;Highly flexible queries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use Case&lt;/td&gt;
&lt;td&gt;Microservices, real-time&lt;/td&gt;
&lt;td&gt;General-purpose, web-friendly&lt;/td&gt;
&lt;td&gt;Client-driven data fetching&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Real-World Use Cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Microservices&lt;/strong&gt;: Efficient inter-service communication (e.g., Netflix, Uber).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-Time Applications&lt;/strong&gt;: Streaming data for gaming, chat, or live updates (e.g., Discord).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile Apps&lt;/strong&gt;: Low-bandwidth communication for better battery life (e.g., Google apps).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IoT&lt;/strong&gt;: Lightweight communication for resource-constrained devices (e.g., smart home systems).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cloud Services&lt;/strong&gt;: Programmatic access to cloud resources (e.g., Google Cloud APIs).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Future Directions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Reflection&lt;/strong&gt;: Runtime service discovery without code generation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-Language Gateways&lt;/strong&gt;: Support for Python, Rust, Node.js, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Serverless gRPC&lt;/strong&gt;: Integration with serverless platforms like AWS Lambda.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Integration&lt;/strong&gt;: gRPC for low-latency AI model serving (e.g., TensorFlow Serving).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enhanced Tooling&lt;/strong&gt;: Improved linting, testing, and observability tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;gRPC is a powerful framework for building high-performance, scalable APIs, particularly suited for microservices, real-time applications, and polyglot environments. Its use of Protocol Buffers, HTTP/2, and streaming capabilities makes it a modern alternative to REST and older RPC frameworks. By leveraging tools like gRPC Gateway, developers can bridge the gap between gRPC and REST, making it accessible to web clients while retaining its performance benefits. Whether you’re building a microservices architecture or a real-time application, gRPC equips you with the tools to create robust, efficient, and maintainable APIs.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How Notion Handles 200 Billion Notes Without Crashing: A Technical Deep Dive</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Wed, 26 Mar 2025 20:19:51 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/how-notion-handles-200-billion-notes-without-crashing-a-technical-deep-dive-5deh</link>
      <guid>https://forem.com/aadarsh-nagrath/how-notion-handles-200-billion-notes-without-crashing-a-technical-deep-dive-5deh</guid>
      <description>&lt;p&gt;Notion isn’t just a note-taking app—it’s a &lt;strong&gt;real-time, collaborative database&lt;/strong&gt; masquerading as a minimalist UI. But how does it handle &lt;strong&gt;200+ billion blocks&lt;/strong&gt; (database entries) without buckling under pressure? &lt;/p&gt;

&lt;p&gt;Let’s peel back the layers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Notion’s Data Model: A Database in Disguise
&lt;/h2&gt;

&lt;p&gt;Every action in Notion—typing text, toggling a checkbox—creates a &lt;strong&gt;block&lt;/strong&gt;, stored as a row in PostgreSQL. Here’s the schema of a block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;blocks&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="nb"&gt;VARCHAR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;       &lt;span class="c1"&gt;-- 'paragraph', 'checkbox', etc.&lt;/span&gt;
  &lt;span class="n"&gt;parent_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;         &lt;span class="c1"&gt;-- Parent block (if nested)&lt;/span&gt;
  &lt;span class="n"&gt;workspace_id&lt;/span&gt; &lt;span class="n"&gt;UUID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;-- Critical for sharding&lt;/span&gt;
  &lt;span class="n"&gt;properties&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;        &lt;span class="c1"&gt;-- Flexible content storage&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;Fun Fact&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
When you hit &lt;code&gt;↑&lt;/code&gt; or &lt;code&gt;↓&lt;/code&gt; in Notion, it’s not moving a cursor—it’s jumping between &lt;strong&gt;database rows&lt;/strong&gt;. A "simple" page with 10 elements = 10+ database queries!&lt;/p&gt;


&lt;h2&gt;
  
  
  The Scaling Crisis: 20 Billion Blocks and Chaos
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Why Postgres Almost Died
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single database&lt;/strong&gt;: Pre-2021, all blocks lived in one PostgreSQL instance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Indexes bloated&lt;/strong&gt;: Querying a workspace’s blocks required scanning &lt;strong&gt;millions of rows&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Writes stalled&lt;/strong&gt;: Concurrent edits from 100M users? Good luck.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  The Sharding Savior
&lt;/h3&gt;

&lt;p&gt;Notion split data into &lt;strong&gt;480 logical shards&lt;/strong&gt; (32 machines × 15 shards each). &lt;br&gt;
How?  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fquryigxdynzwl7jqanhc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fquryigxdynzwl7jqanhc.png" alt="sharding" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Shard Key&lt;/strong&gt;: &lt;code&gt;workspace_id&lt;/code&gt; (every block belongs to one workspace).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Routing&lt;/strong&gt;: Application code directs queries like:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="n"&gt;shard&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;workspace_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;480&lt;/span&gt;  &lt;span class="c1"&gt;# Simple but effective
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Pro Tip&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Sharding isn’t free. Cross-shard queries (e.g., global search) require &lt;strong&gt;fan-out&lt;/strong&gt;—sending requests to all shards. Notion avoids this with Elasticsearch for search.&lt;/p&gt;


&lt;h2&gt;
  
  
  Zero-Downtime Migration: The Double-Write Dance
&lt;/h2&gt;

&lt;p&gt;Migrating 20B+ blocks live? Notion’s 3-step playbook:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Double Writes&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;   &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;save_block&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
     &lt;span class="n"&gt;old_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Legacy database
&lt;/span&gt;     &lt;span class="n"&gt;new_sharded_db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# New shard
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Audit Logs&lt;/strong&gt;: A Kafka stream recorded all changes for reconciliation.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The Big Cutover&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;5-minute downtime&lt;/strong&gt; to flip the switch.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dark reads&lt;/strong&gt; compared old/new DB outputs silently.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Underrated Hack&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
They used PostgreSQL’s &lt;strong&gt;logical replication&lt;/strong&gt; to sync shards—no third-party tools needed.&lt;/p&gt;


&lt;h2&gt;
  
  
  Beyond Postgres: The Data Lake Pivot
&lt;/h2&gt;

&lt;p&gt;Postgres is great for OLTP (transactions), but &lt;strong&gt;analytics&lt;/strong&gt;? Not so much. Notion’s new pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph LR
  A[Postgres Shards] --&amp;gt;|CDC| B[Apache Kafka]
  B --&amp;gt; C[Apache Spark]
  C --&amp;gt; D[Amazon S3 Data Lake]
  D --&amp;gt; E[Snowflake for Analytics]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why?&lt;/strong&gt;  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt;: Snowflake charges per query; S3 is dirt-cheap storage.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Ready&lt;/strong&gt;: Unstructured data (e.g., page content) fuels Notion’s AI features.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Gotcha&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Snowflake hates updates. Notion’s &lt;strong&gt;update-heavy&lt;/strong&gt; workload forced them to build custom tooling.&lt;/p&gt;




&lt;h2&gt;
  
  
  Open Source Gems in Notion’s Stack
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Apache Kafka&lt;/strong&gt;: Handles &lt;strong&gt;4M+ messages/sec&lt;/strong&gt; during peak loads.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pgbouncer&lt;/strong&gt;: Connection pooling to avoid Postgres meltdowns.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Apache Hudi&lt;/strong&gt;: Manages &lt;strong&gt;change-data-capture (CDC)&lt;/strong&gt; for the data lake.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Notion’s engineers &lt;strong&gt;prefer boring tech&lt;/strong&gt;—Postgres over MongoDB, Kafka over proprietary queues.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Future: What’s Next for Notion’s Stack?
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Edge Caching&lt;/strong&gt;: Reduce latency for global users.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Columnar Storage&lt;/strong&gt;: For faster analytics (e.g., Apache Parquet).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vector Databases&lt;/strong&gt;: To power AI features (semantic search, etc.).
&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why This Matters for You
&lt;/h2&gt;

&lt;p&gt;Even if you’re not building the next Notion, these principles apply:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sharding&lt;/strong&gt;: Plan it early. Use a clear key (like &lt;code&gt;workspace_id&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Lakes&lt;/strong&gt;: Separate OLTP and analytics early.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt;: Avoid vendor lock-in; Kafka/Postgres will outlive any SaaS.
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Found this interesting ?&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
To follow me - &lt;br&gt;
MY &lt;a href="https://github.com/aadarsh-nagrath" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, &lt;a href="https://x.com/aadarsh_nagrath" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to run DeepSeek Locally in Your Terminal Like a Pro</title>
      <dc:creator>Aadarsh Nagrath</dc:creator>
      <pubDate>Sun, 02 Feb 2025 15:27:53 +0000</pubDate>
      <link>https://forem.com/aadarsh-nagrath/how-to-run-deepseek-locally-in-your-terminal-like-a-pro-26j2</link>
      <guid>https://forem.com/aadarsh-nagrath/how-to-run-deepseek-locally-in-your-terminal-like-a-pro-26j2</guid>
      <description>&lt;p&gt;If you've been looking for a way to use cutting-edge AI without relying on expensive cloud services, you're in luck! DeepSeek R1 is an open-source reasoning model that runs &lt;strong&gt;entirely on your local machine&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;With a few simple steps, you can ditch online AI services and gain full control over your own AI assistant. In this guide, I'll show you how to get DeepSeek R1 running in your terminal using &lt;strong&gt;Ollama&lt;/strong&gt;, the easiest way to run open-source models locally.&lt;/p&gt;

&lt;p&gt;To follow me - &lt;br&gt;
MY &lt;a href="https://github.com/aadarsh-nagrath" rel="noopener noreferrer"&gt;Github&lt;/a&gt;, &lt;a href="https://x.com/aadarsh_nagrath" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Install Ollama
&lt;/h2&gt;

&lt;p&gt;Before we can run DeepSeek, we need to install &lt;strong&gt;Ollama&lt;/strong&gt;, which is a tool that lets you download and run AI models with a single command. Here's how you can install it based on your OS:&lt;/p&gt;
&lt;h3&gt;
  
  
  🖥️ macOS (with Homebrew)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;ollama
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  🖥️ Linux (Debian/Ubuntu)
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  🖥️ Windows (via WSL)
&lt;/h3&gt;

&lt;p&gt;For Windows, you'll need to install &lt;strong&gt;Windows Subsystem for Linux (WSL)&lt;/strong&gt; and then run the Linux installation command inside WSL.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Once installed, restart your terminal and verify the installation by running:&lt;br&gt;
&lt;/p&gt;


&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu1im2r9b5o1y6wurj89n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu1im2r9b5o1y6wurj89n.png" alt="." width="800" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Download &amp;amp; Run DeepSeek R1
&lt;/h2&gt;

&lt;p&gt;DeepSeek R1 comes in different model sizes, ranging from &lt;strong&gt;1.5 billion&lt;/strong&gt; to a massive &lt;strong&gt;671 billion&lt;/strong&gt; parameters. Generally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Smaller models (1.5B - 7B)&lt;/strong&gt; → Fast but less powerful&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Larger models (67B - 671B)&lt;/strong&gt; → Smarter but require high-end GPUs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get started, let's download and run the &lt;strong&gt;7B model&lt;/strong&gt;, which is a good balance between performance and intelligence:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run deepseek-r1:7b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command does two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Downloads the 7B model (only the first time you run it)&lt;/li&gt;
&lt;li&gt;Starts an interactive chat session with DeepSeek R1 in your terminal&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you want a &lt;strong&gt;lighter&lt;/strong&gt; version, you can try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run deepseek-r1:1.5b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you have a powerful setup and want &lt;strong&gt;maximum reasoning power&lt;/strong&gt;, go for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama run deepseek-r1:67b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(Just make sure you have enough VRAM, as the largest models require high-end GPUs!)&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Use DeepSeek R1 in the Terminal
&lt;/h2&gt;

&lt;p&gt;Once the model starts, you'll see a chat-like interface where you can ask it anything:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; How does quicksort work?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DeepSeek will generate a detailed response in real-time!&lt;/p&gt;

&lt;h3&gt;
  
  
  Customize Your Experience
&lt;/h3&gt;

&lt;p&gt;Ollama provides options to tweak the AI’s behavior. Here are some useful parameters:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9qiqbh9pix31bxomu1r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9qiqbh9pix31bxomu1r.png" alt="." width="800" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Set a custom system prompt&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  ollama run deepseek-r1 &lt;span class="nt"&gt;--system&lt;/span&gt; &lt;span class="s2"&gt;"You are an expert software engineer. Answer concisely."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Use temperature for randomness&lt;/strong&gt; (higher = more creative)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  ollama run deepseek-r1 &lt;span class="nt"&gt;--temperature&lt;/span&gt; 0.7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Limit response length&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;  ollama run deepseek-r1 &lt;span class="nt"&gt;--max-tokens&lt;/span&gt; 256
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 4: Run DeepSeek R1 in API Mode
&lt;/h2&gt;

&lt;p&gt;Want to use DeepSeek programmatically? Ollama provides an &lt;strong&gt;API mode&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ollama serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This starts a local API server. Now, you can send requests using &lt;strong&gt;cURL&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl http://localhost:11434/api/generate &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"model": "deepseek-r1:7b", "prompt": "Explain recursion."}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or integrate it into your &lt;strong&gt;Python/Node.js&lt;/strong&gt; projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Congratulations! You just installed, configured, and ran &lt;strong&gt;DeepSeek R1&lt;/strong&gt; locally in your terminal. Now, you have an open-source AI assistant at your fingertips—&lt;strong&gt;no internet, no cloud fees, just raw AI power&lt;/strong&gt; on your machine.&lt;/p&gt;

&lt;p&gt;Go ahead, experiment with different model sizes, tweak the settings, and enjoy the power of local AI! 🚀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>deepseek</category>
      <category>development</category>
    </item>
  </channel>
</rss>
