<?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>DEV Community: pante5ter</title>
    <description>The latest articles on DEV Community by pante5ter (@pante5ter).</description>
    <link>https://dev.to/pante5ter</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3960224%2F04ba2896-1904-47c7-81cb-e5b7fd9d8488.png</url>
      <title>DEV Community: pante5ter</title>
      <link>https://dev.to/pante5ter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pante5ter"/>
    <language>en</language>
    <item>
      <title>How Much Does a Custom Telegram Bot Cost in 2026? An Honest Breakdown</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Tue, 02 Jun 2026 17:49:17 +0000</pubDate>
      <link>https://dev.to/pante5ter/how-much-does-a-custom-telegram-bot-cost-in-2026-an-honest-breakdown-3lai</link>
      <guid>https://dev.to/pante5ter/how-much-does-a-custom-telegram-bot-cost-in-2026-an-honest-breakdown-3lai</guid>
      <description>&lt;p&gt;"How much for a Telegram bot?" is a fair question with an annoying answer: &lt;em&gt;it depends&lt;/em&gt;. But it depends on a small number of things you can actually reason about. Here's the honest framework I use, so you can estimate before you ever talk to a developer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you're really paying for
&lt;/h2&gt;

&lt;p&gt;The price of a bot isn't about message-sending — Telegram's API does that for free. You're paying for everything &lt;em&gt;around&lt;/em&gt; the messages: the logic, the data, the integrations, and the reliability. Four factors move the price more than anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four price factors
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. How the bot decides what to do.&lt;/strong&gt; A linear FAQ/menu bot is the cheapest tier; conversational flows that remember where the user is (booking, onboarding) cost more; an AI-driven bot that understands free text adds an AI/RAG layer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Whether it needs to remember things.&lt;/strong&gt; A bot with no memory is cheap. The moment it stores users, orders or bookings, you need a database (Postgres/Supabase), a schema and migrations — real engineering, not a script.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Whether money changes hands.&lt;/strong&gt; Taking payments (Telegram Payments, Stars, Stripe) is where "a bot" becomes "a product": correct handling of success/failure/refund states, idempotency so nobody is charged twice, and a record of every transaction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Who manages it.&lt;/strong&gt; If you'll manage content, view orders, or broadcast, you need an admin surface — effectively a second small app bolted on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rough tiers (so you can budget)
&lt;/h2&gt;

&lt;p&gt;Rather than quote numbers that go stale, here's how the tiers stack — each step roughly multiplies effort:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Tier 1 — Simple bot:&lt;/strong&gt; menu, FAQ, a form that emails you. Days, not weeks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tier 2 — Stateful bot with a database:&lt;/strong&gt; bookings, accounts, history. A small but real backend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tier 3 — Payments + admin panel:&lt;/strong&gt; the full "product" — the biggest jump, because correctness and reliability matter most.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add-on — AI assistant layer:&lt;/strong&gt; sits on top of any tier; priced by how much custom knowledge and accuracy you need.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Questions a good developer will ask
&lt;/h2&gt;

&lt;p&gt;If they don't ask these, be cautious: Does it store data, or is it stateless? Will it take payments, and how? Who manages content — you, or the developer each time? Expected volume? Any integrations (CRM, Sheets, your API)?&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes a bot worth the price
&lt;/h2&gt;

&lt;p&gt;A cheap bot that loses orders, double-charges, or silently breaks when Telegram changes something isn't cheap — it's expensive in trust. The value is in the boring parts: retries, error handling, transaction records, clean logs, and code you own and can extend. That's the difference between a weekend script and something you can run a business on.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Thinking about a Telegram bot — for bookings, payments, support or an AI assistant? I build production bots with clean, owned code and an honest scope up front — &lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>telegram</category>
      <category>bots</category>
      <category>automation</category>
      <category>startup</category>
    </item>
    <item>
      <title>Do You Need a Website or a Web App? A Simple Decision Guide</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Tue, 02 Jun 2026 17:47:22 +0000</pubDate>
      <link>https://dev.to/pante5ter/do-you-need-a-website-or-a-web-app-a-simple-decision-guide-4jmp</link>
      <guid>https://dev.to/pante5ter/do-you-need-a-website-or-a-web-app-a-simple-decision-guide-4jmp</guid>
      <description>&lt;p&gt;"I need a website" and "I need a web app" sound similar and cost very differently. Picking the wrong one means either overpaying for complexity you don't need, or building a brochure when you needed a tool. Here's a clear way to tell them apart.&lt;/p&gt;

&lt;h2&gt;
  
  
  The core difference: do users read or do?
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;website&lt;/strong&gt; is mostly &lt;em&gt;read&lt;/em&gt;. Visitors come to learn — what you offer, your prices, your story — and then contact you or buy. Think a clinic site, a restaurant, a portfolio, a landing page. The content changes occasionally; the visitor mostly consumes it.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;web app&lt;/strong&gt; is mostly &lt;em&gt;do&lt;/em&gt;. Users log in and accomplish tasks — booking, managing data, tracking orders, collaborating. State changes constantly because users are creating and changing things. Think a dashboard, a booking system, a SaaS product, an internal tool.&lt;/p&gt;

&lt;p&gt;If your visitors primarily &lt;em&gt;read and contact&lt;/em&gt;, you need a website. If they &lt;em&gt;log in and act&lt;/em&gt;, you need a web app.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it changes cost and timeline
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;website&lt;/strong&gt; is largely pages, content, SEO, and a contact path. It can look premium and load fast without heavy backend work. Faster and cheaper to build.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;web app&lt;/strong&gt; needs accounts, a database, business logic, security, and ongoing state — effectively a small software product. More design, more engineering, more testing. Longer and more expensive, justified by the work it does for users.&lt;/p&gt;

&lt;p&gt;Confusing the two is the most common budgeting mistake. People ask for "just a website" but describe user logins and dashboards (that's an app), or they over-spec an app when a sharp marketing site would convert better.&lt;/p&gt;

&lt;h2&gt;
  
  
  A simple test
&lt;/h2&gt;

&lt;p&gt;Ask: &lt;strong&gt;"What's the most important thing a user does here?"&lt;/strong&gt; Reads about us and books a call or buys a product → website. Logs in and manages something → web app. Both → a website &lt;strong&gt;front&lt;/strong&gt; with an app &lt;strong&gt;behind a login&lt;/strong&gt;. Common and totally fine — just price it as two pieces.&lt;/p&gt;

&lt;h2&gt;
  
  
  The middle ground most businesses want
&lt;/h2&gt;

&lt;p&gt;In practice, many small businesses want a great-looking marketing site &lt;strong&gt;plus&lt;/strong&gt; one interactive piece — a booking flow, a quote calculator, a client portal. That's a website with a focused app feature, not a full SaaS. Recognising this keeps the budget sane: build the polished site, and add only the interactive piece you genuinely need.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to bring to a developer
&lt;/h2&gt;

&lt;p&gt;Describe it in user terms, not tech terms: who visits and the one thing they're here to do; whether users need accounts; whether anything must be saved or tracked by users; whether you'll update content or it rarely changes. Answer those four and any good developer can tell you instantly whether you're looking at a website, a web app, or the practical middle ground — and roughly what that means for time and cost.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Not sure whether you need a website, a web app, or a site with one smart feature? Tell me what your users need to do and I'll give you a straight answer — then build it clean on Next.js. &lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>startup</category>
      <category>beginners</category>
      <category>business</category>
    </item>
    <item>
      <title>From Spreadsheet Chaos to Automation: A Practical Guide for Small Businesses</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Tue, 02 Jun 2026 17:45:31 +0000</pubDate>
      <link>https://dev.to/pante5ter/from-spreadsheet-chaos-to-automation-a-practical-guide-for-small-businesses-1djg</link>
      <guid>https://dev.to/pante5ter/from-spreadsheet-chaos-to-automation-a-practical-guide-for-small-businesses-1djg</guid>
      <description>&lt;p&gt;Most small businesses don't need "AI" or a big software project. They need to stop copying data between a form, a spreadsheet, an email and an invoice by hand. That's automation — and done right, it pays for itself in saved hours within weeks. Here's how to approach it without overcomplicating things.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Find the tasks actually worth automating
&lt;/h2&gt;

&lt;p&gt;Good candidates share three traits: &lt;strong&gt;repetitive&lt;/strong&gt; (done the same way, often), &lt;strong&gt;rule-based&lt;/strong&gt; ("if this, then that," little judgement), and &lt;strong&gt;annoying&lt;/strong&gt; (the work that drains energy and invites copy-paste mistakes). A quick exercise: for one week, jot down every task that made you think "a robot should do this." Tasks that move the same information from one place to another are almost always worth automating first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Map the flow before touching any tool
&lt;/h2&gt;

&lt;p&gt;Write the task as a sentence: &lt;em&gt;"When a customer submits the contact form, add them to the CRM, ping sales on Slack, and email them a confirmation."&lt;/em&gt; That sentence is your spec. Mapping it on paper first stops you from automating a broken process — and reveals the edge cases (what if the email is missing? what if they submit twice?).&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Pick the right level of tooling
&lt;/h2&gt;

&lt;p&gt;There are three tiers, and most businesses start too high or too low.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No-code (Make, Zapier, n8n):&lt;/strong&gt; perfect for connecting apps you already use — form to CRM to email. Fast to build, easy to change. Start here for standard integrations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No-code with a developer's help:&lt;/strong&gt; when the logic gets branchy or hits API limits, a developer building inside Make/n8n keeps it maintainable instead of a fragile spaghetti of steps.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom code:&lt;/strong&gt; when the workflow is core to your business, high-volume, or needs logic the no-code tools can't express cleanly. More upfront work, but you own it and it won't break when a tool changes its pricing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The honest rule: &lt;strong&gt;start no-code, graduate to custom only when the no-code version starts fighting you.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Automate one thing, prove it, then expand
&lt;/h2&gt;

&lt;p&gt;The mistake is trying to automate everything at once. Pick the single most annoying repetitive task, automate just that, run it for a week, and confirm it actually saves time and doesn't drop data. One reliable automation builds trust — and frees the time you'll use to build the next one.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Build in safety nets
&lt;/h2&gt;

&lt;p&gt;Automation that fails silently is worse than no automation. Whatever you build should &lt;strong&gt;log what it did&lt;/strong&gt;, &lt;strong&gt;notify a human on failure&lt;/strong&gt; (a Slack alert beats discovering a week of lost leads), and be &lt;strong&gt;idempotent where money or records are involved&lt;/strong&gt; (running twice shouldn't create two invoices). These are the parts people skip and regret — and what separates a hack that works until it doesn't from a system you can rely on.&lt;/p&gt;

&lt;h2&gt;
  
  
  What good automation feels like
&lt;/h2&gt;

&lt;p&gt;You stop being the integration layer between your tools. Data arrives where it needs to be, the right people get pinged, and you find out &lt;em&gt;immediately&lt;/em&gt; when something needs a human. The goal isn't to remove people — it's to remove the copy-paste so people can do the work only they can do.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Drowning in repetitive tasks and not sure whether to go no-code or custom? I help small businesses build automations that are reliable, not fragile — &lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>productivity</category>
      <category>nocode</category>
      <category>webdev</category>
    </item>
    <item>
      <title>5 Signs Your Business Is Ready for an AI Assistant (and 3 Signs It Isn't)</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Tue, 02 Jun 2026 17:43:39 +0000</pubDate>
      <link>https://dev.to/pante5ter/5-signs-your-business-is-ready-for-an-ai-assistant-and-3-signs-it-isnt-39ok</link>
      <guid>https://dev.to/pante5ter/5-signs-your-business-is-ready-for-an-ai-assistant-and-3-signs-it-isnt-39ok</guid>
      <description>&lt;p&gt;A custom AI assistant — one that answers from &lt;em&gt;your&lt;/em&gt; documents, products and policies — can quietly save a team hours a week. It can also be an expensive toy that nobody uses. The difference isn't the technology; it's whether your situation actually calls for it. Here's how to tell.&lt;/p&gt;

&lt;h2&gt;
  
  
  5 signs you're ready
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. You answer the same questions over and over
&lt;/h3&gt;

&lt;p&gt;If your team retypes the same answers about pricing, hours, policies, or "how do I...", that repetition is exactly what an assistant absorbs. The more repetitive the questions, the higher the payoff.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. The answers live in documents you trust
&lt;/h3&gt;

&lt;p&gt;An assistant is only as good as its source material. If you have a knowledge base, product docs, FAQs or past tickets that are reasonably accurate, you have fuel. Good sources in, good answers out.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. A wrong answer is annoying, not dangerous
&lt;/h3&gt;

&lt;p&gt;The best first use cases are forgiving — support triage, internal "where's the doc on X", drafting first replies. If a rare mistake means a follow-up message rather than a lawsuit, you're in safe territory.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. You have volume
&lt;/h3&gt;

&lt;p&gt;Ten questions a week doesn't justify a build. Hundreds of repetitive interactions a week does — that's where automation pays for itself instead of being a novelty.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Someone will own it
&lt;/h3&gt;

&lt;p&gt;An assistant needs a human who keeps its sources current. If one person owns "is the knowledge up to date," it stays useful. If nobody owns it, it rots.&lt;/p&gt;

&lt;h2&gt;
  
  
  3 signs it isn't time yet
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Your information is scattered and contradictory
&lt;/h3&gt;

&lt;p&gt;If the "source of truth" is three Google Docs, a Slack thread and someone's memory — and they disagree — an assistant will confidently repeat the contradictions. &lt;strong&gt;Fix the knowledge base first;&lt;/strong&gt; that's valuable on its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Every answer needs human judgement
&lt;/h3&gt;

&lt;p&gt;If the real work is nuanced negotiation or high-stakes decisions, an assistant can &lt;em&gt;draft&lt;/em&gt; but shouldn't &lt;em&gt;decide&lt;/em&gt;. If there's no safe "draft and a human reviews" mode, it's early.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. You're doing it because it's trendy
&lt;/h3&gt;

&lt;p&gt;"We should have AI" is not a use case. If you can't name the specific questions it will answer or the hours it will save, the honest move is to wait until you can.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do if it's too early
&lt;/h2&gt;

&lt;p&gt;You're rarely "not ready" — you're usually one step away. Scattered info? Consolidate your FAQs and docs into one trusted place — that helps your team today and becomes the assistant's fuel tomorrow. Low volume? Start with a simpler automation and revisit when volume grows. Just curious? Pilot one narrow, forgiving use case before committing to anything broad.&lt;/p&gt;

&lt;h2&gt;
  
  
  The honest bottom line
&lt;/h2&gt;

&lt;p&gt;A good AI assistant is grounded in your real content, says "I don't know" instead of inventing answers, and earns its keep on repetitive, high-volume, low-risk work. Built that way, it's one of the highest-ROI things a small team can add. Built on hype, it's shelfware.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Want a straight answer on whether an AI assistant fits your business — and one built to cite your real content instead of hallucinating? That's exactly what I do — &lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>startup</category>
      <category>productivity</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Supabase vs Firebase for Your MVP: A Practical Pick Guide</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Tue, 02 Jun 2026 17:36:02 +0000</pubDate>
      <link>https://dev.to/pante5ter/supabase-vs-firebase-for-your-mvp-a-practical-pick-guide-4pnk</link>
      <guid>https://dev.to/pante5ter/supabase-vs-firebase-for-your-mvp-a-practical-pick-guide-4pnk</guid>
      <description>&lt;p&gt;Both Supabase and Firebase let you ship a working product without building a backend from scratch. Both have generous free tiers. So the question isn't "which is better" — it's "which fits &lt;em&gt;this&lt;/em&gt; MVP." Here's how I decide.&lt;/p&gt;

&lt;h2&gt;
  
  
  The one difference that drives everything: the data model
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Firebase (Firestore)&lt;/strong&gt; is a NoSQL document store — you think in collections and documents. Great for fast writes, real-time updates, and naturally nested data. &lt;strong&gt;Supabase&lt;/strong&gt; is Postgres — a real relational database. You think in tables, rows, and relationships, and you can write SQL.&lt;/p&gt;

&lt;p&gt;Everything else flows from this. If your data has clear relationships (users have orders, orders have items), Postgres keeps your data honest with constraints and joins. If your data is loose and document-shaped, Firestore fits comfortably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Auth, storage, and the "batteries included" parts
&lt;/h2&gt;

&lt;p&gt;Both give you authentication, file storage, and serverless functions out of the box, so neither blocks you on day one. Firebase auth is extremely mature and plugs into the Google ecosystem. Supabase auth is built on Postgres with Row Level Security, so your access rules live next to your data as policies. For an MVP both are more than enough — auth is rarely the deciding factor.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pricing shape (not exact numbers — those change)
&lt;/h2&gt;

&lt;p&gt;Don't compare sticker prices; compare the &lt;em&gt;shape&lt;/em&gt; of how you pay. &lt;strong&gt;Firestore&lt;/strong&gt; bills heavily by reads, writes, and deletes — apps that read the same data a lot can see costs climb in surprising ways at scale. &lt;strong&gt;Supabase&lt;/strong&gt; bills more like traditional hosting (compute, storage, bandwidth), which is easier to predict. For an early MVP both are cheap or free; the shape matters most as you grow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vendor lock-in
&lt;/h2&gt;

&lt;p&gt;This is where I lean Supabase for most clients. Because it's Postgres underneath, you can take your database and leave — export it, self-host it, or move to any Postgres provider. Firestore's data model is proprietary; migrating off it later is real work. If owning your data matters, that's a strong point for Supabase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-time and offline
&lt;/h2&gt;

&lt;p&gt;Firebase has best-in-class offline support and real-time sync — if you're building a mobile app that must work on a subway, that's a genuine edge. Supabase has real-time subscriptions too, and they're good, but Firebase's offline story for mobile is still ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  My rule of thumb
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pick Supabase if:&lt;/strong&gt; your data is relational, you value SQL and predictable pricing, you want to avoid lock-in, or your team knows Postgres. This covers most web SaaS MVPs. &lt;strong&gt;Pick Firebase if:&lt;/strong&gt; you're building mobile-first with heavy offline needs, your data is document-shaped, or you're already deep in Google's ecosystem.&lt;/p&gt;

&lt;p&gt;Either way, the worst choice is &lt;em&gt;agonising&lt;/em&gt; over it. Both will get your MVP in front of users this month — the only thing that matters at the MVP stage.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Deciding on a stack, or want your MVP built fast and clean on Next.js + Supabase? I help founders ship a real product instead of a prototype — &lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>supabase</category>
      <category>firebase</category>
      <category>webdev</category>
      <category>database</category>
    </item>
    <item>
      <title>"It Works on My Machine" — Why Deploys Break and How to Stop It</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Tue, 02 Jun 2026 16:58:42 +0000</pubDate>
      <link>https://dev.to/pante5ter/it-works-on-my-machine-why-deploys-break-and-how-to-stop-it-5bgo</link>
      <guid>https://dev.to/pante5ter/it-works-on-my-machine-why-deploys-break-and-how-to-stop-it-5bgo</guid>
      <description>&lt;p&gt;The app runs perfectly on your laptop. You push to production and it white-screens, 500s, or won't even build. This is one of the most common — and most fixable — categories of bug. The cause is almost always a difference between your machine and the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Missing environment variables
&lt;/h2&gt;

&lt;p&gt;Number one by a wide margin. Your local &lt;code&gt;.env&lt;/code&gt; has the API keys and database URLs; production doesn't, because &lt;code&gt;.env&lt;/code&gt; isn't committed (correctly). Locally the app finds its config; in production it gets &lt;code&gt;undefined&lt;/code&gt; and crashes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; keep a committed &lt;code&gt;.env.example&lt;/code&gt; listing every variable (names only, no secrets). Before deploying, confirm every variable in it is set in your host's dashboard. Most "works locally, breaks in prod" tickets end here.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Build-time vs runtime confusion
&lt;/h2&gt;

&lt;p&gt;In frameworks like Next.js, some code runs at build time and some per request. A value that exists at runtime locally might be needed at build time in production — or a variable not exposed to the browser is read in client code and comes back empty.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; know which code runs where. Public values the browser needs must be prefixed correctly (e.g. &lt;code&gt;NEXT_PUBLIC_&lt;/code&gt;). Secrets must never be read in client components.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Case sensitivity
&lt;/h2&gt;

&lt;p&gt;Your laptop (macOS, Windows) is usually case-insensitive: &lt;code&gt;import Button from './button'&lt;/code&gt; finds &lt;code&gt;Button.tsx&lt;/code&gt;. Production runs Linux, which is case-sensitive — and that import fails the build.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; match the exact case of filenames in every import. A green local build and a red production build with "module not found" is almost always a case mismatch.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Dependency drift
&lt;/h2&gt;

&lt;p&gt;Locally a package is cached at the version that worked. Production installs fresh from your lockfile — or without one, gets a newer, slightly different version.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; commit your lockfile and make sure CI installs from it. "It built last week and not today, with no code change" is the signature of dependency drift.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Node version mismatch
&lt;/h2&gt;

&lt;p&gt;You're on Node 20 locally; the host defaults to Node 18. A feature you rely on isn't there, and the build fails on something that looks unrelated.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; pin the Node version in &lt;code&gt;package.json&lt;/code&gt; (&lt;code&gt;engines&lt;/code&gt;) and in your host's settings. Make the two match.&lt;/p&gt;

&lt;h2&gt;
  
  
  A deploy checklist that makes this boring
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Every variable in &lt;code&gt;.env.example&lt;/code&gt; is set in production.&lt;/li&gt;
&lt;li&gt;The project builds from a clean clone, not just incrementally.&lt;/li&gt;
&lt;li&gt;Import paths match filenames exactly (case included).&lt;/li&gt;
&lt;li&gt;The lockfile is committed and used.&lt;/li&gt;
&lt;li&gt;Node versions match locally and in the host.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Fix the root cause once — usually env vars and case sensitivity — and "works on my machine" stops being a phrase you dread.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Got a build that runs locally but won't deploy? That's a same-day fix — I find the exact mismatch, get it green, and tell you what went wrong so it stays fixed. &lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>devops</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Your React App Feels Slow? 7 Real Causes (and How to Fix Each)</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Tue, 02 Jun 2026 16:56:41 +0000</pubDate>
      <link>https://dev.to/pante5ter/your-react-app-feels-slow-7-real-causes-and-how-to-fix-each-oll</link>
      <guid>https://dev.to/pante5ter/your-react-app-feels-slow-7-real-causes-and-how-to-fix-each-oll</guid>
      <description>&lt;p&gt;"It works, but it feels sluggish." That's one of the most common things clients say about a React or Next.js app — and almost always, the slowness comes down to a handful of fixable causes. Here are the seven I run into most, with the concrete fix for each.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Unnecessary re-renders
&lt;/h2&gt;

&lt;p&gt;The single most common culprit. A parent re-renders, and every child re-renders with it — even the ones whose props never changed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to spot it:&lt;/strong&gt; open React DevTools, enable "Highlight updates when components render," and click around. If half the screen flashes when you type into one input, you have a re-render problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; wrap pure children in &lt;code&gt;React.memo&lt;/code&gt;, stabilise callbacks with &lt;code&gt;useCallback&lt;/code&gt;, memoise derived values with &lt;code&gt;useMemo&lt;/code&gt;. Don't sprinkle these everywhere — measure first, then memoise the components that actually re-render hot.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. State that lives too high
&lt;/h2&gt;

&lt;p&gt;When you keep form state at the top of a large tree, every keystroke re-renders everything below it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; push state down to the smallest component that needs it. For genuinely global state (auth, theme, cart), use a focused store like Zustand and subscribe to one slice, so only the components using that slice re-render.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Oversized JavaScript bundles
&lt;/h2&gt;

&lt;p&gt;If your app ships 1.5 MB of JS before anything is interactive, no micro-optimisation saves the first impression.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; code-split by route and lazy-load heavy components with &lt;code&gt;next/dynamic&lt;/code&gt; or &lt;code&gt;React.lazy&lt;/code&gt;. Audit the bundle and look for accidental imports — pulling one helper from a giant library often drags the whole library in.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Images shipped at full size
&lt;/h2&gt;

&lt;p&gt;A hero "image" that's a 4000px, 3 MB PNG tanks your Largest Contentful Paint on mobile every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; use &lt;code&gt;next/image&lt;/code&gt; so images are resized, served in modern formats (WebP/AVIF), and lazy-loaded below the fold. Set explicit width/height to avoid layout shift.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Blocking data fetching
&lt;/h2&gt;

&lt;p&gt;If a page waits for one slow API call before rendering anything, users stare at a blank screen.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; render the shell immediately and stream or progressively load data. Fetch on the server where it makes sense, cache aggressively, and use Suspense or skeletons so the page feels alive.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Effects that fire too often
&lt;/h2&gt;

&lt;p&gt;A &lt;code&gt;useEffect&lt;/code&gt; with the wrong dependency array can run on every render — re-fetching, re-subscribing, or looping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; get the dependency array right, debounce expensive effects (like search-as-you-type), and clean up subscriptions in the return function.&lt;/p&gt;

&lt;h2&gt;
  
  
  7. Doing too much on the main thread
&lt;/h2&gt;

&lt;p&gt;Heavy synchronous work — parsing big JSON, sorting thousands of rows — blocks the thread that also handles clicks and scrolls. The result is jank.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; move heavy work to a Web Worker, virtualise long lists so you only render what's on screen, and memoise expensive computations. Often the real win is not doing the work at all — paginate or filter on the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach it in order
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Measure first&lt;/strong&gt; — Lighthouse for the page-level picture, React DevTools Profiler for re-renders.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fix the biggest lever first&lt;/strong&gt; — usually bundle size or images for first load, re-renders for interaction speed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Re-measure&lt;/strong&gt; — confirm the number moved before moving on.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Most "slow app" complaints are solved by two or three of these — often a single focused afternoon.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Stuck on a React or Next.js app that feels slow and not sure which cause it is? I profile it, fix the highest-impact issues, and hand you the before/after numbers — &lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>performance</category>
      <category>webdev</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>Hydration Errors in Next.js: What They Mean and How to Fix Them for Good</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Tue, 02 Jun 2026 13:24:27 +0000</pubDate>
      <link>https://dev.to/pante5ter/hydration-errors-in-nextjs-what-they-mean-and-how-to-fix-them-for-good-1545</link>
      <guid>https://dev.to/pante5ter/hydration-errors-in-nextjs-what-they-mean-and-how-to-fix-them-for-good-1545</guid>
      <description>&lt;p&gt;Few errors waste more time than a hydration mismatch. The app &lt;em&gt;mostly&lt;/em&gt; works, the console screams "Text content does not match server-rendered HTML," and the cause is rarely where you're looking. Here's what's actually happening and how to fix it permanently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hydration is (in one paragraph)
&lt;/h2&gt;

&lt;p&gt;Next.js renders your page to HTML on the server and sends it down so the user sees content fast. Then React "hydrates" that HTML in the browser — it re-runs your components and attaches event handlers, expecting the output to &lt;strong&gt;match&lt;/strong&gt; the HTML the server already produced. A hydration error means the browser render and the server render disagreed. React notices, throws away the mismatched part, and re-renders on the client — which is slow and can cause flicker.&lt;/p&gt;

&lt;h2&gt;
  
  
  The usual culprits
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Time, dates, and random values
&lt;/h3&gt;

&lt;p&gt;The classic. The server renders the date at one moment; the browser renders it a few hundred milliseconds later — different text, instant mismatch. &lt;code&gt;Math.random()&lt;/code&gt; does the same.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; don't render time-sensitive or random values during SSR. Render a stable placeholder on the server and fill in the live value after mount (in &lt;code&gt;useEffect&lt;/code&gt;), or compute the value once on the server and pass it down as a fixed prop.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. window, localStorage, navigator
&lt;/h3&gt;

&lt;p&gt;These don't exist on the server. If a component reads &lt;code&gt;localStorage&lt;/code&gt; to decide what to render, the server (which has no &lt;code&gt;localStorage&lt;/code&gt;) renders one thing and the browser renders another.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; read browser-only APIs inside &lt;code&gt;useEffect&lt;/code&gt;, which only runs client-side. Render the same neutral output on both server and first client paint, then update after mount.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Invalid HTML nesting
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;div&lt;/code&gt; inside a &lt;code&gt;p&lt;/code&gt;, or a &lt;code&gt;p&lt;/code&gt; inside a &lt;code&gt;p&lt;/code&gt;, gets "corrected" by the browser's HTML parser — so the DOM the browser builds differs from what React expected. This one is sneaky because the code looks fine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; keep your markup valid. Don't nest block elements inside a paragraph; don't put a &lt;code&gt;div&lt;/code&gt; inside a &lt;code&gt;button&lt;/code&gt;. If a third-party component does this, that's often the real source.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Browser extensions
&lt;/h3&gt;

&lt;p&gt;Some extensions inject attributes or elements into the DOM before React hydrates (Grammarly is a frequent offender). The page is fine; the extension changed the HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; this one isn't your bug. Confirm by reproducing in an incognito window with extensions off. For inputs, &lt;code&gt;suppressHydrationWarning&lt;/code&gt; on the specific element is an acceptable, targeted escape hatch.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Conditionals based on client-only state
&lt;/h3&gt;

&lt;p&gt;Rendering a component only when &lt;code&gt;isLoggedIn&lt;/code&gt; is true, where &lt;code&gt;isLoggedIn&lt;/code&gt; comes from &lt;code&gt;localStorage&lt;/code&gt;, is the same problem dressed up — the server can't know the value, so it renders the wrong branch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; gate client-only UI behind a "mounted" flag, or load that state through something the server can read too (a cookie, for example).&lt;/p&gt;

&lt;h2&gt;
  
  
  The reliable pattern: the "mounted" gate
&lt;/h2&gt;

&lt;p&gt;For anything that legitimately differs between server and client, this small hook removes the whole class of errors:&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setMounted&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;setMounted&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[]);&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;mounted&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;lt;&lt;/span&gt;&lt;span class="nx"&gt;Placeholder&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// same on server + first paint&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;LiveThing&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                  &lt;span class="c1"&gt;// only after hydration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use it sparingly — overusing it means giving up SSR benefits — but for genuinely client-only widgets it's the clean fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to debug efficiently
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Read the diff.&lt;/strong&gt; React's error usually shows expected vs received text. That points straight at the offending value.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check incognito.&lt;/strong&gt; If it vanishes with extensions off, it's an extension, not you.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary-search the tree.&lt;/strong&gt; Comment out halves of the page until the warning disappears.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hydration errors feel mysterious, but they almost always reduce to one rule: &lt;strong&gt;the server and the first client render must produce identical HTML.&lt;/strong&gt; Once you internalise that, the fix for each case is obvious.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Fighting a hydration error or another Next.js bug that's eaten your afternoon? I fix React/Next.js bugs same-day, with a plain note on the root cause so it doesn't come back — &lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>react</category>
      <category>webdev</category>
      <category>javascript</category>
    </item>
    <item>
      <title>3 Reasons Your Web Scraper Breaks in Production (and How to Fix Each)</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Mon, 01 Jun 2026 16:29:39 +0000</pubDate>
      <link>https://dev.to/pante5ter/3-reasons-your-web-scraper-breaks-in-production-and-how-to-fix-each-2kj0</link>
      <guid>https://dev.to/pante5ter/3-reasons-your-web-scraper-breaks-in-production-and-how-to-fix-each-2kj0</guid>
      <description>&lt;p&gt;Most scrapers work great on your laptop and then quietly fall apart the moment they run unattended. The script that pulled 10,000 rows in a demo returns 12 rows at 3 a.m. and nobody notices for a week. After shipping a fair number of these for clients, the failure modes are almost always the same three. Here's how to make a scraper that survives real sites.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. No retries
&lt;/h2&gt;

&lt;p&gt;The single most common reason a scraper dies: one network timeout kills the entire run.&lt;/p&gt;

&lt;p&gt;Real sites are flaky. A request that succeeds 99% of the time will still fail several times across a 10,000-page job — and if a single failure throws an uncaught exception, you lose the whole run, not one row.&lt;/p&gt;

&lt;p&gt;The fix is retries with exponential backoff. Wrap each request, retry a few times with growing delays, and log what failed so you can inspect it later. You want to lose a row, not the job.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;retries&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="n"&gt;backoff&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="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;retries&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;TransientError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;e&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;attempt&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;retries&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="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;giving up on %s: %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;backoff&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;attempt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2. Hard-coded selectors with no fallback
&lt;/h2&gt;

&lt;p&gt;Sites change their markup constantly. A scraper built around &lt;code&gt;div.price-box &amp;gt; span.amount&lt;/code&gt; will silently return empty strings the day the site ships a redesign — and silent failure is the worst kind, because your pipeline keeps running on garbage data.&lt;/p&gt;

&lt;p&gt;Two things make this survivable: use resilient selectors (prefer stable attributes like &lt;code&gt;data-*&lt;/code&gt; or itemprops over deeply nested class chains), and validate what you extract. If a field that should always be present comes back empty, raise a clear error instead of writing a blank. A loud failure is a 5-minute fix; a silent one is a corrupted dataset.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. No rate-limit or proxy handling
&lt;/h2&gt;

&lt;p&gt;Hit a site too fast and you get blocked — IP ban, CAPTCHA wall, or throttling that quietly drops your success rate. A scraper with no pacing isn't faster, it's just banned sooner.&lt;/p&gt;

&lt;p&gt;Add human-like delays between requests, respect &lt;code&gt;robots.txt&lt;/code&gt; and any documented limits, and rotate proxies/user-agents for larger jobs. The goal is to keep collecting data steadily rather than burning your access in the first ten minutes.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern underneath all three
&lt;/h2&gt;

&lt;p&gt;Each fix is the same idea: &lt;strong&gt;assume the outside world is hostile and design for failure.&lt;/strong&gt; Retries handle flaky networks, validation handles changing markup, and pacing handles defensive servers. A scraper that does these three things runs unattended for months; one that skips them needs a babysitter.&lt;/p&gt;




&lt;p&gt;I build scrapers, automation and Telegram bots that hold up in production — clean, typed code you own. If you've got a scraping or automation job (or a scraper that keeps breaking), see my work here: &lt;strong&gt;&lt;a href="https://vengstudio-portfolio.vercel.app" rel="noopener noreferrer"&gt;https://vengstudio-portfolio.vercel.app&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;VENG STUDIO — code that comes alive.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>automation</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>webscraping</category>
    </item>
    <item>
      <title>How to stop your RAG assistant from hallucinating (a practical guide)</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Sat, 30 May 2026 18:32:23 +0000</pubDate>
      <link>https://dev.to/pante5ter/how-to-stop-your-rag-assistant-from-hallucinating-a-practical-guide-2imd</link>
      <guid>https://dev.to/pante5ter/how-to-stop-your-rag-assistant-from-hallucinating-a-practical-guide-2imd</guid>
      <description>&lt;p&gt;A RAG (retrieval-augmented generation) assistant is supposed to answer from &lt;em&gt;your&lt;/em&gt; documents, not from the model's imagination. But teams keep shipping bots that confidently invent prices, policies, and features that don't exist. The hallucination usually isn't the model "being creative" — it's a retrieval and prompting problem you can fix. Here's the checklist I actually use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hallucination is usually a retrieval failure, not a model failure
&lt;/h2&gt;

&lt;p&gt;If the right chunk never makes it into the context, the model fills the gap by guessing. So before blaming the LLM, ask: &lt;strong&gt;did retrieval even return the correct passage?&lt;/strong&gt; Most "the AI lied" bugs are really "we fed it the wrong context" bugs. Fix retrieval first; it's where the biggest wins are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Chunk for meaning, not for byte count
&lt;/h2&gt;

&lt;p&gt;Splitting documents every N characters cuts sentences in half and scatters one answer across chunks.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Split on &lt;strong&gt;semantic boundaries&lt;/strong&gt; — headings, sections, list items — not arbitrary lengths.&lt;/li&gt;
&lt;li&gt;Keep chunks focused: one idea per chunk retrieves far more accurately than a wall of mixed topics.&lt;/li&gt;
&lt;li&gt;Add a little &lt;strong&gt;overlap&lt;/strong&gt; so context isn't lost at the seams.&lt;/li&gt;
&lt;li&gt;Attach metadata (source, title, date) to every chunk — you'll need it for filtering and citations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Retrieve better than plain vector search
&lt;/h2&gt;

&lt;p&gt;Pure embedding search misses exact terms (product codes, names, numbers).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;hybrid search&lt;/strong&gt;: combine semantic (vector) with keyword (BM25) so both meaning and exact matches are covered.&lt;/li&gt;
&lt;li&gt;Add a &lt;strong&gt;reranker&lt;/strong&gt; to reorder the top candidates before they hit the prompt — it consistently lifts answer quality.&lt;/li&gt;
&lt;li&gt;Tune how many chunks you pass. Too few starves the model; too many buries the answer in noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Make "I don't know" a first-class answer
&lt;/h2&gt;

&lt;p&gt;This single instruction prevents most embarrassing hallucinations: tell the model to answer &lt;strong&gt;only&lt;/strong&gt; from the provided context, and to say it doesn't know when the context doesn't contain the answer.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the answer is not in the provided context, say you don't have that information — do not guess.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A bot that admits a gap is trustworthy. A bot that confidently makes something up costs you a customer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demand citations and ground every claim
&lt;/h2&gt;

&lt;p&gt;Have the model cite the source chunk for each statement. Two benefits: users can verify, and you can automatically flag answers where the cited text doesn't actually support the claim. If it can't cite, it shouldn't assert.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evaluate, don't vibe-check
&lt;/h2&gt;

&lt;p&gt;You can't improve what you don't measure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a small &lt;strong&gt;test set&lt;/strong&gt; of real questions with known correct answers.&lt;/li&gt;
&lt;li&gt;Track &lt;strong&gt;groundedness&lt;/strong&gt; (is the answer supported by retrieved context?) and &lt;strong&gt;retrieval hit rate&lt;/strong&gt; (did the right chunk show up?).&lt;/li&gt;
&lt;li&gt;Re-run it on every change to chunking, embeddings, or prompts so you catch regressions before users do.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A reliable default stack
&lt;/h2&gt;

&lt;p&gt;Clean, semantically chunked docs with metadata → hybrid retrieval + reranker → a strict "answer only from context, cite sources, admit unknowns" prompt → an eval set guarding the whole thing. Boring, measurable, and it stops the confident nonsense.&lt;/p&gt;




&lt;p&gt;Done right, a RAG assistant becomes the thing customers trust for accurate answers 24/7 instead of a liability. I build RAG assistants and AI automation that stay grounded in real data as a freelancer — you can see examples at &lt;strong&gt;&lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;&lt;/strong&gt;. Questions about retrieval or grounding? Drop them in the comments.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>rag</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Building a Telegram bot that takes payments: what actually matters</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Sat, 30 May 2026 18:31:04 +0000</pubDate>
      <link>https://dev.to/pante5ter/building-a-telegram-bot-that-takes-payments-what-actually-matters-4884</link>
      <guid>https://dev.to/pante5ter/building-a-telegram-bot-that-takes-payments-what-actually-matters-4884</guid>
      <description>&lt;p&gt;"Just add payments to the bot" sounds like a one-liner. In practice, the happy path is the easy 20% — the other 80% is the edge cases that decide whether you actually get paid and keep customers. Here's what actually matters when a Telegram bot handles money, learned from shipping a few of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two very different ways to charge
&lt;/h2&gt;

&lt;p&gt;There are two models, and picking the wrong one causes most of the pain:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Telegram's native payments&lt;/strong&gt; (&lt;code&gt;sendInvoice&lt;/code&gt; + a provider token like Stripe). The whole flow stays inside Telegram, the UX is excellent, and you get a clean &lt;code&gt;successful_payment&lt;/code&gt; update. Great for digital goods and simple checkouts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External payment link / your own gateway.&lt;/strong&gt; You generate a link, the user pays on a web page, and your backend gets a &lt;strong&gt;webhook&lt;/strong&gt;. More flexible (subscriptions, local providers, complex carts) but you own more of the plumbing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most "sell a product or a subscription" bots, native payments are the right default. Reach for external only when the provider or business model forces it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pre-checkout step is not optional
&lt;/h2&gt;

&lt;p&gt;With native payments, Telegram sends a &lt;code&gt;pre_checkout_query&lt;/code&gt; and &lt;strong&gt;you have ~10 seconds to answer it&lt;/strong&gt;. If you don't &lt;code&gt;answerPreCheckoutQuery(ok=true)&lt;/code&gt; in time, the payment fails — even though the user did nothing wrong.&lt;/p&gt;

&lt;p&gt;This is where you do final validation: is the item still in stock, is the price still valid, is the user allowed to buy. Approve only if everything checks out. Skipping real validation here is how people sell things they can't deliver.&lt;/p&gt;

&lt;h2&gt;
  
  
  Treat money events as untrusted until verified
&lt;/h2&gt;

&lt;p&gt;Two rules that save you from fraud and angry customers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Verify webhook signatures.&lt;/strong&gt; Anyone can POST to your webhook URL. If you act on an unsigned "payment succeeded" call, you'll ship goods for payments that never happened. Always verify the provider's signature before trusting the event.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make payment handling idempotent.&lt;/strong&gt; Networks retry. You &lt;em&gt;will&lt;/em&gt; receive the same &lt;code&gt;successful_payment&lt;/code&gt; / webhook twice. Store a unique payment ID and ignore duplicates, or you'll deliver (or refund) twice.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The database is the source of truth, not the chat
&lt;/h2&gt;

&lt;p&gt;A Telegram message can be missed, edited, or arrive out of order. Don't drive business logic off the conversation state alone. Persist every order with an explicit status — &lt;code&gt;pending → paid → fulfilled → refunded&lt;/code&gt; — and let the bot read from that. When a user writes "where's my order?", you answer from the database, not from memory.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plan for refunds and failures from day one
&lt;/h2&gt;

&lt;p&gt;The unglamorous parts customers judge you on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A clear message when a payment &lt;strong&gt;fails&lt;/strong&gt; (and an easy retry), not silence.&lt;/li&gt;
&lt;li&gt;A defined &lt;strong&gt;refund&lt;/strong&gt; path — Telegram supports refunds for native payments; wire it up before you need it.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;admin view&lt;/strong&gt;: who paid, what's unfulfilled, what errored. A bot that takes money but gives the owner no visibility is a support nightmare.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A sane minimum architecture
&lt;/h2&gt;

&lt;p&gt;Bot (webhook mode, not long polling for production) → a small backend that validates and writes to a database → payment provider webhooks landing on a &lt;strong&gt;separate, signature-verified&lt;/strong&gt; endpoint. Keep secrets in env vars, log every money event, and alert on failed payments. That's it — boring on purpose, because boring is what you want around money.&lt;/p&gt;




&lt;p&gt;None of this is hard individually; the value is doing all of it so nothing silently breaks once real money flows. I build Telegram bots with payments, databases and admin panels as a freelancer — you can see examples at &lt;strong&gt;&lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;&lt;/strong&gt;. Happy to answer implementation questions in the comments.&lt;/p&gt;

</description>
      <category>api</category>
      <category>backend</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How I get Next.js sites to load almost instantly — a practical checklist</title>
      <dc:creator>pante5ter</dc:creator>
      <pubDate>Sat, 30 May 2026 16:40:15 +0000</pubDate>
      <link>https://dev.to/pante5ter/how-i-get-nextjs-sites-to-load-almost-instantly-a-practical-checklist-3pf4</link>
      <guid>https://dev.to/pante5ter/how-i-get-nextjs-sites-to-load-almost-instantly-a-practical-checklist-3pf4</guid>
      <description>&lt;p&gt;Speed isn't a vanity metric. On real projects, shaving load time directly moves conversion and Google rankings — Core Web Vitals are a ranking signal, and users bounce before a slow page even paints. Here's the checklist I actually run through on Next.js builds, in the order that gives the biggest wins first.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Ship less JavaScript to the client
&lt;/h2&gt;

&lt;p&gt;The single biggest lever. Most "slow React site" problems are really "we hydrated 400KB of JS the user never needed" problems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Keep components as &lt;strong&gt;Server Components&lt;/strong&gt; by default (App Router). Only add &lt;code&gt;'use client'&lt;/code&gt; where you genuinely need state or browser APIs.&lt;/li&gt;
&lt;li&gt;Push &lt;code&gt;'use client'&lt;/code&gt; &lt;strong&gt;down the tree&lt;/strong&gt;, not up. A whole page doesn't need to be client just because one button is interactive.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;next/dynamic&lt;/code&gt; for anything heavy and below-the-fold (charts, editors, 3D, modals):
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;GalaxyScene&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;dynamic&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="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/GalaxyScene&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;m&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;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GalaxyScene&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;ssr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;loading&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="kc"&gt;null&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;
  
  
  2. Stop layout shift before it starts
&lt;/h2&gt;

&lt;p&gt;CLS is the easiest Vital to wreck and the easiest to fix.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Always give &lt;code&gt;next/image&lt;/code&gt; explicit &lt;code&gt;width&lt;/code&gt;/&lt;code&gt;height&lt;/code&gt; (or &lt;code&gt;fill&lt;/code&gt; + a sized container).&lt;/li&gt;
&lt;li&gt;Reserve space for anything async — ads, embeds, banners.&lt;/li&gt;
&lt;li&gt;Load fonts with &lt;code&gt;next/font&lt;/code&gt; so the swap doesn't reflow text:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Inter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/font/google&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;inter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Inter&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;subsets&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;latin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;swap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. Treat images like the heaviest thing on the page (they are)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;next/image&lt;/code&gt; — it gives you AVIF/WebP, correct sizing, and lazy loading for free.&lt;/li&gt;
&lt;li&gt;Mark the hero image &lt;code&gt;priority&lt;/code&gt; so it isn't lazy-loaded; lazy-load everything else.&lt;/li&gt;
&lt;li&gt;Serve dimensions that match the rendered size. A 4000px photo in a 400px slot is wasted bytes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Render on the server, cache aggressively
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Prefer static rendering / ISR for anything that isn't per-request personalized. A pre-rendered page paints almost instantly.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;fetch&lt;/code&gt; caching and &lt;code&gt;revalidate&lt;/code&gt; instead of refetching on every hit.&lt;/li&gt;
&lt;li&gt;Move third-party scripts to &lt;code&gt;next/script&lt;/code&gt; with &lt;code&gt;strategy="lazyOnload"&lt;/code&gt; so analytics and chat widgets don't block your main thread.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Measure on a throttled mobile, not your laptop
&lt;/h2&gt;

&lt;p&gt;Your machine on fiber lies to you. Run Lighthouse in mobile mode with CPU throttling, and watch the &lt;strong&gt;field data&lt;/strong&gt; in Search Console (CrUX) — that's what Google actually ranks on, not your local numbers.&lt;/p&gt;

&lt;p&gt;A useful habit: set a performance budget (e.g. &amp;lt; 150KB JS on first load) and let CI fail the build if a PR blows past it. It stops slow creep before it ships.&lt;/p&gt;




&lt;p&gt;None of this is exotic. It's just doing the boring things consistently — and the payoff is a site that feels instant, ranks better, and converts more.&lt;/p&gt;

&lt;p&gt;I build Next.js sites, Telegram bots and AI automation as a freelancer — if you want a fast, SEO-ready site, you can see my work at &lt;strong&gt;&lt;a href="https://vengstudio.online" rel="noopener noreferrer"&gt;vengstudio.online&lt;/a&gt;&lt;/strong&gt;. Happy to answer Next.js performance questions in the comments.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>nextjs</category>
      <category>performance</category>
      <category>react</category>
    </item>
  </channel>
</rss>
