<?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: qudrat ullah</title>
    <description>The latest articles on DEV Community by qudrat ullah (@qudratullahdev).</description>
    <link>https://dev.to/qudratullahdev</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%2F3728686%2F67a54c8a-720d-4dcc-ae85-7ed7d072a5fe.jpg</url>
      <title>DEV Community: qudrat ullah</title>
      <link>https://dev.to/qudratullahdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/qudratullahdev"/>
    <language>en</language>
    <item>
      <title>Beyond console.log: A Guide to Production-Ready Logging in Node.js</title>
      <dc:creator>qudrat ullah</dc:creator>
      <pubDate>Fri, 17 Apr 2026 16:00:27 +0000</pubDate>
      <link>https://dev.to/qudratullahdev/beyond-consolelog-a-guide-to-production-ready-logging-in-nodejs-4h5d</link>
      <guid>https://dev.to/qudratullahdev/beyond-consolelog-a-guide-to-production-ready-logging-in-nodejs-4h5d</guid>
      <description>&lt;p&gt;As developers, we all have a favorite debugging tool: &lt;code&gt;console.log&lt;/code&gt;. It is simple, it is fast, and it gets the job done when we are trying to figure out why a variable is &lt;code&gt;undefined&lt;/code&gt; on our local machine. But the habits we build in development can become liabilities in production. Relying on &lt;code&gt;console.log&lt;/code&gt; for a live application is like trying to find a specific grain of sand on a beach. It is inefficient, unstructured, and makes debugging real-world issues a nightmare.&lt;/p&gt;

&lt;p&gt;I have seen teams spend hours, sometimes days, sifting through messy, unsearchable log files, all because their logging strategy never matured beyond what they used for local development. Effective logging is not a feature you add at the end. It is a core part of a robust, maintainable, and observable system. Let’s explore how to level up from basic console statements to a professional logging setup that will save you time and headaches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why &lt;code&gt;console.log&lt;/code&gt; Is Not Enough for Production
&lt;/h2&gt;

&lt;p&gt;When your application is running on a server, handling requests from thousands of users, &lt;code&gt;console.log('User created')&lt;/code&gt; just does not cut it. Here is why it falls short:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. No Structure
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;console.log&lt;/code&gt; statement outputs a simple string. While easy for a human to read one line at a time, it is very difficult for a machine to parse. Imagine you want to find all log entries for a specific user, or only show errors that happened after a certain time. With plain text logs, you are stuck using complex regular expressions. This is slow and error-prone.&lt;/p&gt;

&lt;p&gt;Production logs should be structured, typically as JSON. This allows you to easily filter, search, and aggregate logs in a dedicated logging tool.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Before (console.log):&lt;/strong&gt; &lt;code&gt;User 123 failed to update profile.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;After (Structured Log):&lt;/strong&gt; &lt;code&gt;{"level":"error","time":1678886400000,"pid":456,"hostname":"server-1","userId":123,"msg":"Failed to update profile"}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. No Log Levels
&lt;/h3&gt;

&lt;p&gt;Not all log messages are equal. A message indicating the server has started is informational. A failed database connection is a critical error. &lt;code&gt;console.log&lt;/code&gt; has no concept of severity. While &lt;code&gt;console.warn&lt;/code&gt; and &lt;code&gt;console.error&lt;/code&gt; exist, they do not offer the granularity needed for a production system.&lt;/p&gt;

&lt;p&gt;Standard log levels include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;fatal&lt;/code&gt;&lt;/strong&gt;: The application is about to crash. A critical, service-ending event.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;error&lt;/code&gt;&lt;/strong&gt;: A serious error occurred, but the application can continue running (e.g., a failed API call to a third party).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;warn&lt;/code&gt;&lt;/strong&gt;: Something unexpected happened that is not an error but should be monitored (e.g., deprecated API usage).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;info&lt;/code&gt;&lt;/strong&gt;: Routine information about the application's operation (e.g., server started, user signed in).&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;debug&lt;/code&gt;&lt;/strong&gt;: Detailed information useful only for debugging, typically turned off in production.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;&lt;code&gt;trace&lt;/code&gt;&lt;/strong&gt;: Even more granular information, like detailed function call traces.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Using levels allows you to configure your logger to only output messages of a certain severity. In production, you might set the level to &lt;code&gt;info&lt;/code&gt;, while in development, you might set it to &lt;code&gt;debug&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Inflexible Output
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;console.log&lt;/code&gt; always writes to the standard output (&lt;code&gt;stdout&lt;/code&gt;). In a production environment, you need more control. You might want to write logs to a file, send them to a third-party logging service like Datadog or Logstash, or even suppress them entirely during tests.&lt;br&gt;
A proper logging library allows you to configure different destinations, called "transports" or "streams".&lt;/p&gt;
&lt;h2&gt;
  
  
  The Pillars of Good Logging
&lt;/h2&gt;

&lt;p&gt;To build a production-ready logging system, we need to focus on a few key principles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Structured Data:&lt;/strong&gt; Always log in a machine-readable format like JSON.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Log Levels:&lt;/strong&gt; Use severity levels to categorize your logs.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Context is King:&lt;/strong&gt; Every log entry should contain context to help you trace its origin. The most important piece of context is a unique request identifier.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Configurable Destinations:&lt;/strong&gt; Your application should not care where the logs go. The logging setup should handle routing them to the correct place based on the environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Choosing a Library: Pino for Performance
&lt;/h2&gt;

&lt;p&gt;While there are several great logging libraries for Node.js, such as Winston and Bunyan, my go-to choice for new projects is &lt;strong&gt;Pino&lt;/strong&gt;. It is incredibly fast and has very low overhead, which is important in a high-throughput Node.js application. It focuses on doing one thing well: emitting structured JSON logs.&lt;/p&gt;

&lt;p&gt;Let’s get started with a basic Pino setup.&lt;/p&gt;

&lt;p&gt;First, install it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;pino
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create a simple logger instance:&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;// logger.js&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pino&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;pino&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;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pino&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&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;LOG_LEVEL&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Default to 'info'&lt;/span&gt;
  &lt;span class="na"&gt;formatters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;level&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toUpperCase&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="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;pino&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stdTimeFunctions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isoTime&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this setup, we configure a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  The log &lt;code&gt;level&lt;/code&gt; is set from an environment variable, falling back to &lt;code&gt;info&lt;/code&gt;. This is crucial for controlling log verbosity across different environments.&lt;/li&gt;
&lt;li&gt;  We use a &lt;code&gt;formatter&lt;/code&gt; to make the level label uppercase for consistency.&lt;/li&gt;
&lt;li&gt;  We set a standard ISO timestamp.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now you can use this logger anywhere in your app:&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="nx"&gt;logger&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;./logger&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server is starting...&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warn&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;database&lt;/span&gt;&lt;span class="dl"&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;Connection is a bit slow.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Failed to connect to Redis&lt;/span&gt;&lt;span class="dl"&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;Redis connection error.&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;p&gt;Notice how we can pass an object as the first argument. Pino merges this object into the final JSON log line, which is the perfect way to add context.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Practical Example: Logging in an Express.js App
&lt;/h2&gt;

&lt;p&gt;Let's integrate our logger into a simple Express server. The goal is to automatically log every incoming request and ensure all logs generated while handling that request are tied together with a unique ID.&lt;/p&gt;

&lt;p&gt;We will use &lt;code&gt;pino-http&lt;/code&gt;, a companion library for Pino.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;express pino-http uuid
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's set up our server:&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;pinoHttp&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;pino-http&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;v4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uuidv4&lt;/span&gt; &lt;span class="p"&gt;}&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;uuid&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;logger&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;./logger&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="c1"&gt;// Add the pino-http middleware&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="nf"&gt;pinoHttp&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&gt;// Define a custom request ID generator&lt;/span&gt;
  &lt;span class="na"&gt;genReqId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;function &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&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;existingId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-request-id&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;existingId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;existingId&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;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuidv4&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-Request-Id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Set it on the response header&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// pino-http adds the logger to the request object&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;guest&lt;/span&gt;&lt;span class="dl"&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;User accessed the home page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello, world!&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="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/error&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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This is a simulated error!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;An error occurred on the /error route&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Something went wrong.&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="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="mi"&gt;3000&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="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running on http://localhost:3000&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run this server and hit the &lt;code&gt;/&lt;/code&gt; endpoint, you will see two log lines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; An &lt;code&gt;info&lt;/code&gt; log from our route handler.&lt;/li&gt;
&lt;li&gt; Another &lt;code&gt;info&lt;/code&gt; log that &lt;code&gt;pino-http&lt;/code&gt; automatically generates when the response is sent, including the status code and response time.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Both log lines will share the same &lt;code&gt;req.id&lt;/code&gt;, which is our unique request identifier. This is incredibly powerful. If a user reports an error, you can ask them for the &lt;code&gt;X-Request-Id&lt;/code&gt; from the response header and instantly find every single log associated with their request, even across multiple microservices if you pass the ID along.&lt;/p&gt;

&lt;h2&gt;
  
  
  Managing Logs in a Production Environment
&lt;/h2&gt;

&lt;p&gt;Generating logs is only half the battle. You also need a strategy for collecting, storing, and analyzing them.&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%2Ffn6ythqs389kd6sknzq5.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%2Ffn6ythqs389kd6sknzq5.png" alt="A diagram showing the flow of logs from a Node.js app, through a log agent, to a central logging service for analysis by a developer." width="800" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This diagram shows a typical production logging pipeline:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Application (&lt;code&gt;Node.js App&lt;/code&gt;)&lt;/strong&gt;: Your application writes JSON logs to &lt;code&gt;stdout&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Log Agent (&lt;code&gt;Log Agent on Server&lt;/code&gt;)&lt;/strong&gt;: A lightweight agent (like Fluentd or Vector) running on the same server collects these logs from &lt;code&gt;stdout&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Central Logging Service&lt;/strong&gt;: The agent forwards the logs to a centralized system like Elasticsearch, Datadog, or Logz.io.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Storage and Analysis&lt;/strong&gt;: The service stores, indexes, and provides a user interface (like Kibana) for searching, visualizing, and creating alerts from the log data.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach decouples your application from the logging backend. Your Node.js app's only job is to write structured logs to standard output. The rest is handled by the infrastructure, which is a key principle of the &lt;a href="https://12factor.net/logs" rel="noopener noreferrer"&gt;Twelve-Factor App&lt;/a&gt; methodology.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;graph TD
    A[Node.js App] -- JSON logs to stdout --&amp;gt; B(Log Agent on Server);
    B -- Ships logs --&amp;gt; C{Central Logging Service};
    C -- Stores &amp;amp; Indexes --&amp;gt; D[(Log Database)];
    E[Developer] -- Queries &amp;amp; Visualizes --&amp;gt; C;
    D -- Provides data --&amp;gt; C;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Best Practices and Common Pitfalls
&lt;/h2&gt;

&lt;p&gt;Finally, here are some hard-won lessons from years of managing production systems.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;DO log in JSON.&lt;/strong&gt; I cannot stress this enough. It is the foundation of modern observability.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;DO include a request ID&lt;/strong&gt; in every log entry related to a request.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DON'T log sensitive information.&lt;/strong&gt; Never log passwords, API keys, or personally identifiable information (PII). Use Pino's redaction features to automatically strip sensitive fields from your log objects.&lt;br&gt;
&lt;/p&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;pino&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; 
  &lt;span class="na"&gt;redact&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;password&lt;/span&gt;&lt;span class="dl"&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;user.email&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="nx"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Qudrat&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;secret@example.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// The email and password will be replaced with '[REDACTED]'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DO log errors with their stack traces.&lt;/strong&gt; The error message alone is often not enough. &lt;code&gt;logger.error({ err: myError }, 'A message')&lt;/code&gt; will automatically include the stack trace when you pass the error object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;DON'T be too noisy.&lt;/strong&gt; Logging has a cost, both in performance and in storage. Use the &lt;code&gt;info&lt;/code&gt; level for significant events, not for every single function call. Save verbose logging for the &lt;code&gt;debug&lt;/code&gt; level, which you can enable on demand.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moving beyond &lt;code&gt;console.log&lt;/code&gt; is a sign of a maturing developer. It shows you are thinking not just about making the code work, but about how it will be operated, monitored, and debugged in the real world. By embracing structured logging, you are building more resilient and maintainable applications, and your future self (and your team) will thank you for it.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi, I'm &lt;strong&gt;Qudrat Ullah&lt;/strong&gt;, an Engineering Lead with 10+ years building scalable systems across fintech, media, and enterprise. I write about Node.js, cloud infrastructure, AI, and engineering leadership.&lt;/p&gt;

&lt;p&gt;Find me online: &lt;a href="https://www.linkedin.com/in/qudratullah-me/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://qudratullah.net" rel="noopener noreferrer"&gt;qudratullah.net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you found this useful, share it with a fellow engineer or drop your thoughts in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://qudratullah.net/blog/beyond-consolelog-a-guide-to-production-ready-logging-in-nodejs" rel="noopener noreferrer"&gt;qudratullah.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>node</category>
      <category>logging</category>
      <category>observability</category>
      <category>pino</category>
    </item>
    <item>
      <title>From Vague to Valuable: A Practical Guide to Prompting LLMs - Generative AI</title>
      <dc:creator>qudrat ullah</dc:creator>
      <pubDate>Fri, 17 Apr 2026 15:39:20 +0000</pubDate>
      <link>https://dev.to/qudratullahdev/from-vague-to-valuable-a-practical-guide-to-prompting-llms-generative-ai-56ab</link>
      <guid>https://dev.to/qudratullahdev/from-vague-to-valuable-a-practical-guide-to-prompting-llms-generative-ai-56ab</guid>
      <description>&lt;h2&gt;
  
  
  Your First Superpower in Tech
&lt;/h2&gt;

&lt;p&gt;Have you ever tried to get help from an AI chatbot, like ChatGPT, and received a completely useless answer? It feels frustrating. You know it's powerful, but it doesn't seem to understand you.&lt;/p&gt;

&lt;p&gt;Think of a Large Language Model (LLM) as a brilliant intern. They have read almost every book and website in existence. They are incredibly fast and knowledgeable. But they are also very literal. They have no real-world experience and will do &lt;em&gt;exactly&lt;/em&gt; what you ask, even if it's not what you &lt;em&gt;meant&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Your instruction to this intern is called a "prompt". Learning to write good prompts is like learning a new language for communicating with computers. It is one of the most valuable skills you can build today, whether you are a developer, a student, or just curious about technology. It's a true superpower.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Core of a Good Prompt
&lt;/h2&gt;

&lt;p&gt;Getting a great result from an LLM isn't about secret tricks or magic words. It's about being clear and providing the right information. Let's break down the four key ingredients of a perfect prompt.&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%2Fevx43vcm8gb9oomkwxkb.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%2Fevx43vcm8gb9oomkwxkb.png" alt="A flowchart showing that a vague prompt leads to a poor result, while a good prompt, combining a specific task, context, persona, and format, leads to an excellent result." width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Be Specific and Clear
&lt;/h3&gt;

&lt;p&gt;Imagine walking into a coffee shop and saying, "Give me coffee." You might get a black filter coffee, an espresso, or a latte. It's a gamble. Instead, you say, "I'd like a large iced Americano with no sugar." Now you get exactly what you want.&lt;/p&gt;

&lt;p&gt;Prompts work the same way. Vague prompts lead to vague answers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Bad Prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Write code for a button."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is like asking for "coffee". What language? What does it look like? What does it do?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Good Prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Write the HTML and CSS code for a clickable button. The button's text should be 'Download Report'. It should have a blue background (#3498db), white text, rounded corners (5px), and a light gray border. When a user hovers over it, the background should change to a darker blue (#2980b9)."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;See the difference? We specified the language (HTML/CSS), the text, the colors, the shape, and the behavior. There is no room for guessing.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Provide Context
&lt;/h3&gt;

&lt;p&gt;The LLM does not know what you are working on or what you were thinking about five minutes ago. You have to provide all the necessary background information in your prompt.&lt;/p&gt;

&lt;p&gt;Think of it like asking a friend for directions. You wouldn't just ask, "How do I get to the library?" You'd say, "I'm currently at the corner of Main Street and Park Avenue. What's the quickest way to walk to the central library from here?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Bad Prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"How can I make this function faster?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The LLM has no idea what "this function" is.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A Good Prompt:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"I'm working on a Python project. I have the following function that searches for a user in a list of a million user objects. It's very slow. How can I make it faster? Here is the code:&lt;/p&gt;


&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;find_user_by_email&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;users_list&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;email&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;users_list&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="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;email&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;user&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br&gt;
"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By providing the code and explaining the problem (it's slow with a large list), you give the LLM the context it needs to provide a helpful answer, like suggesting a dictionary for faster lookups.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Define the Persona and Format
&lt;/h3&gt;

&lt;p&gt;One of the most powerful features of LLMs is that you can tell them &lt;em&gt;who to be&lt;/em&gt; and &lt;em&gt;how to answer&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Persona:&lt;/strong&gt; Ask the LLM to adopt a role. This helps shape the tone and style of the response.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  "Act as a senior software engineer conducting a code review."&lt;/li&gt;
&lt;li&gt;  "You are a friendly tutor explaining a complex topic to a beginner."&lt;/li&gt;
&lt;li&gt;  "Pretend you are a skeptical project manager and point out potential flaws in my plan."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Format:&lt;/strong&gt; Tell the LLM exactly how you want the output structured.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  "Provide the answer as a JSON object."&lt;/li&gt;
&lt;li&gt;  "Explain the steps in a numbered list."&lt;/li&gt;
&lt;li&gt;  "Create a markdown table comparing these two databases."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;A Good Prompt Combining Both:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Explain the concept of 'git merge' versus 'git rebase'. Act as a patient mentor talking to a junior developer. Use a simple analogy to explain each one. Finally, summarize the pros and cons of each in a markdown table."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This prompt tells the LLM its role (mentor), the target audience (junior developer), the content required (explanation, analogy), and the final output format (a markdown table). This level of detail almost guarantees a high-quality answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Iterate and Refine
&lt;/h3&gt;

&lt;p&gt;Your first prompt is often just the beginning of a conversation. Don't be discouraged if the first answer isn't perfect. Use it as a starting point and refine your request.&lt;/p&gt;

&lt;p&gt;Think of it like sculpting. You start with a block of clay and slowly shape it.&lt;/p&gt;

&lt;p&gt;A typical conversation might look like this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;You:&lt;/strong&gt; "Give me some ideas for a new mobile app."&lt;br&gt;
&lt;strong&gt;LLM:&lt;/strong&gt; (Gives a generic list: a to-do list app, a fitness tracker, etc.)&lt;br&gt;
&lt;strong&gt;You:&lt;/strong&gt; "Those are okay, but I want something more unique. Focus on apps for people who enjoy gardening."&lt;br&gt;
&lt;strong&gt;LLM:&lt;/strong&gt; (Gives better ideas: a plant identification app, a watering schedule tracker, a community for local gardeners.)&lt;br&gt;
&lt;strong&gt;You:&lt;/strong&gt; "I like the plant identification idea. Can you list the key features for an app like that? Present it as a bulleted list."&lt;/p&gt;

&lt;p&gt;Each follow-up prompt gets you closer to the perfect result.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Couple of Simple "Pro" Tricks
&lt;/h2&gt;

&lt;p&gt;Once you master the basics, you can try these slightly more advanced techniques.&lt;/p&gt;

&lt;h3&gt;
  
  
  Few-Shot Prompting: Show, Don't Just Tell
&lt;/h3&gt;

&lt;p&gt;Sometimes, the best way to get the format you want is to show the LLM a few examples. This is called "few-shot prompting".&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"I need to extract the main subject from these sentences. Follow the pattern below.&lt;/p&gt;

&lt;p&gt;Sentence: The quick brown fox jumps over the lazy dog.&lt;br&gt;
Subject: fox&lt;/p&gt;

&lt;p&gt;Sentence: My team is shipping a new feature tomorrow.&lt;br&gt;
Subject: team&lt;/p&gt;

&lt;p&gt;Sentence: Artificial intelligence is transforming the world.&lt;br&gt;
Subject:"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By providing examples, you train the model on the exact output you expect. It will almost certainly answer "Artificial intelligence".&lt;/p&gt;

&lt;h3&gt;
  
  
  Chain-of-Thought: Ask it to Think Step-by-Step
&lt;/h3&gt;

&lt;p&gt;For problems that require logic or calculation, you can ask the LLM to explain its reasoning process. This often leads to more accurate results because it forces the model to break the problem down. Simply add "Let's think step-by-step" to your prompt.&lt;/p&gt;

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

&lt;blockquote&gt;
&lt;p&gt;"I have 50 apples. I give 10 to my friend, then I buy 25 more. I then split the new total evenly among myself and 4 friends. How many apples does each person get? Let's think step-by-step."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The LLM will first calculate the intermediate steps before giving you the final answer, reducing the chance of a simple math error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;p&gt;Writing a good prompt is a skill, and like any skill, it gets better with practice. Don't worry about getting it perfect on the first try.&lt;/p&gt;

&lt;p&gt;Remember these key principles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Be Specific:&lt;/strong&gt; Avoid vague requests. Detail exactly what you need.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Give Context:&lt;/strong&gt; Provide all the necessary background information. The LLM knows nothing but what you tell it.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Assign a Persona and Format:&lt;/strong&gt; Tell the AI who to be and how to structure its answer.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Iterate:&lt;/strong&gt; Treat it as a conversation. Refine your prompts based on the answers you get.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Show, Don't Tell:&lt;/strong&gt; Use examples (few-shot) to guide the AI's output for complex formatting.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Think Step-by-Step:&lt;/strong&gt; For logic problems, ask the AI to show its work.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mastering this skill will not only help you get better answers from AI but also make you a clearer communicator and a more effective problem-solver. Now go ahead and give that brilliant intern some clear instructions!&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi, I'm &lt;strong&gt;Qudrat Ullah&lt;/strong&gt;, an Engineering Lead with 10+ years building scalable systems across fintech, media, and enterprise. I write about Node.js, cloud infrastructure, AI, and engineering leadership.&lt;/p&gt;

&lt;p&gt;Find me online: &lt;a href="https://www.linkedin.com/in/qudratullah-me/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://qudratullah.net" rel="noopener noreferrer"&gt;qudratullah.net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you found this useful, share it with a fellow engineer or drop your thoughts in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://qudratullah.net/blog/from-vague-to-valuable-a-practical-guide-to-prompting-llms" rel="noopener noreferrer"&gt;qudratullah.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>promptengineering</category>
      <category>llm</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Vector Databases Made Simple: Your First Step Into Modern Data Storage</title>
      <dc:creator>qudrat ullah</dc:creator>
      <pubDate>Fri, 17 Apr 2026 13:24:31 +0000</pubDate>
      <link>https://dev.to/qudratullahdev/vector-databases-made-simple-your-first-step-into-modern-data-storage-oo5</link>
      <guid>https://dev.to/qudratullahdev/vector-databases-made-simple-your-first-step-into-modern-data-storage-oo5</guid>
      <description>&lt;h2&gt;
  
  
  What Are Vector Databases?
&lt;/h2&gt;

&lt;p&gt;Imagine you're organizing your music collection. Instead of just sorting by artist name or genre, you could organize songs by how they "feel" - grouping similar vibes together. Vector databases work similarly, but with data.&lt;/p&gt;

&lt;p&gt;A vector database stores information as mathematical representations called vectors. Think of vectors as coordinates that describe the "essence" or "meaning" of your data. Just like GPS coordinates tell you where something is on Earth, vectors tell you where your data sits in a multi-dimensional space of meaning.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Should You Care About Vector Databases?
&lt;/h2&gt;

&lt;p&gt;Traditional databases are great for exact matches. If you search for "John Smith," you get exactly "John Smith." But what if you want to find "similar" things? What if you want to search for "happy songs" or "articles about cooking pasta"?&lt;/p&gt;

&lt;p&gt;This is where vector databases shine. They excel at:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Similarity search&lt;/strong&gt;: Finding items that are alike&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Semantic search&lt;/strong&gt;: Understanding meaning, not just keywords&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI applications&lt;/strong&gt;: Powering chatbots, recommendation systems, and more&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How Do Vector Databases Work?
&lt;/h2&gt;

&lt;p&gt;Let me explain with a simple analogy. Imagine you're describing people using only three numbers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Height (in inches)&lt;/li&gt;
&lt;li&gt;Age (in years) &lt;/li&gt;
&lt;li&gt;Income (in thousands)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So John might be [70, 25, 45] and Sarah might be [68, 27, 50]. These numbers are vectors. To find people similar to John, you'd look for vectors with numbers close to his.&lt;/p&gt;

&lt;p&gt;In real vector databases, instead of 3 numbers, you might have 384 or 1,536 numbers describing the "meaning" of text, images, or other data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your First Vector Database Example
&lt;/h2&gt;

&lt;p&gt;Let's build a simple example using Python and a popular vector database called Chroma. Don't worry if you're new to Python - I'll explain each step.&lt;/p&gt;

&lt;p&gt;First, install the required packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;chromadb sentence-transformers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create a basic vector database:&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;chromadb&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sentence_transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SentenceTransformer&lt;/span&gt;

&lt;span class="c1"&gt;# Create a vector database client
&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;chromadb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Create a collection (like a table in traditional databases)
&lt;/span&gt;&lt;span class="n"&gt;collection&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_collection&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;my_documents&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Some sample documents
&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I love pizza and pasta&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The weather is sunny today&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Python is a great programming language&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I enjoy Italian food very much&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;It&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s raining outside right now&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Add documents to our collection
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;collection&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="n"&gt;documents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;doc&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="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Documents added to vector database!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's search for similar documents:&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="c1"&gt;# Search for documents similar to a query
&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;query_texts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I like Italian cuisine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;n_results&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="c1"&gt;# Get top 2 similar results
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Similar documents:&lt;/span&gt;&lt;span class="sh"&gt;"&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;doc&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;documents&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;- &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run this code, it will find documents about Italian food, even though your search didn't use the exact words "pizza" or "pasta."&lt;/p&gt;

&lt;h2&gt;
  
  
  Popular Vector Database Options
&lt;/h2&gt;

&lt;p&gt;As a beginner, here are the most beginner-friendly options:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Chroma&lt;/strong&gt; (Best for Learning)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Easy to set up&lt;/li&gt;
&lt;li&gt;Works locally on your computer&lt;/li&gt;
&lt;li&gt;Great documentation&lt;/li&gt;
&lt;li&gt;Free to use&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Pinecone&lt;/strong&gt; (Best for Production)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Cloud-based (no setup required)&lt;/li&gt;
&lt;li&gt;Very fast&lt;/li&gt;
&lt;li&gt;Has a free tier&lt;/li&gt;
&lt;li&gt;Great for real applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Weaviate&lt;/strong&gt; (Best for Advanced Features)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Open source&lt;/li&gt;
&lt;li&gt;Lots of built-in features&lt;/li&gt;
&lt;li&gt;Can run locally or in the cloud&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Common Use Cases You'll See
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Chatbots and Q&amp;amp;A Systems&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When you ask ChatGPT a question, it uses vector databases to find relevant information from its training data.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Recommendation Systems&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Netflix uses similar technology to recommend movies you might like based on what you've watched.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Image Search&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Google Photos can find "pictures of dogs" even if you never tagged them as dogs.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Document Search&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Companies use vector databases to help employees find relevant documents, even with vague queries like "contract about software licensing."&lt;/p&gt;

&lt;h2&gt;
  
  
  Tips for Getting Started
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Start Small&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Begin with a few dozen documents. Don't try to build the next Google on day one.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Use Pre-trained Models&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Don't create your own vectors from scratch. Use models like &lt;code&gt;sentence-transformers&lt;/code&gt; that are already trained.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Test Your Searches&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Try different queries and see what results you get. This helps you understand how your vector database "thinks."&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Monitor Performance&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;As your database grows, searches might get slower. Most vector databases have settings to help with this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Common Beginner Mistakes to Avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mistake 1&lt;/strong&gt;: Using too many dimensions&lt;br&gt;
More dimensions aren't always better. Start with 384 or 768 dimensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 2&lt;/strong&gt;: Not preprocessing your data&lt;br&gt;
Clean your text data first - remove extra spaces, fix typos, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistake 3&lt;/strong&gt;: Expecting perfect results immediately&lt;br&gt;
Vector search is about similarity, not exact matches. Results improve as you fine-tune.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;p&gt;Once you're comfortable with basic vector databases, you can explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid search&lt;/strong&gt;: Combining vector search with traditional keyword search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fine-tuning&lt;/strong&gt;: Customizing models for your specific data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Production deployment&lt;/strong&gt;: Moving from local testing to real applications&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Vector databases store data as mathematical representations that capture meaning&lt;/li&gt;
&lt;li&gt;They excel at finding similar items, not just exact matches&lt;/li&gt;
&lt;li&gt;Start with simple tools like Chroma for learning&lt;/li&gt;
&lt;li&gt;Use pre-trained models instead of building from scratch&lt;/li&gt;
&lt;li&gt;Common applications include chatbots, recommendations, and semantic search&lt;/li&gt;
&lt;li&gt;Begin with small datasets and gradually scale up&lt;/li&gt;
&lt;li&gt;Vector databases are becoming essential for modern AI applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Vector databases might seem complex at first, but they're just tools for finding similar things. Start with the simple example above, experiment with different queries, and you'll quickly see their power. The future of search and AI heavily relies on this technology, so learning it now puts you ahead of the curve.&lt;/p&gt;

&lt;p&gt;If you want me to go ahead with this topic, feel free to tell me. I'll go deeper with real-world working application demos and how to do that step by step.&lt;/p&gt;

&lt;p&gt;Thank you.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi, I'm &lt;strong&gt;Qudrat Ullah&lt;/strong&gt;, an Engineering Lead with 10+ years building scalable systems across fintech, media, and enterprise. I write about Node.js, cloud infrastructure, AI, and engineering leadership.&lt;/p&gt;

&lt;p&gt;Find me online: &lt;a href="https://www.linkedin.com/in/qudratullah-me/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://qudratullah.net" rel="noopener noreferrer"&gt;qudratullah.net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you found this useful, share it with a fellow engineer or drop your thoughts in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://qudratullah.net/blog/vector-databases-made-simple-your-first-step-into-modern-data-storage" rel="noopener noreferrer"&gt;qudratullah.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>vectordatabases</category>
      <category>beginners</category>
      <category>python</category>
      <category>ai</category>
    </item>
    <item>
      <title>Build Your First AI Search in 30 Minutes: A Complete RAG Tutorial</title>
      <dc:creator>qudrat ullah</dc:creator>
      <pubDate>Thu, 16 Apr 2026 20:15:29 +0000</pubDate>
      <link>https://dev.to/qudratullahdev/build-your-first-ai-search-in-30-minutes-a-complete-rag-tutorial-28d9</link>
      <guid>https://dev.to/qudratullahdev/build-your-first-ai-search-in-30-minutes-a-complete-rag-tutorial-28d9</guid>
      <description>&lt;h2&gt;
  
  
  What is RAG and Why Should You Care?
&lt;/h2&gt;

&lt;p&gt;RAG stands for Retrieval-Augmented Generation. Think of it like having a super-smart assistant who can quickly search through your documents and then give you intelligent answers based on what they found.&lt;/p&gt;

&lt;p&gt;Imagine you have thousands of company documents, and instead of spending hours searching through them manually, you could just ask questions like "What's our vacation policy?" and get instant, accurate answers. That's exactly what RAG does.&lt;/p&gt;

&lt;p&gt;The "Retrieval" part finds relevant information, and the "Generation" part creates human-like responses using that information. It's like combining Google search with ChatGPT, but for your own data.&lt;/p&gt;

&lt;h2&gt;
  
  
  How RAG Works: The Simple Explanation
&lt;/h2&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%2Ff51y2npi9rjtdmm4h8p9.jpg" 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%2Ff51y2npi9rjtdmm4h8p9.jpg" alt="RAG workflow diagram showing three steps" width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RAG works in three simple steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Store&lt;/strong&gt;: Break your documents into small chunks and convert them into numbers (called embeddings) that computers understand&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Search&lt;/strong&gt;: When you ask a question, find the most relevant chunks from your stored data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Generate&lt;/strong&gt;: Feed those relevant chunks to an AI model (like GPT) to create a natural answer&lt;/li&gt;
&lt;/ol&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%2Fb7bsx71m77eu9u1v35dt.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%2Fb7bsx71m77eu9u1v35dt.png" alt="What are embeddings" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Think of it like organizing a massive library. Instead of browsing every book, you have a librarian who knows exactly where to find information and can summarize it for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Your First RAG System
&lt;/h2&gt;

&lt;p&gt;Let's build a simple RAG system that can answer questions about your documents. We'll use Python and some helpful libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Install Required Libraries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;langchain openai chromadb sentence-transformers
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Prepare Your Documents
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# documents.py
&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Our company offers 20 days of paid vacation per year. Employees can carry over up to 5 unused days to the next year.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The office hours are 9 AM to 6 PM, Monday through Friday. Remote work is allowed up to 3 days per week.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Health insurance covers 100% of employee premiums and 80% of family member premiums.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;The annual performance review happens in December. Salary increases are effective from January.&lt;/span&gt;&lt;span class="sh"&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: Create the RAG System
&lt;/h3&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%2Fht1jrsdwmq9e1wilscfc.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%2Fht1jrsdwmq9e1wilscfc.png" alt="RAG System Steps" width="800" height="458"&gt;&lt;/a&gt;&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="c1"&gt;# rag_system.py
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.text_splitter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;CharacterTextSplitter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.embeddings&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;HuggingFaceEmbeddings&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.vectorstores&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.llms&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.chains&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RetrievalQA&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;

&lt;span class="c1"&gt;# Set your OpenAI API key
&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;your-api-key-here&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SimpleRAG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Split documents into smaller chunks
&lt;/span&gt;        &lt;span class="n"&gt;text_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;CharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;texts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text_splitter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Create embeddings (convert text to numbers)
&lt;/span&gt;        &lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HuggingFaceEmbeddings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

        &lt;span class="c1"&gt;# Store in vector database
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Chroma&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_documents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;texts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Set up the question-answering chain
&lt;/span&gt;        &lt;span class="n"&gt;llm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temperature&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;qa_chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RetrievalQA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_chain_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;chain_type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stuff&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;retriever&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_retriever&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask_question&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;question&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;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;qa_chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Usage
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;

&lt;span class="n"&gt;rag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SimpleRAG&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;answer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask_question&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How many vacation days do I get?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;answer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Test Your RAG System
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test_rag.py
&lt;/span&gt;&lt;span class="n"&gt;questions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How many vacation days do I get?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Can I work from home?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;When do performance reviews happen?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;What does health insurance cover?&lt;/span&gt;&lt;span class="sh"&gt;"&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;question&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;questions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Q: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;rag&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ask_question&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Making It Better: Pro Tips
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Chunk Your Data Smartly
&lt;/h3&gt;

&lt;p&gt;Don't just split text randomly. Split by paragraphs, sentences, or logical sections:&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="c1"&gt;# Better text splitting
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.text_splitter&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;

&lt;span class="n"&gt;text_splitter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;RecursiveCharacterTextSplitter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;chunk_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;chunk_overlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;separators&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&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;h3&gt;
  
  
  2. Use Better Embeddings
&lt;/h3&gt;

&lt;p&gt;For better search results, use more powerful embedding models:&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;from&lt;/span&gt; &lt;span class="n"&gt;langchain.embeddings&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;OpenAIEmbeddings&lt;/span&gt;

&lt;span class="c1"&gt;# More accurate but costs money
&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;OpenAIEmbeddings&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;# Free alternative that works well
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;sentence_transformers&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SentenceTransformer&lt;/span&gt;
&lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HuggingFaceEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentence-transformers/all-MiniLM-L6-v2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Add Memory for Conversations
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.memory&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ConversationBufferMemory&lt;/span&gt;

&lt;span class="n"&gt;memory&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;ConversationBufferMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;memory_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;chat_history&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;qa_chain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RetrievalQA&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_chain_type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;retriever&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vectorstore&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;as_retriever&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
    &lt;span class="n"&gt;memory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;memory&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Common Mistakes to Avoid
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Mistake 1: Using chunks that are too big or too small&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Too big: AI gets confused with too much information&lt;/li&gt;
&lt;li&gt;Too small: Important context gets lost&lt;/li&gt;
&lt;li&gt;Sweet spot: 500-1500 characters per chunk&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Mistake 2: Not handling edge cases&lt;/strong&gt;&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;safe_ask_question&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Please ask a valid question.&lt;/span&gt;&lt;span class="sh"&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="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;qa_chain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;question&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;Exception&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;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sorry, I couldn&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;t process your question: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;str&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="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Mistake 3: Ignoring document quality&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Clean your documents first&lt;/li&gt;
&lt;li&gt;Remove unnecessary formatting&lt;/li&gt;
&lt;li&gt;Fix typos and inconsistencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Scaling Up: Next Steps
&lt;/h2&gt;

&lt;p&gt;Once you have a basic RAG system working, you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Add more document types&lt;/strong&gt;: PDFs, Word docs, web pages&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improve the UI&lt;/strong&gt;: Build a web interface with Streamlit or Flask&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use better databases&lt;/strong&gt;: PostgreSQL with pgvector for production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add authentication&lt;/strong&gt;: Secure your system for multiple users&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor performance&lt;/strong&gt;: Track which questions work well and which don't&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;RAG combines search and AI generation to answer questions about your documents&lt;/li&gt;
&lt;li&gt;You need three main components: document storage, similarity search, and text generation&lt;/li&gt;
&lt;li&gt;Start simple with basic libraries, then improve gradually&lt;/li&gt;
&lt;li&gt;Good document chunking is crucial for accurate results&lt;/li&gt;
&lt;li&gt;Test with real questions your users would ask&lt;/li&gt;
&lt;li&gt;Always handle errors gracefully in production systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;RAG isn't magic, but it's incredibly powerful when done right. Start with this simple example, experiment with your own documents, and gradually add more features. Before you know it, you'll have built an AI assistant that actually knows about your specific domain.&lt;/p&gt;

&lt;p&gt;The best part? This is just the beginning. RAG technology is evolving rapidly, and mastering the basics now will set you up for even more exciting developments ahead.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About the Author&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hi, I'm &lt;strong&gt;Qudrat Ullah&lt;/strong&gt;, an Engineering Lead with 10+ years building scalable systems across fintech, media, and enterprise. I write about Node.js, cloud infrastructure, AI, and engineering leadership.&lt;/p&gt;

&lt;p&gt;Find me online: &lt;a href="https://www.linkedin.com/in/qudratullah-me/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; · &lt;a href="https://qudratullah.net" rel="noopener noreferrer"&gt;qudratullah.net&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you found this useful, share it with a fellow engineer or drop your thoughts in the comments.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://qudratullah.net/blog/build-your-first-ai-search-in-30-minutes-a-complete-rag-tutorial" rel="noopener noreferrer"&gt;qudratullah.net&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rag</category>
      <category>ai</category>
      <category>python</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Generative AI vs Agentic AI</title>
      <dc:creator>qudrat ullah</dc:creator>
      <pubDate>Sun, 25 Jan 2026 15:32:52 +0000</pubDate>
      <link>https://dev.to/qudratullahdev/generative-ai-vs-agentic-ai-52e9</link>
      <guid>https://dev.to/qudratullahdev/generative-ai-vs-agentic-ai-52e9</guid>
      <description>&lt;h1&gt;
  
  
  Generative AI vs Agentic AI
&lt;/h1&gt;

&lt;p&gt;Artificial Intelligence is moving fast, and two terms are showing up everywhere:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Generative AI&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Agentic AI&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They sound similar, but they serve &lt;strong&gt;very different purposes&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This article explains the difference in a simple, practical way &lt;br&gt;
no buzzwords, no heavy theory.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🤖 What Is Generative AI?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Generative AI creates content.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You give it a prompt, and it generates an output such as text, images, or code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Think of Generative AI as a very smart content creator.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It responds to your request, and then it stops.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common examples
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ChatGPT writing text&lt;/li&gt;
&lt;li&gt;DALL·E generating images&lt;/li&gt;
&lt;li&gt;GitHub Copilot suggesting code&lt;/li&gt;
&lt;li&gt;AI summarising documents&lt;/li&gt;
&lt;li&gt;AI translating languages&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Simple example
&lt;/h3&gt;

&lt;p&gt;You ask:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Write a job description for a frontend developer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Generative AI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generates the text
&lt;/li&gt;
&lt;li&gt;Returns the response
&lt;/li&gt;
&lt;li&gt;Ends the interaction
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;✅ Task completed&lt;br&gt;&lt;br&gt;
❌ No follow-up&lt;br&gt;&lt;br&gt;
❌ No action taken  &lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ What Is Agentic AI?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Agentic AI doesn’t just generate responses, it takes action.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Instead of only answering, it can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Understand a goal&lt;/li&gt;
&lt;li&gt;Break it into steps&lt;/li&gt;
&lt;li&gt;Use tools&lt;/li&gt;
&lt;li&gt;Make decisions&lt;/li&gt;
&lt;li&gt;Execute tasks&lt;/li&gt;
&lt;li&gt;Repeat until the goal is achieved&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Think of Agentic AI as a digital worker.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Simple example
&lt;/h3&gt;

&lt;p&gt;You say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Find family-friendly events in London this weekend and email me the best five.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An Agentic AI might:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Search multiple event websites
&lt;/li&gt;
&lt;li&gt;Open and analyse pages
&lt;/li&gt;
&lt;li&gt;Extract dates, prices, and locations
&lt;/li&gt;
&lt;li&gt;Filter family-friendly events
&lt;/li&gt;
&lt;li&gt;Rank the best options
&lt;/li&gt;
&lt;li&gt;Send you an email
&lt;/li&gt;
&lt;li&gt;Store results for future use
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not just AI responding — this is &lt;strong&gt;AI working toward a goal&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔑 The Key Difference
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Generative AI answers questions.&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Agentic AI completes goals.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🧩 Side-by-Side Comparison
&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;Generative AI&lt;/th&gt;
&lt;th&gt;Agentic AI&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Generates text or images&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Makes decisions&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uses tools or APIs&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Executes actions&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Works autonomously&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Has goals&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  🧠 Everyday Analogy
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Generative AI&lt;/strong&gt; is like a skilled writer.&lt;br&gt;&lt;br&gt;
You ask a question, they write an answer, and the task ends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agentic AI&lt;/strong&gt; is like a personal assistant.&lt;br&gt;&lt;br&gt;
You give a goal, they figure out how to achieve it, and they get it done.&lt;/p&gt;

&lt;h2&gt;
  
  
  👨‍💻 Why This Matters for Developers
&lt;/h2&gt;

&lt;p&gt;If you’re building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Chatbots or writing tools → &lt;strong&gt;Generative AI&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Content generation platforms → &lt;strong&gt;Generative AI&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Automation systems → &lt;strong&gt;Agentic AI&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;AI assistants or workers → &lt;strong&gt;Agentic AI&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;End-to-end workflows → &lt;strong&gt;Agentic AI&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most real-world business value is shifting toward &lt;strong&gt;agentic systems&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Final Takeaway
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Generative AI creates content
&lt;/li&gt;
&lt;li&gt;Agentic AI achieves goals
&lt;/li&gt;
&lt;li&gt;One responds
&lt;/li&gt;
&lt;li&gt;The other acts
&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If Generative AI is the brain,&lt;br&gt;
Agentic AI is the brain &lt;strong&gt;plus hands&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🧠 One Last Question for You
&lt;/h2&gt;

&lt;p&gt;We’ve moved very quickly from:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AI that generates answers&lt;br&gt;
to&lt;br&gt;
AI that takes action&lt;br&gt;
The real question now is:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where should AI stop acting on our behalf?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Should AI agents be fully autonomous?&lt;/li&gt;
&lt;li&gt;Or should humans always stay in the loop?&lt;/li&gt;
&lt;li&gt;Where do &lt;em&gt;you&lt;/em&gt; draw the line between assistant and decision-maker?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👇&lt;br&gt;&lt;br&gt;
&lt;strong&gt;I’d love to hear your thoughts in the comments.&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How to Fix Chromium on Vercel: A Complete Guide to Solving the “libnspr4.so” Error</title>
      <dc:creator>qudrat ullah</dc:creator>
      <pubDate>Fri, 23 Jan 2026 14:26:47 +0000</pubDate>
      <link>https://dev.to/qudratullahdev/how-to-fix-chromium-on-vercel-a-complete-guide-to-solving-the-libnspr4so-error-4i9j</link>
      <guid>https://dev.to/qudratullahdev/how-to-fix-chromium-on-vercel-a-complete-guide-to-solving-the-libnspr4so-error-4i9j</guid>
      <description>&lt;p&gt;If you're deploying a Next.js app with Playwright and Chromium to Vercel, you've probably hit this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/tmp/chromium: error &lt;span class="k"&gt;while &lt;/span&gt;loading shared libraries: libnspr4.so: cannot open shared object file: No such file or directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works perfectly on your local machine but fails on Vercel. This is one of the most frustrating deployment issues developers face when working with headless browsers in serverless environments.&lt;/p&gt;

&lt;p&gt;After analyzing 50+ GitHub issues and testing multiple solutions, I discovered the root cause and the complete fix. Here's everything you need to know.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why It Works Locally But Fails on Vercel
&lt;/h2&gt;

&lt;p&gt;The fundamental difference between your local environment and Vercel's serverless environment causes this issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On your local machine:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;System libraries like &lt;code&gt;libnspr4.so&lt;/code&gt; and &lt;code&gt;libnss3.so&lt;/code&gt; are pre-installed&lt;/li&gt;
&lt;li&gt;You have full file system access&lt;/li&gt;
&lt;li&gt;Complete Node.js environment with all dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;On Vercel serverless:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimal Linux container with no system libraries&lt;/li&gt;
&lt;li&gt;Read-only file system except for the &lt;code&gt;/tmp&lt;/code&gt; directory&lt;/li&gt;
&lt;li&gt;Environment variables must exist before modules load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The critical issue:&lt;/strong&gt; The sparticuz/chromium package checks for &lt;code&gt;AWS_LAMBDA_JS_RUNTIME&lt;/code&gt; when the module imports, but if you set it in your code, it happens after the module is already loaded. This timing mismatch breaks everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Five Problems and Their Solutions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Problem 1: Wrong Package Choice
&lt;/h3&gt;

&lt;p&gt;Many developers try to use the full Playwright package, which doesn't work on Vercel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't use:&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="nl"&gt;"playwright"&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.39.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This package exceeds Vercel's 50MB limit and tries to download the browser at runtime, which fails in serverless environments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use instead:&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;"dependencies"&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="nl"&gt;"playwright-core"&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.39.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"@sparticuz/chromium"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^131.0.0"&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;&lt;strong&gt;Why this works:&lt;/strong&gt; &lt;code&gt;playwright-core&lt;/code&gt; is only about 5MB, and the sparticuz chromium package is about 40MB. Together they stay under Vercel's 50MB limit, and the chromium package provides a pre-bundled Chromium optimized for serverless environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 2: Environment Variable Timing
&lt;/h3&gt;

&lt;p&gt;This is where most developers get stuck. The timing of when environment variables are set matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you import the package, it immediately checks for &lt;code&gt;AWS_LAMBDA_JS_RUNTIME&lt;/code&gt;. But if you set it in your code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;chromiumPack&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@sparticuz/chromium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&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;AWS_LAMBDA_JS_RUNTIME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodejs22.x&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;p&gt;The module has already loaded and checked for the variable. It's too late.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set the environment variable in the Vercel Dashboard, not just in your code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's how:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to Vercel Dashboard&lt;/li&gt;
&lt;li&gt;Select your project&lt;/li&gt;
&lt;li&gt;Go to Settings → Environment Variables&lt;/li&gt;
&lt;li&gt;Add a new variable: &lt;code&gt;AWS_LAMBDA_JS_RUNTIME&lt;/code&gt; with value &lt;code&gt;nodejs22.x&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Apply to Production, Preview, and Development environments&lt;/li&gt;
&lt;li&gt;Redeploy your application&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why the Dashboard matters:&lt;/strong&gt; Environment variables set in the Vercel Dashboard are available before any modules load, which is exactly when the chromium package needs them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 3: Libraries Extracted But Not Found (The Critical Fix)
&lt;/h3&gt;

&lt;p&gt;This was the breakthrough that solved the issue. Even when libraries are extracted correctly, Chromium can't find them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Libraries are extracted to &lt;code&gt;/tmp/libnspr4.so&lt;/code&gt; and &lt;code&gt;/tmp/libnss3.so&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Chromium executable is in &lt;code&gt;/tmp/chromium&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;But Chromium can't find the libraries because the system doesn't know where to look&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Set &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; to the executable directory before launching the browser.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here's the code:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;executablePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromiumPack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executablePath&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;execDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// CRITICAL: Set LD_LIBRARY_PATH so Chromium can find libraries&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;LD_LIBRARY_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;execDir&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;Why this works:&lt;/strong&gt; &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; tells the Linux system loader where to find shared libraries. By setting it to the same directory where the Chromium executable and libraries are located, Chromium can successfully load the required libraries.&lt;/p&gt;

&lt;p&gt;This was the missing piece that most solutions don't mention. Without this, even with the correct environment variable, Chromium will fail to find the libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 4: Old Package Version
&lt;/h3&gt;

&lt;p&gt;Using an outdated version of the chromium package can cause compatibility issues with Node.js 22.x.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't use:&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="nl"&gt;"@sparticuz/chromium"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"119.0.2"&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;Use:&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="nl"&gt;"@sparticuz/chromium"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^131.0.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Version 131.0.0 has better support for Node.js 22.x and includes fixes for common serverless deployment issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem 5: Browser Freezing
&lt;/h3&gt;

&lt;p&gt;Some developers report that the browser freezes after creating a new page, even when everything else is configured correctly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The problem:&lt;/strong&gt; Browser freezes after "Creating new page" message appears.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Disable graphics mode before launching the browser:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;chromiumPack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setGraphicsMode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&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="nx"&gt;chromiumPack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setGraphicsMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Serverless environments don't have GPU support. Disabling graphics mode prevents the browser from trying to use GPU features that aren't available, which causes freezing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Working Solution
&lt;/h2&gt;

&lt;p&gt;Here's the complete implementation that works on Vercel:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Package.json Configuration
&lt;/h3&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;"dependencies"&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="nl"&gt;"@sparticuz/chromium"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^131.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"playwright-core"&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.39.0"&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="nl"&gt;"engines"&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="nl"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"22.x"&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;
  
  
  2. Next.js Configuration
&lt;/h3&gt;

&lt;p&gt;In your &lt;code&gt;next.config.ts&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextConfig&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="s2"&gt;next&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;nextConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;serverExternalPackages&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;playwright-core&lt;/span&gt;&lt;span class="dl"&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;@sparticuz/chromium&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="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;nextConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents Next.js from bundling these packages, which is essential for them to work correctly in the serverless environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Browser Launch Code
&lt;/h3&gt;

&lt;p&gt;Create a file &lt;code&gt;lib/browser.ts&lt;/code&gt; with this code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;chromium&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Browser&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="s2"&gt;playwright-core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;chromiumPack&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@sparticuz/chromium&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;browserInstance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Browser&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getBrowser&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Browser&lt;/span&gt;&lt;span class="o"&gt;&amp;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="nx"&gt;browserInstance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;browserInstance&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;isVercel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;!!&lt;/span&gt;&lt;span class="p"&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;VERCEL&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;VERCEL_ENV&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="nx"&gt;isVercel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Set runtime (fallback if not in Dashboard)&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;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;AWS_LAMBDA_JS_RUNTIME&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&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;AWS_LAMBDA_JS_RUNTIME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodejs22.x&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="c1"&gt;// Set graphics mode to prevent freezing&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;chromiumPack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setGraphicsMode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&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="nx"&gt;chromiumPack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setGraphicsMode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Get executable and set library path&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;executablePath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromiumPack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executablePath&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;execDir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dirname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// CRITICAL: Set LD_LIBRARY_PATH&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;LD_LIBRARY_PATH&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;execDir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;browserInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;chromiumPack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headless&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="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Local development&lt;/span&gt;
    &lt;span class="nx"&gt;browserInstance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;chromium&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;args&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="s2"&gt;--no-sandbox&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;headless&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="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;browserInstance&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;
  
  
  4. API Route Configuration
&lt;/h3&gt;

&lt;p&gt;In your API route file (e.g., &lt;code&gt;app/api/screenshot/route.ts&lt;/code&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&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;NextRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NextResponse&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="s2"&gt;next/server&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;getBrowser&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="s2"&gt;@/lib/browser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;nodejs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;maxDuration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamic&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;force-dynamic&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&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;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;getBrowser&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="c1"&gt;// Your screenshot code here&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;runtime = "nodejs"&lt;/code&gt; ensures the function runs in the Node.js runtime, and &lt;code&gt;maxDuration = 300&lt;/code&gt; gives you 5 minutes for screenshot operations (requires Vercel Pro plan).&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Vercel Dashboard Settings
&lt;/h3&gt;

&lt;p&gt;Before deploying, configure these settings in your Vercel Dashboard:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Required settings:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Environment Variable:&lt;/strong&gt; Add &lt;code&gt;AWS_LAMBDA_JS_RUNTIME&lt;/code&gt; with value &lt;code&gt;nodejs22.x&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Disable Fluid Compute:&lt;/strong&gt; Go to Settings → Functions → Fluid Compute → Turn OFF&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro Plan:&lt;/strong&gt; Required for 300-second timeouts (Hobby plan only allows 10 seconds)&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The Three Critical Fixes
&lt;/h2&gt;

&lt;p&gt;You need all three of these fixes for Chromium to work on Vercel:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Correct packages:&lt;/strong&gt; Use &lt;code&gt;playwright-core&lt;/code&gt; and sparticuz chromium version 131.0.0 or higher&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment variable:&lt;/strong&gt; Set &lt;code&gt;AWS_LAMBDA_JS_RUNTIME=nodejs22.x&lt;/code&gt; in Vercel Dashboard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Library path:&lt;/strong&gt; Set &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; to the executable directory in your code&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Missing any one of these will cause the deployment to fail. They work together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The environment variable tells the package which runtime to use&lt;/li&gt;
&lt;li&gt;The library path tells Chromium where to find the extracted libraries&lt;/li&gt;
&lt;li&gt;The correct packages ensure everything fits within Vercel's limits&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Quick Troubleshooting Checklist
&lt;/h2&gt;

&lt;p&gt;If you're still experiencing issues, check each of these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;code&gt;AWS_LAMBDA_JS_RUNTIME=nodejs22.x&lt;/code&gt; is set in Vercel Dashboard (not just in code)&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; is set in code before browser launch&lt;/li&gt;
&lt;li&gt;[ ] Using &lt;code&gt;playwright-core&lt;/code&gt; (not the full playwright package)&lt;/li&gt;
&lt;li&gt;[ ] Using sparticuz chromium version 131.0.0 or higher&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;setGraphicsMode(false)&lt;/code&gt; is called before launching the browser&lt;/li&gt;
&lt;li&gt;[ ] Fluid Compute is disabled in Vercel settings&lt;/li&gt;
&lt;li&gt;[ ] You're on Vercel Pro plan for extended timeouts&lt;/li&gt;
&lt;li&gt;[ ] &lt;code&gt;serverExternalPackages&lt;/code&gt; is configured in &lt;code&gt;next.config.ts&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why This Solution Works
&lt;/h2&gt;

&lt;p&gt;This solution addresses all the fundamental differences between local and serverless environments:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Package choice:&lt;/strong&gt; &lt;code&gt;playwright-core&lt;/code&gt; and the chromium package are designed for serverless and stay within size limits&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Environment variable:&lt;/strong&gt; Setting it in the Dashboard ensures it's available when modules load&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Library path:&lt;/strong&gt; &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; tells the system where to find shared libraries in the minimal serverless environment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;The critical insight:&lt;/strong&gt; Both the environment variable (for runtime detection) and the library path (for finding libraries) are required. Most solutions only mention one or the other, but you need both.&lt;/p&gt;

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

&lt;p&gt;Deploying Chromium on Vercel requires three essential components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The right packages (&lt;code&gt;playwright-core&lt;/code&gt; and the chromium package)&lt;/li&gt;
&lt;li&gt;Environment variable configured in Vercel Dashboard&lt;/li&gt;
&lt;li&gt;Library path set in your code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you have all three configured correctly, your screenshot application will work reliably on Vercel's serverless infrastructure. The key is understanding that serverless environments are fundamentally different from local development, and each difference requires a specific solution.&lt;/p&gt;

&lt;p&gt;This solution was discovered after analyzing 50+ GitHub issues and testing multiple approaches. The breakthrough was realizing that &lt;code&gt;LD_LIBRARY_PATH&lt;/code&gt; must be set to the executable directory, which most documentation doesn't mention.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Sparticuz/chromium" rel="noopener noreferrer"&gt;sparticuz/chromium GitHub repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.vercel.com/t/issue-with-puppeteer-and-chrome-aws-lambda-on-node-js-18-in-vercel/4229" rel="noopener noreferrer"&gt;Vercel Community Discussion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://playwright.dev" rel="noopener noreferrer"&gt;Playwright Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you found this helpful, feel free to share your experience or ask questions in the comments below!&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>serverless</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
