<?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: Tej Hagargi</title>
    <description>The latest articles on DEV Community by Tej Hagargi (@tejhagargi).</description>
    <link>https://dev.to/tejhagargi</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%2F3327574%2Fb71b119f-f2ac-404d-bb94-eb5d743f525f.jpg</url>
      <title>DEV Community: Tej Hagargi</title>
      <link>https://dev.to/tejhagargi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tejhagargi"/>
    <language>en</language>
    <item>
      <title>CRAG Implementation using TS</title>
      <dc:creator>Tej Hagargi</dc:creator>
      <pubDate>Sat, 16 May 2026 08:22:49 +0000</pubDate>
      <link>https://dev.to/tejhagargi/crag-implementation-using-ts-41ad</link>
      <guid>https://dev.to/tejhagargi/crag-implementation-using-ts-41ad</guid>
      <description>&lt;p&gt;import {&lt;br&gt;
  StateGraph,&lt;br&gt;
  Annotation,&lt;br&gt;
  MessagesAnnotation,&lt;br&gt;
  END,&lt;br&gt;
} from "@langchain/langgraph";&lt;br&gt;
import { ChatOpenAI } from "@langchain/openai";&lt;br&gt;
import { HumanMessage, SystemMessage } from "@langchain/core/messages";&lt;br&gt;
import { PineconeStore } from "@langchain/pinecone";&lt;br&gt;
import { embeddings } from "./embeddings";&lt;br&gt;
import { promptTemplate } from "./ragPrompt";&lt;/p&gt;

&lt;p&gt;const model = new ChatOpenAI({&lt;br&gt;
  modelName: "gpt-4",&lt;br&gt;
  temperature: 0,&lt;br&gt;
  openAIApiKey: process.env.OPENAI_API_KEY,&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;let vectorStore: PineconeStore | null = null;&lt;/p&gt;

&lt;p&gt;async function getVectorStore() {&lt;br&gt;
  console.log("[CRAG] getVectorStore called, cached:", !!vectorStore);&lt;br&gt;
  if (!vectorStore) {&lt;br&gt;
    const { pineconeIndex } = await import("./pinecone");&lt;br&gt;
    vectorStore = await PineconeStore.fromExistingIndex(embeddings, {&lt;br&gt;
      pineconeIndex,&lt;br&gt;
    });&lt;br&gt;
    console.log("[CRAG] vectorStore initialized");&lt;br&gt;
  }&lt;br&gt;
  return vectorStore;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;const CRAGState = Annotation.Root({&lt;br&gt;
  ...MessagesAnnotation.spec,&lt;br&gt;
  question: Annotation({ reducer: (&lt;em&gt;, b) =&amp;gt; b, default: () =&amp;gt; "" }),&lt;br&gt;
  namespace: Annotation({ reducer: (&lt;/em&gt;, b) =&amp;gt; b, default: () =&amp;gt; "" }),&lt;br&gt;
  documents: Annotation({ reducer: (&lt;em&gt;, b) =&amp;gt; b, default: () =&amp;gt; [] }),&lt;br&gt;
  retrievalGrade: Annotation({&lt;br&gt;
    reducer: (&lt;/em&gt;, b) =&amp;gt; b,&lt;br&gt;
    default: () =&amp;gt; "",&lt;br&gt;
  }),&lt;br&gt;
  rewrittenQuestion: Annotation({&lt;br&gt;
    reducer: (&lt;em&gt;, b) =&amp;gt; b,&lt;br&gt;
    default: () =&amp;gt; "",&lt;br&gt;
  }),&lt;br&gt;
  answer: Annotation({ reducer: (&lt;/em&gt;, b) =&amp;gt; b, default: () =&amp;gt; "" }),&lt;br&gt;
  retryCount: Annotation({ reducer: (_, b) =&amp;gt; b, default: () =&amp;gt; 0 }),&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;async function retrieve(state: typeof CRAGState.State) {&lt;br&gt;
  console.log("[CRAG] retrieve node started");&lt;br&gt;
  const store = await getVectorStore();&lt;br&gt;
  const query = state.rewrittenQuestion || state.question;&lt;br&gt;
  console.log("[CRAG] retrieve query:", query, "namespace:", state.namespace);&lt;br&gt;
  const results = await store.similaritySearch(query, 5, {&lt;br&gt;
    namespace: state.namespace,&lt;br&gt;
  });&lt;br&gt;
  const docs = results.map((doc) =&amp;gt; doc.pageContent);&lt;br&gt;
  console.log("[CRAG] retrieve got", docs.length, "docs");&lt;br&gt;
  return { documents: docs };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;async function gradeDocuments(state: typeof CRAGState.State) {&lt;br&gt;
  console.log("[CRAG] LLM grading retrieval...");&lt;/p&gt;

&lt;p&gt;const context = state.documents.join("\n\n");&lt;/p&gt;

&lt;p&gt;const response = await model.invoke([&lt;br&gt;
    new SystemMessage(`&lt;br&gt;
You are a retrieval evaluator.&lt;/p&gt;

&lt;p&gt;Determine whether the retrieved documents&lt;br&gt;
are relevant enough to answer the user's question.&lt;/p&gt;

&lt;p&gt;Reply ONLY with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;good&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;bad&lt;br&gt;
`),&lt;/p&gt;

&lt;p&gt;new HumanMessage(`&lt;br&gt;
Question:&lt;br&gt;
${state.question}&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Retrieved Documents:&lt;br&gt;
${context}&lt;br&gt;
`),&lt;br&gt;
  ]);&lt;/p&gt;

&lt;p&gt;const grade =&lt;br&gt;
    typeof response.content === "string"&lt;br&gt;
      ? response.content.toLowerCase().trim()&lt;br&gt;
      : "bad";&lt;/p&gt;

&lt;p&gt;console.log("[CRAG] LLM grade:", grade);&lt;/p&gt;

&lt;p&gt;return {&lt;br&gt;
    retrievalGrade: grade,&lt;br&gt;
  };&lt;br&gt;
} &lt;/p&gt;

&lt;p&gt;async function rewriteQuery(state: typeof CRAGState.State) {&lt;br&gt;
  console.log("[CRAG] rewriteQuery node started");&lt;br&gt;
  const response = await model.invoke([&lt;br&gt;
    new SystemMessage("Rewrite the user's query to improve vector retrieval."),&lt;br&gt;
    new HumanMessage(state.question),&lt;br&gt;
  ]);&lt;br&gt;
  const rewritten =&lt;br&gt;
    typeof response.content === "string" ? response.content : state.question;&lt;br&gt;
  console.log("[CRAG] rewriteQuery new query:", rewritten);&lt;br&gt;
  return { rewrittenQuestion: rewritten, retryCount: state.retryCount + 1 };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;async function generateAnswer(state: typeof CRAGState.State) {&lt;br&gt;
  console.log("[CRAG] generateAnswer node started");&lt;br&gt;
  const combinedContext = state.documents.join("\n\n");&lt;br&gt;
  const formattedPrompt = await promptTemplate.format({&lt;br&gt;
    context: combinedContext,&lt;br&gt;
  });&lt;br&gt;
  const response = await model.invoke([&lt;br&gt;
    new SystemMessage(formattedPrompt),&lt;br&gt;
    new HumanMessage(state.question),&lt;br&gt;
  ]);&lt;br&gt;
  const answer = typeof response.content === "string" ? response.content : "";&lt;br&gt;
  console.log("[CRAG] generateAnswer produced answer length:", answer.length);&lt;br&gt;
  return { answer, messages: [response] };&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;function shouldRetry(state: typeof CRAGState.State) {&lt;br&gt;
  console.log(&lt;br&gt;
    "[CRAG] shouldRetry grade:",&lt;br&gt;
    state.retrievalGrade,&lt;br&gt;
    "retryCount:",&lt;br&gt;
    state.retryCount,&lt;br&gt;
  );&lt;br&gt;
  if (state.retryCount &amp;gt;= 2) return "generate";&lt;br&gt;
  if (state.retrievalGrade === "bad") return "rewrite_query";&lt;br&gt;
  return "generate";&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;console.log("[CRAG] Graph compiled");&lt;br&gt;
export const cragGraph = new StateGraph(CRAGState)&lt;br&gt;
  .addNode("retrieve", retrieve)&lt;br&gt;
  .addNode("grade_documents", gradeDocuments)&lt;br&gt;
  .addNode("rewrite_query", rewriteQuery)&lt;br&gt;
  .addNode("generate", generateAnswer)&lt;br&gt;
  .addEdge("&lt;strong&gt;start&lt;/strong&gt;", "retrieve")&lt;br&gt;
  .addEdge("retrieve", "grade_documents")&lt;br&gt;
  .addConditionalEdges("grade_documents", shouldRetry, {&lt;br&gt;
    rewrite_query: "rewrite_query",&lt;br&gt;
    generate: "generate",&lt;br&gt;
  })&lt;br&gt;
  .addEdge("rewrite_query", "retrieve")&lt;br&gt;
  .addEdge("generate", END)&lt;br&gt;
  .compile();&lt;/p&gt;

</description>
      <category>rag</category>
      <category>graphrag</category>
      <category>crag</category>
      <category>genai</category>
    </item>
    <item>
      <title>Implementing a Retrieval-Augmented Generation (RAG) Chatbot with LangChain, Firebase, and Pinecone</title>
      <dc:creator>Tej Hagargi</dc:creator>
      <pubDate>Thu, 25 Sep 2025 10:50:48 +0000</pubDate>
      <link>https://dev.to/tejhagargi/implementing-a-retrieval-augmented-generation-rag-chatbot-with-langchain-firebase-and-pinecone-3pm4</link>
      <guid>https://dev.to/tejhagargi/implementing-a-retrieval-augmented-generation-rag-chatbot-with-langchain-firebase-and-pinecone-3pm4</guid>
      <description>&lt;p&gt;Recently, I was working on a Retrieval-Augmented Generation (RAG) chatbot where users can upload PDFs or where I can scrape structured website data. The goal was to convert this data into embeddings, store it in a vector database, and then use it to answer user queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Extract Raw Text&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From pdf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { PdfReader } from 'pdfreader';

let text = '';
const pdfReader = new PdfReader();

await new Promise&amp;lt;void&amp;gt;((resolve, reject) =&amp;gt; {
  pdfReader.parseBuffer(buffer, (err: any, item: any) =&amp;gt; {
    if (err) reject(err);
    else if (!item) resolve();
    else if (item.text) text += item.text + ' ';
  });
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From scraped website data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function extractTextFromScrapedData(data: ScrapedData): string {
  const sections: string[] = [];

  if (data.about) sections.push(`About: ${data.about}`);
  if (data.services) sections.push(`Services: ${data.services.join('\n• ')}`);
  if (data.contact?.phone) sections.push(`Phone: ${data.contact.phone}`);

  return sections.join('\n\n');
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Split Text into Chunks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Long documents need to be split so the LLM can handle them. I used LangChain’s RecursiveCharacterTextSplitter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { Document } from "@langchain/core/documents";

const doc = new Document({ pageContent: text });
const splitter = new RecursiveCharacterTextSplitter({
  chunkSize: 1000,
  chunkOverlap: 200
});

const allSplits = await splitter.splitDocuments([doc]);
console.log("Chunks created:", allSplits.length);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Generate Embeddings + Store&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the most important part:&lt;br&gt;
When you call vectorStore.addDocuments(), LangChain automatically calls your embedding model (e.g. OpenAI, Cohere) and saves those vectors into your configured database (Pinecone in my case).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { vectorStore } from "@/app/lib/langchain";

// Store with namespace (client-specific)
await vectorStore.addDocuments(allSplits, { namespace: clientId });
console.log("✅ Documents added to vectorStore");

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Retrieve Context During Chat&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user asks a question, we retrieve the top-k similar chunks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const retrieved = await vectorStore.similaritySearchWithScore(
  userMessage,
  3,
  { namespace: clientId }
);

const relevantMatches = retrieved.filter(([doc, score]) =&amp;gt; score &amp;gt; 0.6);
console.log("Relevant matches:", relevantMatches.length);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The other chunking methods are :
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Agentic Chunking → LLM-guided, semantic-aware chunking based on meaning and context.&lt;/li&gt;
&lt;li&gt;CharacterTextSplitter → Splits by character count (simple, fast).&lt;/li&gt;
&lt;li&gt;RecursiveCharacterTextSplitter → Splits by hierarchy (paragraph → sentence → word → char). Most commonly used.&lt;/li&gt;
&lt;li&gt;TokenTextSplitter → Splits by tokens, aligns with model tokenization.&lt;/li&gt;
&lt;li&gt;MarkdownTextSplitter → Splits Markdown docs by headers/sections.&lt;/li&gt;
&lt;li&gt;HTMLTextSplitter → Splits HTML while respecting tags.&lt;/li&gt;
&lt;li&gt;CodeTextSplitter → Splits source code by functions, classes, logical blocks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refer to this doc for more clarifying &lt;br&gt;
&lt;a href="https://js.langchain.com/docs/tutorials/rag/" rel="noopener noreferrer"&gt;DOC&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Happy Coding, Keep Striving.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>llm</category>
      <category>typescript</category>
      <category>tutorial</category>
      <category>rag</category>
    </item>
    <item>
      <title>Docker Essentials for Beginners: What I Learned Building My First Node.js App</title>
      <dc:creator>Tej Hagargi</dc:creator>
      <pubDate>Sun, 06 Jul 2025 10:46:40 +0000</pubDate>
      <link>https://dev.to/tejhagargi/docker-essentials-for-beginners-what-i-learned-building-my-first-nodejs-app-5606</link>
      <guid>https://dev.to/tejhagargi/docker-essentials-for-beginners-what-i-learned-building-my-first-nodejs-app-5606</guid>
      <description>&lt;p&gt;Over the past few days, I’ve been diving into Docker and learning how it simplifies development and deployment. I started with a basic Node.js app and ended up understanding key Docker concepts that I’m sharing below — explained in simple terms from a beginner’s point of view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Docker?
&lt;/h2&gt;

&lt;p&gt;Docker simplifies application development, deployment, and scaling by packaging your app along with its dependencies into containers. These containers run the same way in development, testing, or production — ensuring consistency across environments.&lt;/p&gt;

&lt;p&gt;First rule: Make sure Docker Desktop is running before executing any Docker commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Docker Commands I Learned
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it ubuntu         # Image
docker container ls           # List running containers
docker container ls -a        # List all containers (including stopped)
docker start &amp;lt;container&amp;gt;      # Start a stopped container
docker stop &amp;lt;container&amp;gt;       # Stop a running container
docker exec &amp;lt;container&amp;gt; ls    # Run commands inside the container from host
docker exec -it &amp;lt;container&amp;gt; bash  # Open shell inside the container

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding Images vs Containers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Images are the blueprint (environment setup, app code).&lt;/li&gt;
&lt;li&gt;Containers are the live, running instances of those images.&lt;/li&gt;
&lt;li&gt;Multiple containers can use the same image — they are isolated from each other.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating &amp;amp; Sharing Custom Images
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Write a Dockerfile to define environment &amp;amp; dependencies.&lt;/li&gt;
&lt;li&gt;Build the image (docker build -t codebro-image .).&lt;/li&gt;
&lt;li&gt;Push it to Docker Hub.&lt;/li&gt;
&lt;li&gt;Your teammates can run it using:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull your-dockerhub/codebro-image
docker run -it your-dockerhub/codebro-image

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker Networking
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bridge Network (Default)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolated network created by Docker.&lt;/li&gt;
&lt;li&gt;Containers can talk to each other using names (if on custom bridge).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network inspect bridge

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Host Network&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shares host machine’s network.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it --network=host your-image

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;None Network&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No network access (complete isolation).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it --network=none alpine

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a Custom Network&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network create my-custom-network

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Port Mapping &amp;amp; Environment Variables
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Expose ports from container to host:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it -p 1025:1025 image-name

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Pass environment variables:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it -p 1025:1025 -e key=value -e key=value image-name

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Volume Mounting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Attach host folders to containers for persistent storage:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it -v /Users/tejhagargi/Desktop:/home/abc ubuntu

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changes in /home/abc inside container reflect on your desktop and vice versa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer Caching
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Each line in a Dockerfile becomes a layer. Docker reuses unchanged layers to speed up builds.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:18           # Layer 1
WORKDIR /app           # Layer 2
COPY package.json .    # Layer 3
RUN npm install        # Layer 4
COPY . .               # Layer 5
CMD ["node", "index.js"]  # Layer 6

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multi-Stage Builds
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build your app in one stage and copy only the necessary files to a clean final image.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm install &amp;amp;&amp;amp; npm run build

FROM node:18-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Try My Dockerized Node App&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull tejhagargi/myfirstnodeapp_docker
docker run -it -p 3000:3000 tejhagargi/myfirstnodeapp_docker

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;`FROM ubuntu &lt;/p&gt;

&lt;p&gt;RUN apt-get update&lt;/p&gt;

&lt;p&gt;RUN apt-get install -y curl&lt;/p&gt;

&lt;p&gt;RUN curl -sL &lt;a href="https://deb.nodesource.com/setup_18.x" rel="noopener noreferrer"&gt;https://deb.nodesource.com/setup_18.x&lt;/a&gt; | bash -&lt;/p&gt;

&lt;p&gt;RUN apt-get upgrade -y &lt;/p&gt;

&lt;p&gt;RUN apt-get install -y nodejs&lt;/p&gt;

&lt;p&gt;COPY package-lock.json package-lock.json&lt;br&gt;
COPY package.json package.json&lt;br&gt;
COPY main.js main.js&lt;/p&gt;

&lt;p&gt;RUN npm install&lt;/p&gt;

&lt;p&gt;ENTRYPOINT [ "node", "main.js" ]&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrapping Up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Learning Docker has helped me understand how to ship applications reliably. Whether you’re working solo or with a team, containerization is a powerful tool that makes life easier.&lt;/p&gt;

&lt;p&gt;If you're also learning Docker, feel free to drop questions or tips in the comments!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧑‍💻 Happy Dockering!&lt;br&gt;
— Tej Hagargi&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
