<?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: Meidi Airouche</title>
    <description>The latest articles on DEV Community by Meidi Airouche (@mairouche).</description>
    <link>https://dev.to/mairouche</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%2F872884%2F044b43e3-7255-4221-ac9e-c59821b15a1c.jpg</url>
      <title>DEV Community: Meidi Airouche</title>
      <link>https://dev.to/mairouche</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mairouche"/>
    <language>en</language>
    <item>
      <title>Multi-Agent Platform with A2A, Python, Strands &amp; AWS AgentCore</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Wed, 14 Jan 2026 08:39:44 +0000</pubDate>
      <link>https://dev.to/onepoint/multi-agent-platform-with-a2a-python-strands-aws-agentcore-2n74</link>
      <guid>https://dev.to/onepoint/multi-agent-platform-with-a2a-python-strands-aws-agentcore-2n74</guid>
      <description>&lt;p&gt;A single RAG agent is easy to ship.&lt;/p&gt;

&lt;p&gt;But the moment you need &lt;strong&gt;multiple domains&lt;/strong&gt; (HR, IT, …), different knowledge sources, and clean ownership boundaries, a single “do‑everything” agent turns into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an unmaintainable prompt,&lt;/li&gt;
&lt;li&gt;a tangled toolset,&lt;/li&gt;
&lt;li&gt;and a retrieval strategy that mixes unrelated documents.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This post shows a &lt;strong&gt;production-shaped&lt;/strong&gt; approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HR Agent&lt;/strong&gt;: RAG over HR documents (AWS Knowledge Base ID configured via env)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;IT Agent&lt;/strong&gt;: RAG over IT documents (different KB ID)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestrator Agent&lt;/strong&gt;: routes queries by calling HR/IT agents over &lt;strong&gt;A2A&lt;/strong&gt;, then synthesizes the final answer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All three are deployed as &lt;strong&gt;AgentCore Runtime&lt;/strong&gt; apps : each handler is a &lt;code&gt;BedrockAgentCoreApp&lt;/code&gt; entrypoint.&lt;/p&gt;

&lt;p&gt;Strands Agents is a Python SDK for building LLM-based production-ready agents as first-class software components.&lt;br&gt;
It abstracts prompt management, tool invocation, and agent-to-agent communication, enabling to compose complex agent systems without hard-coding control flows or glue logic.&lt;/p&gt;


&lt;h2&gt;
  
  
  What we are building
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Components
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HR Agent&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strands &lt;code&gt;Agent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tool: &lt;code&gt;strands_tools.retrieve&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Config: &lt;code&gt;KNOWLEDGE_BASE_ID&lt;/code&gt; (HR KB)&lt;/li&gt;
&lt;li&gt;Exposed as an A2A endpoint via AgentCore Runtime&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;IT Agent&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same as HR agent&lt;/li&gt;
&lt;li&gt;Config: &lt;code&gt;KNOWLEDGE_BASE_ID&lt;/code&gt; (IT KB)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Orchestrator Agent&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Strands &lt;code&gt;Agent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tools: &lt;code&gt;ask_hr_agent&lt;/code&gt;, &lt;code&gt;ask_it_agent&lt;/code&gt; (A2A client calls)&lt;/li&gt;
&lt;li&gt;Config: &lt;code&gt;HR_AGENT_URL&lt;/code&gt;, &lt;code&gt;IT_AGENT_URL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Decides routing automatically (tool choice) and synthesizes a final answer&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Runtime request flow
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;User sends a question to the &lt;strong&gt;Orchestrator&lt;/strong&gt; (AgentCore Runtime endpoint)&lt;/li&gt;
&lt;li&gt;Orchestrator LLM decides whether to use:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ask_hr_agent()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ask_it_agent()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;or both&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Orchestrator calls the specialized agent(s) via &lt;strong&gt;A2A&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Specialized agent uses &lt;code&gt;retrieve&lt;/code&gt; tool (RAG) against its Knowledge Base&lt;/li&gt;
&lt;li&gt;Orchestrator produces a final, human‑readable answer&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  1 — Configuration (env vars)
&lt;/h2&gt;

&lt;p&gt;This architecture is intentionally &lt;strong&gt;configuration-first&lt;/strong&gt;. No hardcoded URLs or KB IDs.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Knowledge bases are created with S3 Vector base but outside of this topic since it's easy to create with 5 clics. Just collect the IDs once created.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The retrieve tool provided by strands_tools is automatically configured at runtime using KNOWLEDGE_BASE_ID, which AgentCore resolves to the correct vector store and injects into the retrieval tool execution.&lt;/p&gt;
&lt;h3&gt;
  
  
  HR Agent env
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;KNOWLEDGE_BASE_ID&lt;/code&gt;
The Knowledge Base ID for HR content.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  IT Agent env
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;KNOWLEDGE_BASE_ID&lt;/code&gt;
The Knowledge Base ID for IT content.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Orchestrator env
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;HR_AGENT_URL&lt;/code&gt;&lt;br&gt;&lt;br&gt;
A2A endpoint for the HR Agent (for example, an AgentCore Runtime service URL).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;IT_AGENT_URL&lt;/code&gt;&lt;br&gt;&lt;br&gt;
A2A endpoint for the IT Agent.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;AWS_REGION&lt;/code&gt; (optional)&lt;br&gt;&lt;br&gt;
Defaults to &lt;code&gt;eu-central-1&lt;/code&gt; in the handler.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  2 — HR Agent handler (AgentCore Runtime + RAG)
&lt;/h2&gt;

&lt;p&gt;This is the &lt;strong&gt;complete&lt;/strong&gt; HR agent handler.&lt;/p&gt;

&lt;p&gt;Key design choices:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lazy initialization&lt;/strong&gt;: create the Strands agent only once per runtime container&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Single tool&lt;/strong&gt;: &lt;code&gt;retrieve&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Strict behavior&lt;/strong&gt;: if retrieval doesn’t find anything relevant, say so
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
HR Agent handler for AgentCore Runtime deployment with A2A support.

Requirements: 1.1, 1.2, 1.4
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Configuration
&lt;/span&gt;&lt;span class="n"&gt;KNOWLEDGE_BASE_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KNOWLEDGE_BASE_ID&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="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;KNOWLEDGE_BASE_ID&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="n"&gt;KNOWLEDGE_BASE_ID&lt;/span&gt;

&lt;span class="n"&gt;HR_SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are an expert HR assistant. You answer questions related to human resources,
HR policies, leave, benefits, recruitment, and people management.

Use the retrieval tool to search the HR knowledge base.
If you cannot find relevant information, clearly state it.

Always respond in a professional and concise manner.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="c1"&gt;# Lazy agent initialization
&lt;/span&gt;&lt;span class="n"&gt;_hr_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_hr_agent&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Lazy load HR agent.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;_hr_agent&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_hr_agent&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;retrieve&lt;/span&gt;

        &lt;span class="n"&gt;_hr_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;HR_SYSTEM_PROMPT&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HR agent initialized&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_hr_agent&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Handle HR agent requests.&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="n"&gt;prompt_str&lt;/span&gt; &lt;span class="o"&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;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_hr_agent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&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="n"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HR agent error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="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;Erreur agent RH: &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;span class="c1"&gt;# For AgentCore Runtime with A2A
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bedrock_agentcore.runtime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentCoreApp&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockAgentCoreApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HR BedrockAgentCoreApp initialized&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="nd"&gt;@app.entrypoint&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HR received: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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;ImportError&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="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bedrock_agentcore.runtime not available: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Why &lt;code&gt;os.environ["KNOWLEDGE_BASE_ID"] = KNOWLEDGE_BASE_ID&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;Some tooling layers (including retrieval integrations) resolve configuration directly from process environment. By forcing it into &lt;code&gt;os.environ&lt;/code&gt;, you ensure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;consistent behavior in local runs&lt;/li&gt;
&lt;li&gt;consistent behavior in AgentCore Runtime containers&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  What “RAG” means here
&lt;/h3&gt;

&lt;p&gt;In this handler, &lt;strong&gt;RAG is not manual&lt;/strong&gt; (no explicit vector DB queries in your code).&lt;br&gt;
Instead, the Strands agent uses the &lt;strong&gt;&lt;code&gt;retrieve&lt;/code&gt; tool&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the LLM decides when to call &lt;code&gt;retrieve&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;the tool pulls relevant chunks from your Knowledge Base&lt;/li&gt;
&lt;li&gt;the response is generated with that context&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  3 — IT Agent handler (AgentCore Runtime + RAG)
&lt;/h2&gt;

&lt;p&gt;This is the &lt;strong&gt;complete&lt;/strong&gt; IT agent handler.&lt;/p&gt;

&lt;p&gt;Same architecture as HR:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lazy init&lt;/li&gt;
&lt;li&gt;tool = &lt;code&gt;retrieve&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
IT Agent handler for AgentCore Runtime deployment with A2A support.

Requirements: 2.1, 2.2, 2.4
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Configuration
&lt;/span&gt;&lt;span class="n"&gt;KNOWLEDGE_BASE_ID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;KNOWLEDGE_BASE_ID&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="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;KNOWLEDGE_BASE_ID&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="n"&gt;KNOWLEDGE_BASE_ID&lt;/span&gt;

&lt;span class="n"&gt;IT_SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are an expert IT assistant. You answer questions related to IT,
systems, software, technical support, cybersecurity, and infrastructure.

Use the retrieval tool to search the IT knowledge base.
If you cannot find relevant information, clearly state it.

Always respond in a professional and concise manner.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="c1"&gt;# Lazy agent initialization
&lt;/span&gt;&lt;span class="n"&gt;_it_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_it_agent&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Lazy load IT agent.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;_it_agent&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_it_agent&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;retrieve&lt;/span&gt;

        &lt;span class="n"&gt;_it_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;retrieve&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;IT_SYSTEM_PROMPT&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;IT agent initialized&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_it_agent&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Handle IT agent requests.&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="n"&gt;prompt_str&lt;/span&gt; &lt;span class="o"&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;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_it_agent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&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="n"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;IT agent error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="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;Erreur agent IT: &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;span class="c1"&gt;# For AgentCore Runtime with A2A
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bedrock_agentcore.runtime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentCoreApp&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockAgentCoreApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;IT BedrockAgentCoreApp initialized&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="nd"&gt;@app.entrypoint&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;IT received: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&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="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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;ImportError&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="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bedrock_agentcore.runtime not available: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Why separate agents instead of one big agent with two KBs?
&lt;/h3&gt;

&lt;p&gt;Because the separation buys you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;independent prompts&lt;/li&gt;
&lt;li&gt;independent retrieval scopes (no “HR policy” leaking into IT answers)&lt;/li&gt;
&lt;li&gt;independent deployment/scaling&lt;/li&gt;
&lt;li&gt;simpler evaluation (HR answers vs IT answers)&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  4 — Orchestrator handler (AgentCore Runtime + A2A tools)
&lt;/h2&gt;

&lt;p&gt;Now the interesting part: the orchestrator.&lt;/p&gt;

&lt;p&gt;Your orchestrator is a Strands agent with two tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ask_hr_agent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ask_it_agent&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those tools are wrappers around an &lt;strong&gt;A2A client call&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Orchestrator key behaviors
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;It &lt;strong&gt;does not&lt;/strong&gt; use &lt;code&gt;retrieve&lt;/code&gt; itself&lt;/li&gt;
&lt;li&gt;It delegates to specialized agents&lt;/li&gt;
&lt;li&gt;It may call &lt;strong&gt;both&lt;/strong&gt; if needed
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Orchestrator Agent handler for AgentCore Runtime deployment.

Uses Strands Agent with HR/IT agents as tools - the model decides routing.

Requirements: 3.1, 3.2, 3.3, 3.4, 3.5
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Any&lt;/span&gt;

&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Configuration
&lt;/span&gt;&lt;span class="n"&gt;AWS_REGION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_REGION&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;eu-central-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;HR_AGENT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HR_AGENT_URL&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="n"&gt;IT_AGENT_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getenv&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_AGENT_URL&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="c1"&gt;# Lazy initialization
&lt;/span&gt;&lt;span class="n"&gt;_orchestrator_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;


&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;_call_a2a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Internal A2A call.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;a2a.client&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;A2AClient&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="nc"&gt;A2AClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;send_message&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&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;part&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
        &lt;span class="k"&gt;return&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;response&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_hr_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Ask the specialized HR agent.

    Use this tool for questions about:
    - HR policies, leave, payroll
    - Recruitment, hiring, contracts
    - Training, performance reviews
    - Benefits, insurance, retirement
    - Remote work, absences
    &lt;/span&gt;&lt;span class="sh"&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;HR_AGENT_URL&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;Erreur: Agent RH non configuré&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;asyncio&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="nf"&gt;_call_a2a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HR_AGENT_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&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="n"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HR agent error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="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;Erreur agent RH: &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;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ask_it_agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Ask the specialized IT agent.

    Use this tool for questions about:
    - Computers, software, support
    - Network, Wi‑Fi, VPN, internet
    - Passwords, accounts, access
    - Security, antivirus
    - Email, Teams, apps
    &lt;/span&gt;&lt;span class="sh"&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;IT_AGENT_URL&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;Erreur: Agent IT non configuré&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;asyncio&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="nf"&gt;_call_a2a&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IT_AGENT_URL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;query&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="n"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;IT agent error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="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;Erreur agent IT: &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;span class="n"&gt;ORCHESTRATOR_SYSTEM_PROMPT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;You are an orchestrator assistant for employees.

You have access to two specialized agents:
- HR Agent: for all human resources questions (leave, payroll, contracts, training, etc.)
- IT Agent: for all IT-related questions (software, hardware, technical support, etc.)

Analyze each question and use the appropriate agent(s) to answer.
If a question spans both domains, consult both agents.

After receiving the responses, synthesize a clear and complete final answer.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_orchestrator_agent&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Get or create the orchestrator agent with HR/IT tools.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;global&lt;/span&gt; &lt;span class="n"&gt;_orchestrator_agent&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;_orchestrator_agent&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;

        &lt;span class="n"&gt;_orchestrator_agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ask_hr_agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ask_it_agent&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;system_prompt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ORCHESTRATOR_SYSTEM_PROMPT&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Orchestrator agent initialized with HR/IT tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_orchestrator_agent&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Handle orchestrator requests.&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="n"&gt;prompt_str&lt;/span&gt; &lt;span class="o"&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;prompt&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_orchestrator_agent&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt_str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&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="n"&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="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Orchestration error: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="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;Erreur: &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;span class="c1"&gt;# For AgentCore Runtime
&lt;/span&gt;&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bedrock_agentcore.runtime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockAgentCoreApp&lt;/span&gt;
    &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockAgentCoreApp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Orchestrator BedrockAgentCoreApp initialized&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="nd"&gt;@app.entrypoint&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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;ImportError&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="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bedrock_agentcore.runtime not available: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;e&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="n"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Why implement HR/IT calls as &lt;em&gt;tools&lt;/em&gt;?
&lt;/h3&gt;

&lt;p&gt;Because it makes routing &lt;strong&gt;model-driven&lt;/strong&gt; instead of hard-coded.&lt;/p&gt;

&lt;p&gt;You’re giving the orchestrator:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a system prompt describing the domains&lt;/li&gt;
&lt;li&gt;tool docstrings that describe when to use them&lt;/li&gt;
&lt;li&gt;a stable interface (&lt;code&gt;ask_hr_agent(query) -&amp;gt; str&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The LLM chooses the right tool(s), and you keep your Python logic minimal.&lt;/p&gt;


&lt;h2&gt;
  
  
  5 — A2A call parsing
&lt;/h2&gt;

&lt;p&gt;A2A responses often come as structured messages with parts.&lt;br&gt;
The parsing strategy is resilient:&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;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;message&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&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;part&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;parts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;hasattr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;
&lt;span class="k"&gt;return&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;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Why this matters:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You don’t assume a single “text blob” response&lt;/li&gt;
&lt;li&gt;You gracefully fallback to &lt;code&gt;str(response)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6 — Lazy initialization (production detail that matters)
&lt;/h2&gt;

&lt;p&gt;All three handlers use lazy init (&lt;code&gt;_agent = None&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Why it’s important in AgentCore Runtime:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cold start cost is paid once per container&lt;/li&gt;
&lt;li&gt;subsequent requests reuse the same agent instance&lt;/li&gt;
&lt;li&gt;lower latency and less overhead&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is the kind of detail that separates a demo from something you can run for real users.&lt;/p&gt;




&lt;h2&gt;
  
  
  7 — How routing actually happens
&lt;/h2&gt;

&lt;p&gt;You don’t have &lt;code&gt;if "vpn" in query: ...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The orchestrator receives the question&lt;/li&gt;
&lt;li&gt;It decides which tool(s) to call based on system prompt + tool descriptions&lt;/li&gt;
&lt;li&gt;It synthesizes a final answer&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;HR-only question → calls &lt;code&gt;ask_hr_agent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;IT-only question → calls &lt;code&gt;ask_it_agent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Mixed question → calls both, then merges&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8 — Failure modes and debugging
&lt;/h2&gt;

&lt;p&gt;Your code already includes the essentials:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;INFO logging&lt;/li&gt;
&lt;li&gt;explicit “not configured” messages&lt;/li&gt;
&lt;li&gt;tool-level error handling&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Common issues:&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing URL
&lt;/h3&gt;

&lt;p&gt;If &lt;code&gt;HR_AGENT_URL&lt;/code&gt; is empty:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ask_hr_agent&lt;/code&gt; returns &lt;code&gt;Error: HR agent not configured&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Network/A2A issues
&lt;/h3&gt;

&lt;p&gt;If A2A fails:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;error is logged&lt;/li&gt;
&lt;li&gt;tool returns &lt;code&gt;Error HR agent: ...&lt;/code&gt; / &lt;code&gt;Error IT agent: ...&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The orchestrator can still produce a partial answer if only one agent fails.&lt;/p&gt;




&lt;h2&gt;
  
  
  9 — Practical hardening ideas (optional)
&lt;/h2&gt;

&lt;p&gt;These keep the same architecture, but improve resilience:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Timeouts &amp;amp; retries&lt;/strong&gt; for A2A calls (network I/O).&lt;/li&gt;
&lt;li&gt;Avoid &lt;code&gt;asyncio.run()&lt;/code&gt; if you ever run inside an existing event loop.&lt;/li&gt;
&lt;li&gt;Return structured tool outputs (citations, metadata) if you need auditability later.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Why this architecture scales
&lt;/h2&gt;

&lt;p&gt;Adding a new domain agent (Finance / Legal / Security) is just repetition of the same pattern:&lt;/p&gt;

&lt;p&gt;1) new RAG agent handler with &lt;code&gt;retrieve&lt;/code&gt; + domain prompt + &lt;code&gt;KNOWLEDGE_BASE_ID&lt;/code&gt;&lt;br&gt;&lt;br&gt;
2) new orchestrator tool &lt;code&gt;ask_finance_agent&lt;/code&gt; calling A2A&lt;br&gt;&lt;br&gt;
3) add tool to orchestrator’s &lt;code&gt;tools=[...]&lt;/code&gt;  &lt;/p&gt;

&lt;p&gt;No refactor required.&lt;/p&gt;




&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;If you already know how to build RAG (or deterministic tools), the next step is &lt;strong&gt;orchestration&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This pattern gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;domain isolation&lt;/li&gt;
&lt;li&gt;deployable units (AgentCore Runtime)&lt;/li&gt;
&lt;li&gt;model-driven routing (tools)&lt;/li&gt;
&lt;li&gt;a clean evolution path&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s basically microservices:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;small, focused services with a clear interface — except the services can reason.&lt;/p&gt;
&lt;/blockquote&gt;




</description>
      <category>python</category>
      <category>aws</category>
      <category>agents</category>
      <category>rag</category>
    </item>
    <item>
      <title>RAG Works — Until You Hit the Long Tail</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Sun, 11 Jan 2026 23:23:12 +0000</pubDate>
      <link>https://dev.to/onepoint/rag-works-until-you-hit-the-long-tail-54lp</link>
      <guid>https://dev.to/onepoint/rag-works-until-you-hit-the-long-tail-54lp</guid>
      <description>&lt;h2&gt;
  
  
  Why Training Knowledge Into Weights Is the Next Step Beyond RAG
&lt;/h2&gt;

&lt;p&gt;If you use ChatGPT or similar large language models on a daily basis, you have probably developed a certain level of trust in them. They are articulate, fast, and often impressively capable. Many engineers already rely on them for coding assistance, documentation, or architectural brainstorming.&lt;/p&gt;

&lt;p&gt;And yet, sooner or later, you hit a wall.&lt;/p&gt;

&lt;p&gt;You ask a question that actually matters in your day-to-day work — something internal, recent, or highly specific — and the model suddenly becomes vague, incorrect, or confidently wrong. This is not a prompting issue. It is a structural limitation.&lt;/p&gt;

&lt;p&gt;This article explores why that happens, why current solutions only partially address the problem, and why training knowledge directly into model weights is likely to be a key part of the future.&lt;/p&gt;




&lt;h2&gt;
  
  
  The real problem is not the knowledge cutoff
&lt;/h2&gt;

&lt;p&gt;The knowledge cutoff is the most visible limitation of LLMs. Models are trained on data up to a certain point in time, and anything that happens afterward simply does not exist for them.&lt;/p&gt;

&lt;p&gt;In practice, however, this is rarely the most painful issue. Web search, APIs, and tools can often mitigate it.&lt;/p&gt;

&lt;p&gt;The deeper problem is the &lt;strong&gt;long tail of knowledge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In real production environments, the most valuable questions are rarely about well-documented public facts. They are about internal systems, undocumented decisions, proprietary processes, and domain-specific conventions that exist nowhere on the public internet.&lt;/p&gt;

&lt;p&gt;Examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why did this service start failing after a seemingly unrelated change?&lt;/li&gt;
&lt;li&gt;Has this architectural trade-off already been discussed internally?&lt;/li&gt;
&lt;li&gt;How does &lt;em&gt;our&lt;/em&gt; company interpret a specific regulatory constraint?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These questions live in the long tail. And that is exactly where large foundation models perform the worst.&lt;/p&gt;




&lt;h2&gt;
  
  
  Three ways to give knowledge to a language model
&lt;/h2&gt;

&lt;p&gt;If we strip away tooling details, there are only three fundamental ways to make a language model “know” something new.&lt;/p&gt;

&lt;p&gt;The first is to place the knowledge directly into the prompt.&lt;br&gt;&lt;br&gt;
The second is to retrieve relevant information at inference time.&lt;br&gt;&lt;br&gt;
The third is to train the knowledge into the model itself.&lt;/p&gt;

&lt;p&gt;Most systems today rely almost entirely on the first two.&lt;/p&gt;


&lt;h2&gt;
  
  
  Full context: simple, expensive, and fragile
&lt;/h2&gt;

&lt;p&gt;The most naive solution is to put everything into the prompt.&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="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&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;
You are an assistant with access to our internal documentation.

&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;internal_docs&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;

Question:
Why does service X fail under load?
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For small documents, this works. It is easy to implement and requires no additional infrastructure.&lt;/p&gt;

&lt;p&gt;However, as context grows, several issues appear at once. Token costs increase linearly. Latency increases significantly. Most importantly, reasoning quality degrades as more weakly relevant information is added.&lt;/p&gt;

&lt;p&gt;This is not an implementation issue. It is a consequence of how transformer models work.&lt;/p&gt;




&lt;h2&gt;
  
  
  The transformer bottleneck and context degradation
&lt;/h2&gt;

&lt;p&gt;Transformers rely on self-attention, where every token attends to every other token. This leads to quadratic complexity with respect to input length.&lt;/p&gt;

&lt;p&gt;Even though modern models can technically accept very large context windows, there is an important difference between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;not crashing with long input, and&lt;/li&gt;
&lt;li&gt;reasoning well over long input.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Empirically, performance degrades as context grows, even when the relevant information remains the same. The model continues to produce fluent text, but its ability to connect the right pieces of information deteriorates. This phenomenon is often referred to as context rot.&lt;/p&gt;

&lt;p&gt;As a result, simply increasing the context window is not a viable long-term solution.&lt;/p&gt;




&lt;h2&gt;
  
  
  RAG: external memory via embeddings
&lt;/h2&gt;

&lt;p&gt;To avoid pushing everything into the prompt, the industry converged on Retrieval-Augmented Generation (RAG).&lt;/p&gt;

&lt;p&gt;The idea is to store documents externally, retrieve the most relevant ones using embeddings, and inject only those into the prompt.&lt;/p&gt;

&lt;p&gt;A minimal Python example looks like this:&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.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.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="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="n"&gt;vector_store&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;documents&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;docs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt;
&lt;span class="p"&gt;)&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;vector_store&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;similarity_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Why does the CI pipeline fail?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RAG is popular because it is flexible, relatively cheap, and easy to deploy. Today, it is the default solution for adding memory to LLM-based systems.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why RAG is fundamentally limited
&lt;/h2&gt;

&lt;p&gt;RAG retrieves information, but retrieval is not reasoning. Selecting a few relevant chunks does not guarantee that the model can correctly combine them, especially when the answer depends on implicit relationships or multi-step reasoning across documents.&lt;/p&gt;

&lt;p&gt;Embeddings also encode a single global notion of similarity. They are not adaptive to local domain semantics. In practice, documents that should never be confused often end up close together in vector space.&lt;/p&gt;

&lt;p&gt;Finally, embeddings are not inherently secure. With enough effort, large portions of the original text can be reconstructed from them. This makes vector databases unsuitable as a privacy-preserving abstraction.&lt;/p&gt;

&lt;p&gt;These limitations suggest that RAG is powerful, but incomplete.&lt;/p&gt;




&lt;h2&gt;
  
  
  The naive fine-tuning trap
&lt;/h2&gt;

&lt;p&gt;At this point, it is tempting to fine-tune the model directly on internal data.&lt;/p&gt;

&lt;p&gt;In practice, naive fine-tuning almost always fails. Training directly on small, specialized datasets causes the model to overfit, lose general reasoning abilities, and forget previously learned knowledge. This phenomenon is known as catastrophic forgetting.&lt;/p&gt;

&lt;p&gt;The result is a model that memorizes patterns but loses its ability to generalize and reason beyond the training data.&lt;/p&gt;




&lt;h2&gt;
  
  
  Synthetic data as the missing link
&lt;/h2&gt;

&lt;p&gt;The key insight that changes the picture is synthetic data generation.&lt;/p&gt;

&lt;p&gt;Instead of training on raw documents, we generate a large and diverse set of tasks that describe the knowledge contained in those documents. These can include question–answer pairs, explanations, paraphrases, and counterfactuals.&lt;/p&gt;

&lt;p&gt;A simplified example in Python:&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;generate_qa&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;instruction&lt;/span&gt;&lt;span class="sh"&gt;"&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;Explain the key idea behind: &lt;/span&gt;&lt;span class="si"&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;title&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&lt;/span&gt;&lt;span class="sh"&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;summary&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;synthetic_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;generate_qa&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="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;internal_docs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach teaches the domain, not the surface text. Surprisingly, it works even when the original dataset is small, as long as the synthetic data is sufficiently diverse.&lt;/p&gt;




&lt;h2&gt;
  
  
  Training into weights without destroying the model
&lt;/h2&gt;

&lt;p&gt;To avoid catastrophic forgetting, modern systems rely on parameter-efficient fine-tuning. Instead of updating all weights, only a small subset is modified.&lt;/p&gt;

&lt;p&gt;One common technique is LoRA (Low-Rank Adaptation):&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;peft&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;LoraConfig&lt;/span&gt;

&lt;span class="n"&gt;lora_config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LoraConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;lora_alpha&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;target_modules&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;q_proj&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;v_proj&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;p&gt;The key idea is to make small, localized changes that steer the model without overwriting its existing knowledge.&lt;/p&gt;

&lt;p&gt;Other approaches, such as prefix tuning or memory layers, follow the same principle with different trade-offs.&lt;/p&gt;




&lt;h2&gt;
  
  
  A hybrid future: context, retrieval, and weights
&lt;/h2&gt;

&lt;p&gt;None of these techniques replaces the others entirely. The most effective systems combine all three.&lt;/p&gt;

&lt;p&gt;Context is useful for immediate instructions. Retrieval is essential for fresh or frequently changing data. Training into weights provides deep, coherent domain understanding that retrieval alone cannot achieve.&lt;/p&gt;

&lt;p&gt;The central design question going forward is not whether to train models on private knowledge, but what knowledge deserves to live in weights versus being handled at inference time.&lt;/p&gt;




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

&lt;p&gt;RAG is a pragmatic and powerful solution, and it will remain part of the LLM ecosystem. However, it is fundamentally limited when it comes to deep reasoning over specialized knowledge.&lt;/p&gt;

&lt;p&gt;As training techniques become more efficient, training knowledge into weights will no longer be a research curiosity. It will be an engineering decision.&lt;/p&gt;

&lt;p&gt;In the long run, the most valuable LLM systems will not be defined by the base model they use, but by what they have been taught — and how carefully that teaching was done.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>rag</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>How Reasoning LLMs Are Challenging Orchestration</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Tue, 04 Nov 2025 20:03:35 +0000</pubDate>
      <link>https://dev.to/onepoint/how-reasoning-llms-are-challenging-orchestration-42pm</link>
      <guid>https://dev.to/onepoint/how-reasoning-llms-are-challenging-orchestration-42pm</guid>
      <description>&lt;p&gt;I spent most of last year buried in &lt;strong&gt;LangGraph&lt;/strong&gt;.&lt;br&gt;
It felt like engineering telepathy — drawing thoughts as state machines, chaining prompts into something almost alive.&lt;br&gt;
Until one night, at 2 AM, I was staring at a 15-node graph just to summarize a document.&lt;br&gt;
Every retry, every validation, every branch was on me.&lt;br&gt;
That’s when it clicked: &lt;em&gt;I was orchestrating cognition that the model could have handled itself.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So I did what most of us do when we’re tired of over-engineering: I tore it down and rebuilt it — this time around a &lt;strong&gt;reasoning-native model&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The usual way: Manual Orchestration with LangGraph
&lt;/h2&gt;

&lt;p&gt;LangGraph made sense when models couldn’t plan or reason.&lt;br&gt;&lt;br&gt;
Here’s a minimal example of what my early pipelines looked like:&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;langgraph.graph&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StateGraph&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain_openai&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ChatOpenAI&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;langchain.schema&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;SystemMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;HumanMessage&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;ChatOpenAI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;gpt-4-turbo&lt;/span&gt;&lt;span class="sh"&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;summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="nc"&gt;SystemMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarize briefly and clearly.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;HumanMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;doc&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&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;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summary&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;llm&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="nc"&gt;SystemMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Return OK if factual, else ERROR.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="nc"&gt;HumanMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verified&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;content&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="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;graph&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StateGraph&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_node&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize&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;verify&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_entry_point&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;summarize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;graph&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;doc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;manual.txt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read&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;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we can state :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It’s explicit and predictable — but verbose.&lt;/li&gt;
&lt;li&gt;Every new condition means another node.&lt;/li&gt;
&lt;li&gt;Every correction means editing a graph.&lt;/li&gt;
&lt;li&gt;You become the conductor instead of letting the model compose the music.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The New Approach: Reasoning Models + MCP Tools
&lt;/h2&gt;

&lt;p&gt;When I switched to &lt;strong&gt;Claude 4.5&lt;/strong&gt; (and later GPT-5), I stopped describing &lt;em&gt;steps&lt;/em&gt; and started describing &lt;em&gt;goals&lt;/em&gt;.&lt;br&gt;&lt;br&gt;
The model could plan, call tools, and validate its own results through &lt;strong&gt;MCP&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="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Search internal docs.&lt;/span&gt;&lt;span class="sh"&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;Search results for &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_words&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Summarize text.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;max_words&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;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Return &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;OK&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; if factual.&lt;/span&gt;&lt;span class="sh"&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;OK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MCPClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;claude-4.5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
You are a reasoning agent.
Goal: Summarize and fact-check &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;LangGraph framework&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;.
1. Search relevant data.
2. Summarize it.
3. Validate results; retry if not OK.
Return only the final validated summary.
&lt;/span&gt;&lt;span class="sh"&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;client&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;prompt&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The trace looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[Plan] Step 1 → search("LangGraph framework")
[Plan] Step 2 → summarize(results)
[Plan] Step 3 → validate(summary)
[Reflection] Validation OK → returning summary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s &lt;strong&gt;one reasoning session&lt;/strong&gt; instead of three separate LLM calls:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Latency dropped from 2.3s to ~1.1s.&lt;/li&gt;
&lt;li&gt;Tokens halved.&lt;/li&gt;
&lt;li&gt;And my orchestration code disappeared.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Reasoning Traces as Your New Logs
&lt;/h2&gt;

&lt;p&gt;Reasoning-native models emit &lt;strong&gt;structured traces&lt;/strong&gt; — JSON instead of plain text logs.&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;"plan"&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="s2"&gt;"search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"summarize"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validate"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"confidence"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0.94&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tokens_used"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;540&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"duration_ms"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1180&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"outcome"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"validated_summary"&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;I store these in SQLite and diff them like code.&lt;br&gt;&lt;br&gt;
When a model’s plan drifts or confidence drops, my CI flags it.&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;test_reasoning_behavior&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;baseline_trace&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Summarize and validate: LangGraph&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;trace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;confidence&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;baseline_trace&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;trace&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;plan&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;baseline_trace&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;plan&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;It’s not deterministic — it’s &lt;strong&gt;bounded variance&lt;/strong&gt;, and that’s testable.&lt;/p&gt;




&lt;h2&gt;
  
  
  Observing Cognition in Production
&lt;/h2&gt;

&lt;p&gt;Each reasoning session becomes a span in OpenTelemetry.&lt;br&gt;&lt;br&gt;
I track average token usage and confidence in Grafana:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens_used&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;confidence&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;traces&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;INTERVAL&lt;/span&gt; &lt;span class="s1"&gt;'1 day'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When confidence dips, we investigate prompts — not servers.&lt;br&gt;&lt;br&gt;
Monitoring cognition feels weird at first, but it’s the only way to scale non-deterministic intelligence safely.&lt;/p&gt;


&lt;h2&gt;
  
  
  What You Trade (and Gain)
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;LangGraph&lt;/th&gt;
&lt;th&gt;Reasoning + MCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Control&lt;/td&gt;
&lt;td&gt;Explicit nodes&lt;/td&gt;
&lt;td&gt;Emergent planning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging&lt;/td&gt;
&lt;td&gt;Stack traces&lt;/td&gt;
&lt;td&gt;Cognitive traces&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Determinism&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Bounded&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adaptability&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Maintenance&lt;/td&gt;
&lt;td&gt;Tedious&lt;/td&gt;
&lt;td&gt;Lightweight&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Creativity&lt;/td&gt;
&lt;td&gt;Predictable&lt;/td&gt;
&lt;td&gt;Expansive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;LangGraph still shines where compliance or determinism rule.&lt;br&gt;&lt;br&gt;
But when your system needs flexibility and learning-like behavior, &lt;strong&gt;reasoning-native wins&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  Lessons (and Mistakes) from the Field
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reasoning drift&lt;/strong&gt; — identical input, different answers. Use baseline scoring.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token bloat&lt;/strong&gt; — models love to overthink. Set session budgets.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trace chaos&lt;/strong&gt; — vendor formats differ. Normalize JSON.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compliance audits&lt;/strong&gt; — sign and retain traces.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Team culture&lt;/strong&gt; — teach prompt design as system design.
&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  When AWS Gets It Right with AgentCore
&lt;/h2&gt;

&lt;p&gt;The most interesting thing about &lt;strong&gt;AWS AgentCore&lt;/strong&gt; isn’t that it’s another managed service — it’s that its design choices perfectly align with where reasoning-native orchestration is headed.&lt;/p&gt;

&lt;p&gt;AgentCore treats reasoning as a &lt;strong&gt;first-class runtime concern&lt;/strong&gt;, not a framework problem.&lt;br&gt;&lt;br&gt;
You don’t define workflows. You define &lt;em&gt;intent&lt;/em&gt; and &lt;em&gt;tools&lt;/em&gt;, and the runtime handles retries, observability, and tool invocation policy for you — all inside a managed cognitive environment.&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;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BedrockModel&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;http_request&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_words&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;int&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="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;max_words&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;…&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;important&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BedrockModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;us.anthropic.claude-sonnet-4-20250514-v1:0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;region_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;eu-west-3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;client_args&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;api_key&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="n"&gt;params&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;temperature&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;summarize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;http_request&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;prompt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
Summarize the key points of the LangGraph framework and then validate the summary.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prompt&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;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s it — no DAGs, no state machines, no manual recovery logic.&lt;br&gt;
AgentCore hosts your agent, tracks its reasoning trace, and automatically replays or retries failed tool calls.&lt;/p&gt;

&lt;p&gt;In practice, it embeds orchestration inside reasoning, instead of wrapping reasoning inside orchestration.&lt;br&gt;
That inversion is exactly what this whole post argues for.&lt;/p&gt;

&lt;p&gt;The fact that AWS — arguably the most conservative player in cloud architecture — built AgentCore this way tells me this isn’t a niche trend.&lt;br&gt;
It’s the industry quietly acknowledging that reasoning is the new orchestration layer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;LangGraph taught me structure.&lt;br&gt;
It forced me to make my thinking explicit — every state, every branch, every validation. But it also showed me the limits of explicitness: when you draw too much of the reasoning, the system stops thinking for itself.&lt;/p&gt;

&lt;p&gt;Reasoning models flipped that.&lt;br&gt;
They brought back uncertainty — and with it, adaptability.Instead of engineering every step, I started describing outcomes and letting the model figure out how to get there. That shift didn’t remove orchestration; it changed what orchestration means.&lt;/p&gt;

&lt;p&gt;And now, when I look at frameworks like &lt;strong&gt;AWS AgentCore&lt;/strong&gt;, I see the industry catching up. They didn’t rebuild the LangGraph paradigm. They embedded it inside the runtime — where reasoning, recovery, and policy coexist naturally. It’s orchestration without the scaffolding, cognition without the chaos.&lt;/p&gt;

&lt;p&gt;So here’s what I’ve learned: the future of orchestration isn’t about bigger graphs or smarter DAGs. It’s about &lt;strong&gt;trusting the reasoning layer&lt;/strong&gt; to do what the graph used to. And whether that reasoning runs in your own loop, or inside a managed runtime like AgentCore, the principle stays the same:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The system no longer needs to be told how to think, &lt;br&gt;
it just needs to be given the space to reason.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>mcp</category>
      <category>aws</category>
    </item>
    <item>
      <title>Cloud Is No Longer a Specialty — It’s the Operating System of Modern Engineering</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Fri, 05 Sep 2025 12:43:30 +0000</pubDate>
      <link>https://dev.to/onepoint/cloud-is-no-longer-a-specialty-its-the-operating-system-of-modern-engineering-1g5g</link>
      <guid>https://dev.to/onepoint/cloud-is-no-longer-a-specialty-its-the-operating-system-of-modern-engineering-1g5g</guid>
      <description>&lt;p&gt;Walk into almost any engineering org today and you’ll notice the same pattern: the places where code runs, where data lands, where models are trained and served, and where controls are enforced have mostly moved to the cloud. That move didn’t just change our tooling; it rewired how teams work, what “good” looks like, and which skills actually move the needle. This isn’t hype. It’s budget, platform design, and regulation all pointing the same way. Analyst forecasts put 2025 public-cloud end-user spend around $723B and we're on track to reach it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why this became inevitable
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Economics changed first&lt;/strong&gt;. Elastic infrastructure beat capacity planning spreadsheets. Managed services outpaced hand-rolled clusters. And once finance teams could see clear unit costs—per request, per job, per model hour—the conversation shifted from “can we?” to “is it worth it?” Cloud stopped being a cost center and became a lever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Platformization followed&lt;/strong&gt;. To keep speed and governance from fighting, many orgs built internal platforms and developer portals: golden paths, paved roads, templates, and policy baked into CI/CD. This is the heart of platform engineering—product-managing the internal experience so teams can move fast without leaving a compliance crater. The cloud-native community has documented this shift for years, and adoption keeps climbing in larger orgs because complexity demands it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Regulation sealed it&lt;/strong&gt;. In Europe especially, rules now expect traceability, resilience, and portability as a baseline—not a sticker you add later. The EU AI Act applies obligations to general-purpose models starting August 2, 2025; DORA has applied across financial services since January 17, 2025; and the Data Act becomes applicable September 12, 2025, bringing switching and portability into the mainstream. Meeting those obligations is dramatically easier when identity, logging, lineage, and deployment are first-class cloud capabilities—auditable by design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sovereignty raised the bar, not the walls&lt;/strong&gt;. Europe isn’t rolling back cloud; it’s demanding more control. That’s why you see sovereign offerings—EU-operated, EU-resident stacks with stricter controls. For architects, that means designing for residency, autonomy, and reversibility—not retreating to the basement.&lt;/p&gt;

&lt;h2&gt;
  
  
  What actually changes in the roles
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Software engineers&lt;/strong&gt; stop treating “infrastructure” as someone else’s problem. The platform is an API surface: you ship to it, observe through it, and live with the reliability and cost that follow. Knowing how traffic enters, how secrets are granted, how rollouts can be reversed, and how your service shows up on the bill is no longer “nice to have”—it’s part of building a product.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data engineers and analytics folks&lt;/strong&gt; inherit “data as a product.” Contracts, SLOs for freshness, lineage, and lifecycle rules move from slideware to everyday work. Elastic compute is a superpower until you lose track of it; cost-aware designs become a craft. Portability and exit duties under the Data Act make schema choices and platform coupling strategic, not just technical.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI/ML engineers&lt;/strong&gt; are broadening from model concerns to system concerns. As training and inference live deeper in production, the work naturally spans data contracts, storage classes and vector indexes, event-driven orchestration, GPU/SKU choices, and access-control patterns. In Europe, the AI Act doesn’t point fingers; it codifies practices many teams already value—reproducibility, evaluation, and risk management. In practical terms, that means keeping auditable logs, dataset/feature lineage, and evaluation reports alongside model artifacts, so accuracy, latency, cost, and risk can be governed together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Security engineers&lt;/strong&gt; become identity and supply-chain specialists. The shared-responsibility line is clear: providers secure the substrate; you secure identities, configurations, data paths, and the software supply chain. In practice, this means policy-as-code, strong KMS habits, least privilege, and proofs (attestations, SBOMs) embedded in pipelines—because auditors now read YAML. DORA made this non-optional for finance; everyone else is following.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architects&lt;/strong&gt; shift from diagram authors to platform product managers. Your job is curating guardrails that make good choices the easiest ones: standard templates, default policies, sovereign patterns when required, and a small number of blessed paths that cover most work. You measure adoption, lead time, and incident burn, not just conformance.&lt;/p&gt;

&lt;h2&gt;
  
  
  The new baseline
&lt;/h2&gt;

&lt;p&gt;Nobody needs to be an expert in every managed service. You do need to be conversant in the handful of concepts that show up in every design review:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How the app is packaged and rolled out; how it rolls back.&lt;/li&gt;
&lt;li&gt;Where it lives on the network, and what “private by default” means here.&lt;/li&gt;
&lt;li&gt;Which identities it uses, which keys guard data, and who can rotate them.&lt;/li&gt;
&lt;li&gt;What it emits (logs/metrics/traces), which SLOs it’s held to, and how alerts tie to action.&lt;/li&gt;
&lt;li&gt;How it will be audited: data lineage, deployment history, model evaluations if there’s AI in the loop.&lt;/li&gt;
&lt;li&gt;How the costs map to units the business cares about.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are the muscles that translate architecture to outcomes. They make you portable across providers, because the patterns rhyme even when service names don’t. If you’ve ever switched from one framework to another, you know the feeling: a week of vocabulary, then you’re home.&lt;/p&gt;

&lt;h2&gt;
  
  
  Market direction: more cloud, more accountability
&lt;/h2&gt;

&lt;p&gt;Spending is still rising because the work moved there: applications, analytics, and AI. That &lt;strong&gt;~$723B&lt;/strong&gt; 2025 forecast reflects not just growth but consolidation of strategy—organizations are building on a smaller set of managed capabilities and demanding better economics from them. Community surveys show cloud-first and cloud-native practices are no longer outliers; they’re the default in many environments. The cultural follow-through is visible: FinOps disciplines to keep the bill honest, and platform-engineering to keep speed and safety from arguing.&lt;/p&gt;

&lt;p&gt;At the same time, Europe’s regulatory cadence and sovereignty projects point to a world where &lt;strong&gt;cloud proficiency includes governance proficiency&lt;/strong&gt;: knowing how to prove where data lives, who touched it, how a model was evaluated, and how fast you can exit or fail over. That’s not a step backward—it’s the maturity curve technologies go through when they become infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this doesn’t fully apply (yet)
&lt;/h2&gt;

&lt;p&gt;Reality is messy. Plenty of orgs are mid-migration or still discovering their platform identity. Some workloads—industrial/OT, defense, certain HPC or ultra-low-latency use cases, deeply embedded stacks—will stay hybrid or on-prem for good reasons. There’s also a visible current of “repatriation” and cost-driven hybridization. None of that contradicts the thesis. It raises the bar on &lt;strong&gt;discipline&lt;/strong&gt;: good identity, IaC, policy-as-code, and supply-chain hygiene travel well between clouds, regions, and data centers. Sovereign setups add necessary constraints; they don’t erase the need for cloud-literate engineering.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do with this
&lt;/h2&gt;

&lt;p&gt;Own the path from code to value. If you’re a software engineer, be able to explain your rollout, identity, SLO, and unit cost without phoning a friend. If you’re in data or ML, treat datasets and models like products—with owners, contracts, and budgets. If you’re in security, bring policy-as-code and supply-chain proofs into development early. If you’re an architect, act like a platform PM: choose a few defaults, measure adoption, and invest in governance that developers can feel—not paperwork they ignore.&lt;/p&gt;

&lt;p&gt;Cloud isn’t a badge anymore. It’s the operating system of the modern engineering org. Learn to speak it fluently and you won't just keep up, you'll lead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion: where seniority now comes from
&lt;/h2&gt;

&lt;p&gt;As AI weaves itself into every product, seniority isn’t measured by stack trivia or how many models you can fine-tune. It’s measured by your ability to connect the pieces—platform, data, security, compliance—and to set sane defaults so teams can ship safely at scale. That redefinition of roles is the value add: the software engineer who speaks IAM and SLOs as naturally as APIs; the data/ML engineer who treats datasets and models as governed products; the security engineer who codes policy and supply-chain proofs; the architect who product-manages the platform.&lt;/p&gt;

&lt;p&gt;Call it end-to-end ownership with judgment. When you can explain where the data lives, how the system fails, what it costs, and why a decision is acceptable under the AI Act or DORA, you’re not just keeping up—you’re raising the bar. That’s the kind of engineering AI rewards—not more heroics, but better guardrails, clearer trade-offs, faster learning loops. That’s what senior looks like now.&lt;/p&gt;




&lt;p&gt;Sources :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ciodive.com&lt;/li&gt;
&lt;li&gt;tag-app-delivery.cncf.io&lt;/li&gt;
&lt;li&gt;info.getport.io&lt;/li&gt;
&lt;li&gt;digital-strategy.ec.europa.eu&lt;/li&gt;
&lt;li&gt;wsj.com&lt;/li&gt;
&lt;li&gt;esma.europa.eu&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>cloud</category>
      <category>devops</category>
      <category>ai</category>
      <category>data</category>
    </item>
    <item>
      <title>How to Create a Web Search AI Agent with AWS Bedrock</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Fri, 25 Jul 2025 16:32:50 +0000</pubDate>
      <link>https://dev.to/onepoint/how-to-create-a-web-search-ai-agent-with-aws-bedrock-5f1k</link>
      <guid>https://dev.to/onepoint/how-to-create-a-web-search-ai-agent-with-aws-bedrock-5f1k</guid>
      <description>&lt;p&gt;Amazon Bedrock Agents let you build autonomous agents powered by LLMs that can reason, act, and interact with APIs, data sources, and users. Based on the ReAct paradigm, they break down tasks, perform API calls, and integrate with knowledge bases—all without needing to manage underlying infra.&lt;/p&gt;

&lt;p&gt;By combining Bedrock Agents with web search APIs, you can extend your chatbot with real-time access to internet content. This unlocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live web queries in-chat – Keep users in the conversation while retrieving up-to-date info.&lt;/li&gt;
&lt;li&gt;Context-aware actions – Use CoT prompting to decide when to call APIs or search the web.&lt;/li&gt;
&lt;li&gt;Smarter responses – Blend internal knowledge and external data for more relevant replies.&lt;/li&gt;
&lt;li&gt;Fast setup – Add dynamic search with minimal config, and deploy via CloudFormation or CDK.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This integration gives your AI apps richer, more accurate responses while keeping UX simple. Ideal for building more helpful, responsive chatbots—without reinventing the wheel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Global Solution
&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%2Fnisgb1duscw3podw407a.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%2Fnisgb1duscw3podw407a.png" alt="flowchart" width="441" height="181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An Amazon Bedrock agent acts as the central orchestrator between the user and external web search APIs. It manages the conversation flow, handles optional memory, and the web search.&lt;/p&gt;

&lt;p&gt;Search logic is offloaded to an AWS Lambda function, which is responsible for calling a third-party search provider and formatting the results.&lt;/p&gt;

&lt;p&gt;We rely on &lt;a href="https://serper.dev/" rel="noopener noreferrer"&gt;Serper API&lt;/a&gt; for the web search. It provides up-to-date, real-time information&lt;/p&gt;

&lt;p&gt;API keys for these services are securely stored and accessed via AWS Secrets Manager.&lt;/p&gt;

&lt;p&gt;Amazon Bedrock foundation models (Claude 3 Haiku for celerity) handle natural language generation, crafting final answers based on the retrieved content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account&lt;/li&gt;
&lt;li&gt;AWS CLI configured with your AWS account&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configure the Serper API
&lt;/h2&gt;

&lt;p&gt;Serper API offers a web search service that integrates easily with Amazon Bedrock agents via RESTful calls from a Lambda function. It supports multiple search engines like Google, Bing, and Yahoo, and gives control over query parameters and result types—such as organic results, featured snippets, images, or videos.&lt;/p&gt;

&lt;p&gt;This makes Serper a solid choice when you need access to specific search engine features or want results aggregated from multiple sources.&lt;/p&gt;

&lt;p&gt;For this example, we’re using Serper API exclusively, with API keys securely stored in AWS Secrets Manager and accessed from the Lambda function during execution. You can use this AWS CLI command to create the secret :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws secretsmanager create-secret &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; SERPER_API_KEY &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--description&lt;/span&gt; &lt;span class="s2"&gt;"The API secret key for Serper."&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--secret-string&lt;/span&gt; &lt;span class="s2"&gt;"&amp;lt;SERPER_API_KEY&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that the API is configured, we can start building the web search Amazon Bedrock agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Web search AWS Bedrock agent using the console
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create a web search agent
&lt;/h3&gt;

&lt;p&gt;To create a web search agent using the console, complete the following steps:&lt;/p&gt;

&lt;p&gt;1) On the Amazon Bedrock console, choose Agents in the navigation pane.&lt;br&gt;
2) Choose Create agent.&lt;br&gt;
3) Enter a name for the agent (such as websearch-agt) and an a description, then choose Create.&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%2Fmqc0m83x8hpoojudqxys.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%2Fmqc0m83x8hpoojudqxys.png" alt="agent-screenshot" width="800" height="700"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We are now in the new agent builder screen, where we can access and edit the configuration of an agent.&lt;/p&gt;

&lt;p&gt;4) For Agent resource role, leave the default Create and use a new service role&lt;br&gt;
5) For the model, we choose Anthropic and Claude Haiku 3 (if not available, you can claim access in the model access menu of Bedrock)&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%2Fjtepng7q4q37ulw46ql0.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%2Fjtepng7q4q37ulw46ql0.png" alt="agent-config" width="800" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;6) Here are the instructions for the agent. You can enhance it if you feel comfortable enought to do so :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are an agent that can help users do research and finding up-to-date information. For up-to-date information always uses web search. Web search uses Google Search - this is great for looking up up-to-date information and current events.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;7) Choose &lt;strong&gt;Add&lt;/strong&gt; button in &lt;strong&gt;Action groups&lt;/strong&gt;. Those groups enable us to trigger the lambda function when needed.&lt;br&gt;
8) For &lt;strong&gt;Enter action group&lt;/strong&gt; name, enter &lt;code&gt;action-group-websearch&lt;/code&gt;.&lt;br&gt;
9) For &lt;strong&gt;Action group type&lt;/strong&gt;, select &lt;strong&gt;Define with function details&lt;/strong&gt; so you can specify a function and its parameters as JSON instead of providing an Open API schema.&lt;br&gt;
10) For &lt;strong&gt;Action group invocation&lt;/strong&gt;, set up what the agent does after this action group is identified by the model. Because we want to call the web search APIs, select &lt;strong&gt;Quick create a new Lambda function&lt;/strong&gt;.&lt;br&gt;
With this option, Amazon Bedrock creates a basic Lambda function for your agent that you can later modify on the Lambda console for the use case of calling the web search API. The agent will predict the function and function parameters needed to fulfil its goal and pass the parameters to the Lambda function.&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%2Fawbdjmqxwwr544l98537.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%2Fawbdjmqxwwr544l98537.png" alt="group-action-config" width="800" height="694"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;11) Now, configure the Serper API Google search function for the action group with name google-search and the description of your choice.&lt;br&gt;
12) Add a query parameter of type String for the search query.&lt;br&gt;
13) Choose &lt;strong&gt;Create&lt;/strong&gt; to complete the action group creation.&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%2F459fofq6gxgssymjco0o.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%2F459fofq6gxgssymjco0o.png" alt="action-config" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;14) Choose &lt;strong&gt;Save&lt;/strong&gt; to save the agent configuration&lt;/p&gt;
&lt;h3&gt;
  
  
  Lambda function configuration &amp;amp; code
&lt;/h3&gt;

&lt;p&gt;1) On the Lambda console, look for the function with the name &lt;code&gt;action_group_websearch-&amp;lt;code&amp;gt;&lt;/code&gt;.&lt;br&gt;
2) Edit this function and replace the existing code with this one :&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;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;http.client&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="c1"&gt;# Logging setup
&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;basicConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;level&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;logging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;__name__&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Environment config
&lt;/span&gt;&lt;span class="n"&gt;AWS_REGION&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_REGION&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;us-east-1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# change with your region
&lt;/span&gt;&lt;span class="n"&gt;ACTION_GROUP_NAME&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ACTION_GROUP&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;action-group-websearch&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;SERPER_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&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="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPER_API_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Fallback to Secrets Manager if key not in env
&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;SERPER_API_KEY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;secrets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;secretsmanager&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;region_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AWS_REGION&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;SERPER_API_KEY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_secret_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SecretId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SERPER_API_KEY&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;SecretString&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# Extracts query parameters
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;extract_search_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionGroup&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="n"&gt;ACTION_GROUP_NAME&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid action group&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;

    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&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;p&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;event&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parameters&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;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;params&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;params&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;target_website&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="c1"&gt;# Calls Serper API
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;google_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;target_site&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&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;target_site&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&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; site:&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;target_site&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="n"&gt;headers&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;X-API-KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;SERPER_API_KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Content-Type&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;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;HTTPSConnection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;google.serper.dev&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;POST&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;/news&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getresponse&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Lambda entry point
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;lambda_handler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extract_search_params&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;query&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;error&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;Missing query&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;google_search&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;site&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="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;response&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;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionGroup&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;actionGroup&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;function&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;function&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;functionResponse&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;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;responseBody&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;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;TEXT&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;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&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;Here are the top search results for &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="si"&gt;}&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;results&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="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&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;messageVersion&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;event&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messageVersion&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;p&gt;3) Click on &lt;strong&gt;Deploy&lt;/strong&gt; to deploy the code.&lt;/p&gt;

&lt;p&gt;By default, the Lambda's default resource policy already has the right premissions to be called from the agent since we created it from the agent action group.&lt;br&gt;
But since we use Secret Manager in the lambda, we need to add this permission to the lambda's role :&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;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"secretsmanager:GetSecretValue"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&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="s2"&gt;"arn:aws:secretsmanager:&amp;lt;REGION&amp;gt;:&amp;lt;ACCOUNT_ID&amp;gt;:secret:SERPER_API_KEY*"&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;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"GetSecretsManagerSecret"&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;Don't forget to replace &lt;strong&gt;REGION&lt;/strong&gt; and &lt;strong&gt;ACCOUNT_ID&lt;/strong&gt; with yours.&lt;/p&gt;

&lt;h3&gt;
  
  
  Test the agent
&lt;/h3&gt;

&lt;p&gt;You’re now ready to test the agent.&lt;/p&gt;

&lt;p&gt;1) On the Amazon Bedrock console, on the websearch-agt details page, choose Test.&lt;br&gt;
2) Choose &lt;strong&gt;Prepare&lt;/strong&gt; to load the agent.&lt;br&gt;
3) Ask a question to your agent. Example : "Who won the latest Champions League ?" (yes, I'm french ;D)&lt;br&gt;
4) You should now be able to recieve the answer from your agent. You can now click on &lt;strong&gt;Show trace&lt;/strong&gt; to understand the decision and sources of the agent.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final thougts
&lt;/h2&gt;

&lt;p&gt;Here we are : we are now able to do a web search in our agentic architectures. This is a powerful and an anovoidable feature that you will obviously need to have.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>aws</category>
      <category>llm</category>
    </item>
    <item>
      <title>AWS Kiro: Another AI-Powered IDE Challenger or a Game Changer?</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Tue, 15 Jul 2025 14:15:37 +0000</pubDate>
      <link>https://dev.to/onepoint/aws-kiro-another-ai-powered-ide-challenger-or-a-game-changer-1bj8</link>
      <guid>https://dev.to/onepoint/aws-kiro-another-ai-powered-ide-challenger-or-a-game-changer-1bj8</guid>
      <description>&lt;p&gt;&lt;em&gt;AWS has released Kiro, a new AI-powered IDE with built-in agentic workflows, specification generation, and cloud integration. But how does it compare to established tools like GitHub Copilot, Google Gemini Code Assist, or Cursor?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As AI coding assistants evolve from simple autocomplete tools into fully agentic systems, a new category of IDEs is emerging — ones that help you plan, structure, test, and ship code end-to-end.&lt;/p&gt;

&lt;p&gt;This article provides a deep, technical comparison between &lt;strong&gt;AWS Kiro&lt;/strong&gt;, &lt;strong&gt;GitHub Copilot Agent Mode&lt;/strong&gt;, &lt;strong&gt;Google Gemini Code Assist&lt;/strong&gt;, and &lt;strong&gt;Cursor&lt;/strong&gt;, focusing on their features, workflows, and usage in real-world developer contexts.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is AWS Kiro?
&lt;/h2&gt;

&lt;p&gt;Kiro is an AI-native IDE developed by AWS, built as a customized fork of VS Code (based on Code-OSS). It focuses on specification-driven development and provides out-of-the-box support for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Agent-assisted task decomposition,&lt;/li&gt;
&lt;li&gt;Automatic generation of technical specifications (&lt;code&gt;requirements.md&lt;/code&gt;, &lt;code&gt;design.md&lt;/code&gt;, etc.),&lt;/li&gt;
&lt;li&gt;Integration of infrastructure as code (AWS CDK, SAM, Terraform),&lt;/li&gt;
&lt;li&gt;Built-in hooks for tests, documentation, and security checks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kiro works locally and integrates with AWS services (Bedrock, IAM...), but it can also be used in other environments (e.g., with GitHub or local repos).&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature Category&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Kiro (AWS)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Copilot Agent (GitHub)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Gemini Code Assist (Google)&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cursor (Anysphere)&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Spec Generation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Automatic &lt;code&gt;requirements.md&lt;/code&gt;, &lt;code&gt;design.md&lt;/code&gt;, &lt;code&gt;tasks.md&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌ No automatic spec generation&lt;/td&gt;
&lt;td&gt;❌ Manual via chat&lt;/td&gt;
&lt;td&gt;⚠️ Prompt-based only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Code Agent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Plans and implements across multiple files&lt;/td&gt;
&lt;td&gt;✅ Handles multi-file context&lt;/td&gt;
&lt;td&gt;✅ Assisted actions, test generation&lt;/td&gt;
&lt;td&gt;✅ Contextual refactoring and commands&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pre-Commit Hooks&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Built-in test, lint, doc, security checks&lt;/td&gt;
&lt;td&gt;❌ Manual setup or external tooling&lt;/td&gt;
&lt;td&gt;❌ Reactive suggestions only&lt;/td&gt;
&lt;td&gt;⚠️ Partial automation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infrastructure Gen&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Supports AWS CDK, SAM, Terraform&lt;/td&gt;
&lt;td&gt;⚠️ Requires separate configuration&lt;/td&gt;
&lt;td&gt;⚠️ No infra scaffolding features&lt;/td&gt;
&lt;td&gt;❌ Not infra-oriented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;IDE Integration&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Native VS Code fork&lt;/td&gt;
&lt;td&gt;✅ Official VS Code extension&lt;/td&gt;
&lt;td&gt;✅ VS Code, IntelliJ, Android Studio&lt;/td&gt;
&lt;td&gt;✅ Custom VS Code fork&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloud Alignment&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;🌩️ AWS-native (IAM, Bedrock)&lt;/td&gt;
&lt;td&gt;☁️ GitHub + Azure&lt;/td&gt;
&lt;td&gt;☁️ Google Cloud oriented&lt;/td&gt;
&lt;td&gt;☁️ Cloud-agnostic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Steering/Rules&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ &lt;code&gt;.kiro/steering&lt;/code&gt; for project coding norms&lt;/td&gt;
&lt;td&gt;⚠️ Prompt-defined preferences only&lt;/td&gt;
&lt;td&gt;⚠️ No native steering&lt;/td&gt;
&lt;td&gt;⚠️ Custom plugins or config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MCP Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;td&gt;✅ Yes&lt;/td&gt;
&lt;td&gt;❌ No&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Workflow differences
&lt;/h2&gt;

&lt;p&gt;A key difference between these IDEs is &lt;strong&gt;how much structure they impose or support&lt;/strong&gt;.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;You define a goal or description.&lt;/li&gt;
&lt;li&gt;Kiro generates structured specs (requirements, design).&lt;/li&gt;
&lt;li&gt;It decomposes tasks and assigns them to agents.&lt;/li&gt;
&lt;li&gt;On save or commit, it can run tests, linting, documentation generation, and security scanning.&lt;/li&gt;
&lt;li&gt;Optionally scaffolds infrastructure code with IaC tools.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GitHub Copilot Agent Mode:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You prompt it in chat or command mode.&lt;/li&gt;
&lt;li&gt;It generates code and can make edits across multiple files.&lt;/li&gt;
&lt;li&gt;It’s highly reactive but requires manual steering.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Gemini Code Assist:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Offers code suggestions, test generation, and chat interface.&lt;/li&gt;
&lt;li&gt;CLI (Gemini CLI) supports shell commands and task automation.&lt;/li&gt;
&lt;li&gt;It’s focused on augmenting the developer rather than enforcing structure.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Focused on large-scale code refactoring, search, and editing.&lt;/li&gt;
&lt;li&gt;Excellent for legacy or unfamiliar codebases.&lt;/li&gt;
&lt;li&gt;Less opinionated — leaves decisions to the developer.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Plan&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Kiro&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Copilot Pro&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Gemini Free&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;50 agent tasks/month&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅ ~180k completions&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro&lt;/td&gt;
&lt;td&gt;\$19/month (1k tasks)&lt;/td&gt;
&lt;td&gt;\$10/month&lt;/td&gt;
&lt;td&gt;–&lt;/td&gt;
&lt;td&gt;\$20–\$30/month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pro+&lt;/td&gt;
&lt;td&gt;\$39/month (3k tasks)&lt;/td&gt;
&lt;td&gt;Enterprise pricing&lt;/td&gt;
&lt;td&gt;Enterprise plans&lt;/td&gt;
&lt;td&gt;Enterprise pricing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do You Need to Pay for AWS Bedrock Separately?&lt;/p&gt;

&lt;p&gt;No, unless you configure Kiro to use your own Bedrock models:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Default setup (e.g. Claude Sonnet) → included in Kiro’s pricing&lt;/li&gt;
&lt;li&gt;⚠️ Custom models via .kiro/agents.yaml → billed separately by AWS&lt;/li&gt;
&lt;li&gt;⚠️ External Bedrock calls via CLI/plugins → also billed by AWS&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;👉 For most users, there's no extra Bedrock cost unless you opt into advanced configurations. Beware with this.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to Use Which Tool
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use Case&lt;/th&gt;
&lt;th&gt;Best Fit&lt;/th&gt;
&lt;th&gt;Reasoning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Structured app development&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Kiro&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Provides specs, infra scaffolding, QA hooks&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rapid prototyping / GitHub-native&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Copilot Agent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Integrated in GitHub and VS Code, great for agile teams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Personal or lightweight usage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Gemini&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Free, minimal setup, multiplatform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Legacy code or refactoring&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Cursor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Advanced context navigation and editing capabilities&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Pros and Cons of Kiro
&lt;/h2&gt;

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

&lt;ul&gt;
&lt;li&gt;Structured dev flow (design → tasks → code → deploy)&lt;/li&gt;
&lt;li&gt;Agentic hooks (test, lint, scan on save/commit)&lt;/li&gt;
&lt;li&gt;Infrastructure-as-code support&lt;/li&gt;
&lt;li&gt;Ideal for production environments&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;Currently in preview; evolving rapidly&lt;/li&gt;
&lt;li&gt;Requires AWS Builder ID / IAM role for full integration&lt;/li&gt;
&lt;li&gt;Interaction quotas tied to pricing tiers&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  How to Use Kiro Effectively ?
&lt;/h2&gt;

&lt;p&gt;Kiro introduces a workflow that differs from traditional IDEs. To get the most out of it, it's worth adapting your habits slightly to embrace its agentic, spec-driven model.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation &amp;amp; Setup
&lt;/h3&gt;

&lt;p&gt;Kiro is currently in public preview and can be installed locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew &lt;span class="nb"&gt;install &lt;/span&gt;aws/tap/kiro  &lt;span class="c"&gt;# macOS&lt;/span&gt;
kiro login                 &lt;span class="c"&gt;# authenticate via AWS Builder ID, IAM, or GitHub&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also download platform-specific installers from &lt;a href="https://kiro.dev/downloads/" rel="noopener noreferrer"&gt;kiro.dev&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For the authentication, Kiro supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS Builder ID&lt;/li&gt;
&lt;li&gt;IAM roles&lt;/li&gt;
&lt;li&gt;GitHub or Google accounts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you're deploying or using Bedrock models (e.g., Claude Sonnet), you’ll need AWS credentials configured locally via aws configure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Bootstrapping
&lt;/h3&gt;

&lt;p&gt;You can start from scratch or use an existing codebase. In either case, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kiro init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;Sets up the .kiro/ directory (for agent config and steering rules)&lt;/li&gt;
&lt;li&gt;Creates empty spec files (&lt;code&gt;requirements.md&lt;/code&gt;, &lt;code&gt;design.md&lt;/code&gt;, etc.)&lt;/li&gt;
&lt;li&gt;Connects your repo to Kiro's agent backend&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Using Agents to Build Features
&lt;/h3&gt;

&lt;p&gt;With Kiro running, press Cmd+K (or via Command Palette) and describe a feature:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;"Build a CRUD REST API for invoices with validation and automated tests."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiro will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generate a plan (&lt;code&gt;tasks.md&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Write or scaffold relevant code across files&lt;/li&gt;
&lt;li&gt;Propose tests, docs, and infra (if enabled)&lt;/li&gt;
&lt;li&gt;Apply your .kiro/steering coding standards&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can refine behavior via config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# .kiro/steering/rules.yaml&lt;/span&gt;
&lt;span class="na"&gt;rules&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;prefer_lib&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;zod&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;enforce_test_coverage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;infra&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;terraform&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pre-Commit Quality Hooks
&lt;/h3&gt;

&lt;p&gt;Kiro can automatically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Run unit tests (npm test, pytest, etc.)&lt;/li&gt;
&lt;li&gt;Lint your codebase&lt;/li&gt;
&lt;li&gt;Check security rules (via integrated scans)&lt;/li&gt;
&lt;li&gt;Regenerate documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, these hooks run on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;File save&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git commit&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Configure hook behavior in &lt;code&gt;.kiro/config.yaml&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure Integration
&lt;/h3&gt;

&lt;p&gt;Kiro supports scaffolding with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS CDK&lt;/li&gt;
&lt;li&gt;AWS SAM&lt;/li&gt;
&lt;li&gt;Terraform&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kiro infra add dynamodb-table &lt;span class="nt"&gt;--stack&lt;/span&gt; invoice-db
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kiro can then deploy the stack using your local AWS credentials or CloudFormation pipeline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Agent Workflows
&lt;/h3&gt;

&lt;p&gt;Kiro agents aren't just for code generation, they can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitor task progress&lt;/li&gt;
&lt;li&gt;Keep specs up to date&lt;/li&gt;
&lt;li&gt;Detect stale or undocumented changes&lt;/li&gt;
&lt;li&gt;Suggest updates when your code diverges from the plan&lt;/li&gt;
&lt;/ul&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kiro &lt;span class="nb"&gt;sync&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To refresh your spec and design files based on recent code edits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tips
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Start every feature with a description&lt;/strong&gt;, not just code — Kiro thrives on intent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use&lt;/strong&gt; &lt;code&gt;.kiro/steering&lt;/code&gt; to define how your team writes code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Let agents run tests and scans early&lt;/strong&gt; — they'll prevent issues from escalating.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adopt it gradually&lt;/strong&gt; — it plays nicely with existing tools, including Git, VS Code, and AWS CLI.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Kiro isn’t trying to replace Copilot — it’s targeting a different layer of software engineering. Where Copilot and Gemini are productivity tools, Kiro is a structure enforcer. It brings planning, design, QA, and infra together in a single, AI-supported loop.&lt;/p&gt;

&lt;p&gt;For teams building long-lived, production-grade applications — especially in AWS environments — Kiro offers strong value.&lt;/p&gt;

&lt;p&gt;That said, if your needs are exploratory, fast-paced, or centered on legacy code, tools like Copilot or Cursor may remain more flexible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Do You Think?
&lt;/h2&gt;

&lt;p&gt;Have you tested Kiro? Planning to?&lt;/p&gt;

&lt;p&gt;Feel free to share your thoughts in the comments — real-world feedback is essential to evaluate how tools like this actually change development workflows.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>development</category>
      <category>ide</category>
      <category>ai</category>
    </item>
    <item>
      <title>How to become a Staff Software Engineer</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Mon, 12 May 2025 07:57:14 +0000</pubDate>
      <link>https://dev.to/onepoint/how-to-become-a-staff-software-engineer-1l7h</link>
      <guid>https://dev.to/onepoint/how-to-become-a-staff-software-engineer-1l7h</guid>
      <description>&lt;p&gt;I didn’t set out to become a Staff Engineer. It wasn’t part of some grand plan. But over time, I realized that the most important problems I could work on weren’t on my team’s backlog, and sometimes weren’t even clearly defined. What follows isn’t a formula, just a reflection of the kinds of shifts that made a difference for me and for others I’ve learned from along the way.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Nature of Impact Changes
&lt;/h2&gt;

&lt;p&gt;As a Senior Engineer, you're valued for your ability to deliver. You own features end-to-end, manage technical complexity, and often mentor others along the way. You’re fast, autonomous, and reliable.&lt;/p&gt;

&lt;p&gt;At the Staff+ level, the work shifts from execution to &lt;strong&gt;enablement&lt;/strong&gt;. Your job becomes helping &lt;strong&gt;others&lt;/strong&gt; deliver more effectively across teams, across quarters, and often without directly writing the code yourself.&lt;/p&gt;

&lt;p&gt;You might spot a flaw in a planned architecture that avoids months of rework. You might introduce a pattern or internal tool that quietly makes onboarding smoother for every new hire. You might remove a blocker between two teams who didn’t even realize they were misaligned.&lt;/p&gt;

&lt;p&gt;In a way, your success becomes more abstract and often less visible. But its effects compound.&lt;/p&gt;




&lt;h2&gt;
  
  
  Scope Becomes Organizational
&lt;/h2&gt;

&lt;p&gt;One clear shift is the &lt;strong&gt;expansion of scope&lt;/strong&gt;. Not in terms of technical breadth for its own sake, but in the number of people and systems your decisions touch.&lt;/p&gt;

&lt;p&gt;Instead of focusing on “how we build this feature well,” you start asking questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Should this system even be built?&lt;/li&gt;
&lt;li&gt;If we do this, how will it affect other teams six months from now?&lt;/li&gt;
&lt;li&gt;Who’s responsible for maintaining this? Will they still be here?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this level, you’re expected to think in &lt;strong&gt;systems&lt;/strong&gt;: not just technical systems, but &lt;strong&gt;organizational ones&lt;/strong&gt;. And your ability to navigate those systems starts to matter as much as your ability to write code.&lt;/p&gt;

&lt;p&gt;At Meta, Staff Engineers are frequently brought into projects &lt;em&gt;not&lt;/em&gt; because of their domain expertise, but because they can identify how choices made today will affect infrastructure, team autonomy, and platform stability a year from now.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ambiguity Becomes the Default
&lt;/h2&gt;

&lt;p&gt;Staff+ engineers gravitate toward poorly scoped, high-risk, politically sensitive problems, because they’re often the only ones in a position to handle them.&lt;/p&gt;

&lt;p&gt;Sometimes it’s technical: “This legacy system is a mess and no one owns it, but we’re scaling fast and it’s now a bottleneck.”&lt;/p&gt;

&lt;p&gt;Sometimes it’s organizational: “Two teams are solving the same problem in parallel. Their solutions don’t align. Leadership hasn’t noticed.”&lt;/p&gt;

&lt;p&gt;These problems don’t come with tickets. They don’t even always come with permission. But solving them creates space for others to move faster, more safely, and more clearly.&lt;/p&gt;

&lt;p&gt;At Stripe, a Staff engineer once took on standardizing observability tooling, not because it was glamorous, but because dozens of engineers were wasting time reinventing similar dashboards in different ways. No one owned the problem. She did. And in doing so, she cleared a path for dozens of teams.&lt;/p&gt;




&lt;h2&gt;
  
  
  You Lead Without Authority
&lt;/h2&gt;

&lt;p&gt;Staff Engineers often lead projects where no one reports to them. Influence happens through clarity, credibility, and trust: not hierarchy.&lt;/p&gt;

&lt;p&gt;That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Asking better questions than giving perfect answers&lt;/li&gt;
&lt;li&gt;Offering direction without dismissing opposing views&lt;/li&gt;
&lt;li&gt;Getting buy-in not because you’re senior, but because your logic holds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In many tech companies (Google, for example) some of the most impactful engineers are those who can walk into a messy, cross-team situation and bring calm, technical reasoning to the table. They don’t push harder. They create alignment.&lt;/p&gt;

&lt;p&gt;This work can be frustrating. You’ll spend more time in conversations than in code. But when you do it well, entire teams move more effectively.&lt;/p&gt;




&lt;h2&gt;
  
  
  Technical Depth Still Matters
&lt;/h2&gt;

&lt;p&gt;Being Staff doesn’t mean giving up technical skill. In fact, your credibility often hinges on it.&lt;/p&gt;

&lt;p&gt;But instead of being deep in &lt;strong&gt;everything&lt;/strong&gt;, you’re expected to be deep in something and fluent in how it connects to everything else.&lt;/p&gt;

&lt;p&gt;You might be the person who understands caching and latency behavior better than anyone else on the platform. Or the one who can anticipate failure modes in distributed systems before they hit production. Or maybe you’ve earned trust by consistently cleaning up architectural debt in a pragmatic way.&lt;/p&gt;

&lt;p&gt;At Netflix, Staff+ engineers are often seen jumping into highly focused technical deep dives when they matter most, during incident response, during a high-stakes redesign, or when no one else knows quite where to start. Their expertise is a scalpel, not a hammer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Writing Is a Core Part of the Job
&lt;/h2&gt;

&lt;p&gt;Staff-level engineers are expected to scale their thinking beyond themselves. That means communicating ideas in ways that last across time zones, org charts, and reorgs.&lt;/p&gt;

&lt;p&gt;Design docs. Technical strategies. Memos. Decision records. Naming proposals. Postmortems. Lessons learned...&lt;/p&gt;

&lt;p&gt;If you can't explain the “why” behind a decision or the trade-offs that were considered, you're not operating at Staff level yet.&lt;/p&gt;




&lt;h2&gt;
  
  
  You Create Leverage, Not Velocity
&lt;/h2&gt;

&lt;p&gt;One of the toughest transitions is letting go of individual productivity as your core identity.&lt;/p&gt;

&lt;p&gt;It can feel uncomfortable to spend an entire week:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unblocking another team’s architecture&lt;/li&gt;
&lt;li&gt;Mentoring three engineers through design reviews&lt;/li&gt;
&lt;li&gt;Refactoring a strategy doc for clarity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But that work, while not “productive” in the traditional sense, creates leverage. It &lt;strong&gt;increases the speed and quality of decision-making&lt;/strong&gt; across the org. And that’s far more valuable than a few extra commits.&lt;/p&gt;

&lt;p&gt;At Google, Staff Engineers are frequently evaluated not on how much they shipped but on how much shipping they made possible.&lt;/p&gt;




&lt;h2&gt;
  
  
  You Don't Wait for Permission
&lt;/h2&gt;

&lt;p&gt;Many of the highest-impact things you’ll do at Staff level won’t be assigned to you.&lt;/p&gt;

&lt;p&gt;You’ll see something broken or inefficient something that slows teams down, causes confusion, or erodes confidence and instead of walking past it, you’ll stop. You’ll dig. You’ll propose a fix. And you’ll carry it through.&lt;/p&gt;

&lt;p&gt;You don’t do this for credit. You do it because it’s necessary.&lt;/p&gt;

&lt;p&gt;Often, the clearest indicator that someone is ready for a Staff title is that they're &lt;strong&gt;already doing the work&lt;/strong&gt;, without waiting for the role to make it official.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Didn’t Work
&lt;/h2&gt;

&lt;p&gt;Along the way, some instincts that served me well at the Senior level turned out to be limiting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Trying to scale impact by coding more hours&lt;/li&gt;
&lt;li&gt;Accepting every request instead of focusing on what truly moves the needle&lt;/li&gt;
&lt;li&gt;Assuming good work would always be recognized without communicating it&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Letting go of those reflexes, especially the drive to “just do it myself”,  was uncomfortable, but necessary.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;Becoming a Staff+ Engineer isn’t about being faster, louder, or smarter than your peers. It’s about changing your relationship to &lt;strong&gt;impact&lt;/strong&gt;, &lt;strong&gt;scope&lt;/strong&gt;, and &lt;strong&gt;responsibility&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It’s about becoming the person who:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Brings clarity where there’s confusion&lt;/li&gt;
&lt;li&gt;Sees risk where others see progress&lt;/li&gt;
&lt;li&gt;Connects dots others didn’t realize were connected&lt;/li&gt;
&lt;li&gt;Makes other people better by how they think and work&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Clarity, trust, and long-term thinking.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
That’s what made the difference for me and what I look for when I see others growing into this kind of role.&lt;/p&gt;

&lt;p&gt;There’s no single path to get there. But if you're already showing up like that, your title will probably catch up eventually.&lt;/p&gt;




&lt;h3&gt;
  
  
  Further Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://staffeng.com/book" rel="noopener noreferrer"&gt;&lt;em&gt;Staff Engineer – Will Larson&lt;/em&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://principles.dev/" rel="noopener noreferrer"&gt;Principles of Staff Engineering&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://netflixtechblog.com/" rel="noopener noreferrer"&gt;Netflix Tech Blog&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://charity.wtf/2017/05/11/the-engineer-manager-pendulum/" rel="noopener noreferrer"&gt;Being Glue – Charity Majors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>softwareengineering</category>
      <category>programming</category>
      <category>career</category>
      <category>coding</category>
    </item>
    <item>
      <title>Supercharge Your Spring Boot App with Java 21 and Native Image</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Tue, 06 May 2025 08:00:05 +0000</pubDate>
      <link>https://dev.to/onepoint/supercharge-your-spring-boot-app-with-java-21-and-native-image-439k</link>
      <guid>https://dev.to/onepoint/supercharge-your-spring-boot-app-with-java-21-and-native-image-439k</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: We migrated a classic Spring Boot microservice to Spring Boot 3 + Java 21 + GraalVM Native Image + Virtual Threads. We dropped cold starts from 3.4s to 75ms and cut memory usage by 4x — without rewriting the world. Here's how we did it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;A few months back, our &lt;code&gt;invoice-service&lt;/code&gt; was what you'd call "classic enterprise Java service"... it worked fine, until it didn’t.&lt;/p&gt;

&lt;p&gt;Many alerts because of too long startup times. Memory usage kept creeping up. Scaling wasn't instant. We were paying for warm-up time on Kubernetes like it was 2015.&lt;/p&gt;

&lt;p&gt;We knew something had to change.&lt;/p&gt;

&lt;p&gt;This is the story of how we made that service &lt;strong&gt;native, fast, and cloud-ready&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Service: What We Started With
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;invoice-service&lt;/code&gt; handles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Invoice persistence (via JPA)&lt;/li&gt;
&lt;li&gt;PDF generation (Apache PDFBox)&lt;/li&gt;
&lt;li&gt;Calling an external payment API&lt;/li&gt;
&lt;li&gt;Sending out emails&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Basically: I/O, I/O, and more I/O.&lt;/p&gt;

&lt;p&gt;Here’s the old stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Java 11&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Spring Boot 2.7&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RestTemplate&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fat JAR Docker build (~250MB)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Cold start in K8s: &lt;strong&gt;~3.4 seconds&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Memory: &lt;strong&gt;~220MB idle&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It ran, sure — but it was sluggish. Not exactly cloud native friendly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Java 21 + Spring Boot 3
&lt;/h2&gt;

&lt;p&gt;We bit the bullet and upgraded. Honestly, the Jakarta EE namespace migration was more annoying than hard:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;javax.persistence -&amp;gt; jakarta.persistence
javax.servlet -&amp;gt; jakarta.servlet
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Painful? A little. But manageable.&lt;/p&gt;

&lt;p&gt;Once we were on &lt;strong&gt;Spring Boot 3.2 + Java 21&lt;/strong&gt;, we got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Hibernate 6&lt;/strong&gt; with improved performance&lt;/li&gt;
&lt;li&gt;Out-of-the-box &lt;strong&gt;observability&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Support for &lt;strong&gt;virtual threads&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;AOT and native image support baked in&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Already, startup dropped to &lt;strong&gt;~2.1 seconds&lt;/strong&gt; — not bad for zero code change.&lt;/p&gt;




&lt;h2&gt;
  
  
  Virtual Threads to the Rescue
&lt;/h2&gt;

&lt;p&gt;Here’s where things got spicy.&lt;/p&gt;

&lt;p&gt;We noticed that invoice creation was bottlenecked by thread pool saturation. It had to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Save to the DB&lt;/li&gt;
&lt;li&gt;Generate a PDF&lt;/li&gt;
&lt;li&gt;Call payment API&lt;/li&gt;
&lt;li&gt;Send an email&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;All mostly I/O. We had been using &lt;code&gt;@Async&lt;/code&gt; + thread pools. It worked, but the tuning was fragile.&lt;/p&gt;

&lt;p&gt;With Java 21’s &lt;strong&gt;virtual threads&lt;/strong&gt;, we rewrote it like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;scope&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;StructuredTaskScope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;ShutdownOnFailure&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Invoice&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;saved&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;invoiceRepository&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;save&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toEntity&lt;/span&gt;&lt;span class="o"&gt;()));&lt;/span&gt;
    &lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pdfService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;generatePdf&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;paymentClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;callApi&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;
    &lt;span class="nc"&gt;Future&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;mail&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fork&lt;/span&gt;&lt;span class="o"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;emailService&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendMail&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;join&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;scope&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;throwIfFailed&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvoiceResponse&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;saved&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultNow&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resultNow&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;CompletableFuture&lt;/code&gt;, no custom &lt;code&gt;ExecutorService&lt;/code&gt;. Just readable, parallel logic with &lt;strong&gt;safe cancellation and error propagation&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Under load testing, throughput jumped by &lt;strong&gt;~40%&lt;/strong&gt;, and CPU dropped ~15%.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Going Native with GraalVM
&lt;/h2&gt;

&lt;p&gt;We always talked about GraalVM like it was a mythical beast: powerful, but dangerous. Turns out, with Spring Boot 3, it’s shockingly tame.&lt;/p&gt;

&lt;p&gt;We added this to our build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./mvnw &lt;span class="nt"&gt;-Pnative&lt;/span&gt; &lt;span class="nt"&gt;-DskipTests&lt;/span&gt; spring-boot:build-image
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Native binary ~&lt;strong&gt;60MB&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Cold start: &lt;strong&gt;~75ms&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;RAM usage idle: &lt;strong&gt;~48MB&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, you read that right — &lt;strong&gt;a real Java microservice, starting faster than some Go apps.&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Deploying this in our cluster felt like cheating.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Observability Still Works in Native
&lt;/h2&gt;

&lt;p&gt;Here’s the cool part: &lt;strong&gt;tracing, metrics, and logs&lt;/strong&gt; kept working after the native build.&lt;/p&gt;

&lt;p&gt;With &lt;strong&gt;Micrometer Tracing&lt;/strong&gt; and &lt;strong&gt;OTEL&lt;/strong&gt;, we added:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;management&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;tracing&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;enabled&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;sampling&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;probability&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.0&lt;/span&gt;
    &lt;span class="na"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;http://otel-collector:4317&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No code change.&lt;br&gt;&lt;br&gt;
We got:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DB spans&lt;/li&gt;
&lt;li&gt;HTTP client/server spans&lt;/li&gt;
&lt;li&gt;PDF generation timing&lt;/li&gt;
&lt;li&gt;Distributed trace correlation across services&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Spring handled everything. Even in native mode. That was a &lt;strong&gt;wow&lt;/strong&gt; moment.&lt;/p&gt;




&lt;h2&gt;
  
  
  Before vs After
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before (JVM)&lt;/th&gt;
&lt;th&gt;After (Native + VT)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cold Start Time&lt;/td&gt;
&lt;td&gt;~3.4s&lt;/td&gt;
&lt;td&gt;~75ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Memory Usage (idle)&lt;/td&gt;
&lt;td&gt;~220MB&lt;/td&gt;
&lt;td&gt;~48MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker Image Size&lt;/td&gt;
&lt;td&gt;~250MB&lt;/td&gt;
&lt;td&gt;~80MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Concurrency Performance&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Great (I/O-scaled)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Observability&lt;/td&gt;
&lt;td&gt;Manual setup&lt;/td&gt;
&lt;td&gt;Built-in w/ OTEL&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Lessons Learned
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Virtual threads rock for I/O-heavy services&lt;/strong&gt;. We didn’t need to switch to WebFlux to scale.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GraalVM is production-ready now&lt;/strong&gt;, especially with Spring Boot’s AOT engine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native apps don’t mean losing Spring magic&lt;/strong&gt; — metrics, tracing, profiles… all still work.&lt;/li&gt;
&lt;li&gt;If you’re using &lt;code&gt;RestTemplate&lt;/code&gt;, just don’t. WebClient or nothing.&lt;/li&gt;
&lt;li&gt;We didn’t rewrite the service. We just upgraded it &lt;em&gt;intelligently&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Spring Boot 3 + Java 21 + GraalVM isn’t just “the latest thing.” It’s a better way to build Java services.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smaller&lt;/li&gt;
&lt;li&gt;Faster&lt;/li&gt;
&lt;li&gt;Cloud-native by design&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Back in the game to compete with Quarkus ;)&lt;/p&gt;

</description>
      <category>java</category>
      <category>graalvm</category>
      <category>performance</category>
      <category>spring</category>
    </item>
    <item>
      <title>AWS Solution Architect Pro: advice from an AWS Instructor</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Fri, 13 Dec 2024 10:25:09 +0000</pubDate>
      <link>https://dev.to/onepoint/aws-solution-architect-pro-advice-from-an-aws-instructor-53nn</link>
      <guid>https://dev.to/onepoint/aws-solution-architect-pro-advice-from-an-aws-instructor-53nn</guid>
      <description>&lt;p&gt;The AWS Solution Architect Professional certification is probably one of the hardest ones. Unlike some other certifications, working to achieve it provides you with significant and robust knowledge about AWS, as well as the most popular patterns and technologies in the market.&lt;/p&gt;

&lt;p&gt;Coupled with practical experience, this certification can help you advance to another level very quickly. At least, that was the case for me.&lt;/p&gt;

&lt;p&gt;As an AWS Authorized Instructor since 2019, I have passed many AWS certifications and trained numerous people to achieve the same. I’m writing this article to share my real-life feedback on how to prepare for the exam the right way and the pitfalls to avoid.&lt;/p&gt;

&lt;h2&gt;
  
  
  The AWS Journey Framework
&lt;/h2&gt;

&lt;p&gt;When I was a consultant, I worked closely with AWS training teams, and we aligned on the observation that even though many people train for the certification and attend classrooms, less than half of them actually register for the exam. Often, this is due to a lack of time because of work, family obligations, etc.&lt;/p&gt;

&lt;p&gt;We then built a training framework to support people from start to finish: getting certified.&lt;/p&gt;

&lt;p&gt;Here is the framework we developed in 5 steps:&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%2Foiqls8dptc9a63tvil60.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%2Foiqls8dptc9a63tvil60.png" alt="AWS Journey Framework" width="800" height="308"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Official Training&lt;/strong&gt;: If you or your company can afford it, take 5 days of official training for the certification with an AWS Authorized Instructor. These sessions are intense and can save you a lot of time, even though you’ll need to complement them with self-training. They allow you to block dedicated time to dive into the most important topics for the certification. By the end of the 5 days, you’ll only need to cover side topics and will already feel comfortable with the core ones.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Skill Builder&lt;/strong&gt;: AWS used to offer free training classrooms with instructors to answer questions and conduct practice exams with other certification candidates. Now, AWS Skill Builder has replaced this. However, in my experience, I don’t find it very useful. While it offers a lot of content, it lacks a clear and complete learning path.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Self-Training&lt;/strong&gt;: A consistent self-training platform is a crucial step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practice Tests&lt;/strong&gt;: Practice tests must be done on a good platform. In the past, I wasted time with irrelevant practice tests sold by AWS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exam Registration&lt;/strong&gt;: Don’t wait to feel “ready” before registering for the certification. Here’s a rule I never break: I always register after my first practice exam. This first attempt gives me an idea of the time I need to prepare. Then, I pick a date. Having a booked exam date keeps me motivated and focused on the objective.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach worked for me and, with small variations, for my students. Over the past 5 years, I’ve trained approximately 300 people, and every single one who followed these steps passed.&lt;/p&gt;

&lt;h2&gt;
  
  
  My advice for the learning
&lt;/h2&gt;

&lt;p&gt;First of all, you need to acquire a significant amount of knowledge about AWS Cloud infrastructure and the many services it offers. I wanted a solid foundation, so I reviewed many videos—even those I had already seen for the Solution Architect Associate certification—to reinforce my understanding. I also needed instructors with good English skills and effective communication to avoid the “Homer Simpson Monkey” effect after 3 minutes.&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%2Fvufq0whi49r9znuulrh5.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%2Fvufq0whi49r9znuulrh5.png" alt="Monkey" width="176" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Recommended self-training platforms
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.qa.com/self-paced-learning/" rel="noopener noreferrer"&gt;QA&lt;/a&gt; (former Cloud Academy) offers good training paths with labs to practice, section tests, final exams, etc. It’s a great way to prepare yourself or complement the 5-day training with an AWS Authorized Instructor.&lt;/li&gt;
&lt;li&gt;The Gold Content according to me is the training made by Adrian Cantrill &lt;a href="https://learn.cantrill.io/courses" rel="noopener noreferrer"&gt;here&lt;/a&gt;. This is what I used, and trust me, it’s the best $80 you’ll ever spend. This course not only helped me achieve the certification but also prepared me to manage AWS services with deep and consistent knowledge.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Practice exams platform
&lt;/h3&gt;

&lt;p&gt;The AWS SA Pro exam is notoriously difficult to prepare for because every practice test takes around 3 hours, and you need to complete multiple tests to feel ready. I won’t sugarcoat it—this part is challenging. Even during re-certification, it’s the part I dislike the most. Here’s my routine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every day during lunch, I complete 20 questions.&lt;/li&gt;
&lt;li&gt;After a few weeks, I take 2–3 full-length exams under real conditions on weekends.
This is crucial because practice tests often cover concepts absent from training courses. They also help you familiarize yourself with the question types and answer formats. My favorite platform is &lt;a href="https://www.whizlabs.com/" rel="noopener noreferrer"&gt;Whizlabs&lt;/a&gt;, as many of its training questions appear in the actual certification exam.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  My advice for the exam
&lt;/h2&gt;

&lt;p&gt;Here is a list of advice that can be very useful the D-Day :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you’re unsure of the correct answer, try to eliminate the wrong ones.&lt;/li&gt;
&lt;li&gt;Look for keywords in the question. For example, questions about IAM (roles) or Kinesis (real-time) are easy to recognize.&lt;/li&gt;
&lt;li&gt;Try not to spend more than 2 minutes per question.&lt;/li&gt;
&lt;li&gt;Don’t overthink—there are no trick questions.&lt;/li&gt;
&lt;li&gt;Don’t stress if you don’t know the answer to the first few questions. The later ones might be simpler..&lt;/li&gt;
&lt;li&gt;Don’t anticipate failure. I’ve passed 7 AWS exams, and 6 times I was convinced I’d fail halfway through. I didn’t.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Useful information
&lt;/h2&gt;

&lt;p&gt;Here is a recap of useful information about this certification :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Duration&lt;/strong&gt; : 180min&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost&lt;/strong&gt; : 300$&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Number of questions&lt;/strong&gt; : 75&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Average passing score&lt;/strong&gt; : 75%&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you have questions, feel free to comment this article.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>architecture</category>
      <category>certification</category>
    </item>
    <item>
      <title>Setup a Micro-Frontend architecture in 15min with Vite!</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Tue, 10 Dec 2024 13:06:20 +0000</pubDate>
      <link>https://dev.to/onepoint/setup-a-micro-frontend-architecture-in-15min-with-vite-4pbg</link>
      <guid>https://dev.to/onepoint/setup-a-micro-frontend-architecture-in-15min-with-vite-4pbg</guid>
      <description>&lt;p&gt;In a monolithic frontend architecture, a single codebase handles the entire user interface. While this can simplify initial development, it can become complex as the application grows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Scaling&lt;/strong&gt;: Large teams working in a monolithic repo may face merge conflicts, slower CI/CD pipelines, and difficulty with dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Independency&lt;/strong&gt;: sometimes working on shared stuff can impact other teams&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Resilience&lt;/strong&gt;: a failure can bring down the whole application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Micro-frontends can help when you start facing those problems. Unlike Web Components, coming with limited inter-framework communication and lifecycle management challenges, Vite based micro-frontends allow developers to work with differents frameworks. They provide flexibility in tooling, better state management, and more robust integration options. In a real life software growing through years, being able to handle multiple frameworks can be a smooth way to migrate from an old one to a new one whenever it's needed.&lt;/p&gt;

&lt;p&gt;In this article, we’ll create a micro-frontend setup using &lt;strong&gt;Vite&lt;/strong&gt; as our build tool and combine &lt;strong&gt;Vue.js&lt;/strong&gt;, &lt;strong&gt;Angular&lt;/strong&gt;, and &lt;strong&gt;React&lt;/strong&gt; components into a unified experience. The example? A modular news portal, where each framework handles a specific section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modular News Portal
&lt;/h2&gt;

&lt;p&gt;This modular news portal will have :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;strong&gt;Header&lt;/strong&gt; made with Vue.js: with a simple navigation bar&lt;/li&gt;
&lt;li&gt;a &lt;strong&gt;Trending&lt;/strong&gt; made with React: with the last articles to show&lt;/li&gt;
&lt;li&gt;an &lt;strong&gt;Highlights&lt;/strong&gt; made with Angular: with the most popular articles to show&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In a real-world example, separating news management across multiple technologies wouldn’t be ideal, but it serves our example well.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Shell
&lt;/h2&gt;

&lt;p&gt;In micro-frontend architecture, the &lt;strong&gt;Shell&lt;/strong&gt; acts as the container for the micro-frontends. It has 3 main features :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Coordination&lt;/strong&gt;: The Shell is responsible for loading and rendering the different micro-frontends into designated areas of the application&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Orchestration&lt;/strong&gt;: It handles global concerns like navigation, shared styles, shared state, data...&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Entry Point&lt;/strong&gt;: This is what the users loads first in their browser. It can also provide fallbacks if one of the micro-frontends fails to load.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Shell in our setup will use Vite and load ESM modules dynamically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;host&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;index&lt;/span&gt;&lt;span class="nc"&gt;.html&lt;/span&gt;  &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nt"&gt;Main&lt;/span&gt; &lt;span class="nt"&gt;entry&lt;/span&gt; &lt;span class="nt"&gt;point&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="nc"&gt;.js&lt;/span&gt;     &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nt"&gt;Loads&lt;/span&gt; &lt;span class="nt"&gt;the&lt;/span&gt; &lt;span class="nt"&gt;micro-frontends&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;vite&lt;/span&gt;&lt;span class="nc"&gt;.config.js&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;package&lt;/span&gt;&lt;span class="nc"&gt;.lock.json&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;package&lt;/span&gt;&lt;span class="nc"&gt;.json&lt;/span&gt;
&lt;span class="nt"&gt;apps&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;            &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="nt"&gt;Contains&lt;/span&gt; &lt;span class="nt"&gt;individual&lt;/span&gt; &lt;span class="nt"&gt;micro-frontends&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;header&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;components&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
            &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;Header&lt;/span&gt;&lt;span class="nc"&gt;.vue&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="nc"&gt;.js&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;vite&lt;/span&gt;&lt;span class="nc"&gt;.config.js&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;package&lt;/span&gt;&lt;span class="nc"&gt;.lock.json&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;package&lt;/span&gt;&lt;span class="nc"&gt;.json&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;trending&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;components&lt;/span&gt;
            &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;Trending&lt;/span&gt;&lt;span class="nc"&gt;.jsx&lt;/span&gt;
        &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;main&lt;/span&gt;&lt;span class="nc"&gt;.jsx&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;eslint&lt;/span&gt;&lt;span class="nc"&gt;.config.js&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;package&lt;/span&gt;&lt;span class="nc"&gt;.lock.json&lt;/span&gt;
    &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;vite&lt;/span&gt;&lt;span class="nc"&gt;.config.js&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;highlights&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's build it !&lt;/p&gt;

&lt;p&gt;We start by initializing a Vite workspace for our host and micro-frontends.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir &lt;/span&gt;news-portal &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd &lt;/span&gt;news-portal  
npm init vite@latest host &lt;span class="nt"&gt;--template&lt;/span&gt; vanilla  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s organize the project to separate each micro-frontend:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; apps/header apps/trending apps/highlights
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create our simple index.html with the components architecture inside our DOM :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;News Portal&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"trending"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"highlights"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"module"&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"./src/main.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, let's create our main.js file that is responsible of mounting the micro-frontends (note that imports won't work until we build our micro-frontends):&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;// main.js&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;mount&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;mountHeader&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../apps/header/dist/header.js&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;mount&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;mountTrending&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../apps/trending/dist/trending.js&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;mount&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;mountHighlights&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../apps/highlights/dist/highlights.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nf"&gt;mountHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;mountTrending&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#trending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="nf"&gt;mountHighlights&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#highlights&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;Then, we create the Vite configuration inside vite.config.js to enable the Vite 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;// vite.config.js&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;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&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;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;server&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;port&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="na"&gt;open&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start the Shell to be ready to serve :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;host
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here we are : we've successfully created our Shell and it's ready to serve our future micro-frontends. Now, let's create them !&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Header with Vue 3
&lt;/h2&gt;

&lt;p&gt;Let's create our &lt;strong&gt;Header&lt;/strong&gt; folder inside apps and navigate into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;apps
npm init vite@latest header &lt;span class="nt"&gt;--template&lt;/span&gt; vue  
&lt;span class="nb"&gt;cd &lt;/span&gt;header  
npm &lt;span class="nb"&gt;install&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside &lt;code&gt;src/components/Header.vue&lt;/code&gt;, create a simple header with navigation and for example a search bar:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;header&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Home&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;World&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Tech&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"#"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Sports&lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Search news..."&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/header&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;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="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;Header&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="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt; &lt;span class="na"&gt;scoped&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nc"&gt;.header&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-between&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;nav&lt;/span&gt; &lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;list-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;nav&lt;/span&gt; &lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0.5em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need a &lt;code&gt;src/main.js&lt;/code&gt; to mount the component :&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createApp&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&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;Header&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Header.vue&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;function&lt;/span&gt; &lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;createApp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&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;Configure vite.config.js to expose this app as a library :&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@vitejs/plugin-vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="c1"&gt;// https://vite.dev/config/&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;vue&lt;/span&gt;&lt;span class="p"&gt;()],&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/main.js&lt;/span&gt;&lt;span class="dl"&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;Header&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;header&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="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, build the micro-frontend to generate the dist folder :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;apps/header
npm run build 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now be able to see your &lt;strong&gt;Header&lt;/strong&gt; served in your &lt;strong&gt;Shell&lt;/strong&gt;. It happens because we told to our Shell to serve the dist folder of our Header and we generated it with the &lt;code&gt;npm build&lt;/code&gt; command.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Trending section with React 18
&lt;/h2&gt;

&lt;p&gt;Let's create our &lt;strong&gt;Trending&lt;/strong&gt; folder inside apps and navigate into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;apps
npm init vite@latest trending &lt;span class="nt"&gt;--template&lt;/span&gt; react  
&lt;span class="nb"&gt;cd &lt;/span&gt;trending
npm &lt;span class="nb"&gt;install&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add a Trending component in &lt;code&gt;src/components/Trending.jsx&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&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;Trending&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;articles&lt;/span&gt; &lt;span class="o"&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;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;React 18 Released&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Learn what's new in React 18.&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="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;AI Revolution&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;How AI is transforming industries.&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="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"trending"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Trending News&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;article&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h3&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;summary&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;section&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We need a &lt;code&gt;src/main.jsx&lt;/code&gt; to mount the component :&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&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;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom/client&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;Trending&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Trending&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;function&lt;/span&gt; &lt;span class="nf"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&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;root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
  &lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Trending&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure &lt;code&gt;vite.config.js&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&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;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;lib&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./src/main.jsx&lt;/span&gt;&lt;span class="dl"&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;Trending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;trending&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="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Build to generate the dist folder :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here we are ! We now have our second micro-frontend served inside our Shell, under our Header.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building Highlights with Angular 19
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Edit:&lt;/strong&gt; I haven't been able to make Vite works with Angular 19 without module federation, custom element or widget yet. I'm currently trying to find the best approach between the 3 to propose you the most efficient in a later edit of this post.&lt;/p&gt;




&lt;h2&gt;
  
  
  Bonus: Runtime Federation with Vite
&lt;/h2&gt;

&lt;p&gt;While the approach described above focuses on combining microfrontends during the build step, for production, you might want to embrace runtime federation. This approach offers true independence for microfrontends, allowing each module to be deployed separately and updated independently.&lt;/p&gt;

&lt;p&gt;Each microfrontend can be hosted on its own server or domain. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://header.news-portal.com" rel="noopener noreferrer"&gt;https://header.news-portal.com&lt;/a&gt; for Header&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://trending.news-portal.com" rel="noopener noreferrer"&gt;https://trending.news-portal.com&lt;/a&gt; for Trending&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dynamic Loading in the Shell Application
&lt;/h3&gt;

&lt;p&gt;The shell application dynamically loads microfrontends at runtime using import() or similar methods. Here’s how the shell could dynamically load both the Header and Trending modules from their respective URLs, listed in a microfrontend manifest json document, in the Shell &lt;code&gt;main.js&lt;/code&gt; :&lt;/p&gt;

&lt;p&gt;Manifest of microservices (ex: &lt;a href="https://news-portal.com/microfrontends.json" rel="noopener noreferrer"&gt;https://news-portal.com/microfrontends.json&lt;/a&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="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Header"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://header.news-portal.com/dist/header.js"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Trending"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://trending.news-portal.com/dist/trending.js"&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;Shell &lt;code&gt;main.js&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;data&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;modules&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="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;mounted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&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;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://news-portal.com/microfrontends.json&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;microfrontends&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;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

      &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;mfe&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;microfrontends&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;module&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&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;mfe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modules&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&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="nx"&gt;mfe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&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="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&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="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;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 load microfrontends:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;div&amp;gt;
      &amp;lt;h1&amp;gt;Shell App&amp;lt;/h1&amp;gt;
      &amp;lt;div v-for="module in modules" :key="module.name"&amp;gt;
        &amp;lt;component :is="module.component" /&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;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;
  
  
  Sharing Dependencies
&lt;/h3&gt;

&lt;p&gt;To avoid duplicating common dependencies like Vue, we could use &lt;code&gt;peerDependencies&lt;/code&gt; in our &lt;code&gt;package.json&lt;/code&gt; and externalize them in the Vite build process. We can configure it in &lt;code&gt;vite.config.js&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&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;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rollupOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;external&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;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="c1"&gt;// Prevent bundling Vue with the module&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This ensures that the &lt;strong&gt;Shell&lt;/strong&gt; provides the dependency (e.g., Vue), and both &lt;strong&gt;Header&lt;/strong&gt; and &lt;strong&gt;Trending&lt;/strong&gt; modules rely on the same instance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Benefits of Runtime Federation
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Independent Deployments&lt;/strong&gt;: Each module can be updated without redeploying the entire application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability&lt;/strong&gt;: Teams can work on different microfrontends autonomously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic Composition&lt;/strong&gt;: New modules can be added or updated without touching the shell or other microfrontends.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Common pitfalls
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Port Conflicts
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Assign a unique port to each micro-frontend in vite.config.js or angular.json to avoid conflicts&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Shared Libraries
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Use a shared CDN for common libraries to reduce duplication and bundle sizes&lt;/li&gt;
&lt;li&gt;Ensure version compatibility to avoid runtime errors&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  CORS problems
&lt;/h2&gt;

&lt;p&gt;During local development, micro-frontends hosted on different ports may face CORS issues due to browser security policies&lt;/p&gt;

&lt;p&gt;For production, configure your web server to allow cross-origin requests:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight nginx"&gt;&lt;code&gt;&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Allow-Origin'&lt;/span&gt; &lt;span class="s"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Allow-Methods'&lt;/span&gt; &lt;span class="s"&gt;'GET,&lt;/span&gt; &lt;span class="s"&gt;POST,&lt;/span&gt; &lt;span class="s"&gt;OPTIONS'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;add_header&lt;/span&gt; &lt;span class="s"&gt;'Access-Control-Allow-Headers'&lt;/span&gt; &lt;span class="s"&gt;'Origin,&lt;/span&gt; &lt;span class="s"&gt;Content-Type,&lt;/span&gt; &lt;span class="s"&gt;Accept'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Minimize CORS requirements by deploying all micro-frontends and the Shell under the same domain or subdomain structure (e.g., &lt;a href="https://news-portal.com/header" rel="noopener noreferrer"&gt;https://news-portal.com/header&lt;/a&gt;, &lt;a href="https://news-portal.com/trending" rel="noopener noreferrer"&gt;https://news-portal.com/trending&lt;/a&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Github link
&lt;/h2&gt;

&lt;p&gt;Github to the code : &lt;a href="https://github.com/mairouche/mfe-news-portal" rel="noopener noreferrer"&gt;Code Repository&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Congratulations, you've setup your first MicroFrontend architecture with Vite. For those who already used web components in the past, you may find it really simpler and useful. I hope it will be a good help to set up your first MFE projects whenever you'll need to decouple the development of multiple front parts of your software.&lt;/p&gt;

</description>
      <category>vite</category>
      <category>vue</category>
      <category>react</category>
      <category>angular</category>
    </item>
    <item>
      <title>Using CDC or Outbox pattern in microservices for decentralized data propagation</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Mon, 04 Nov 2024 23:13:30 +0000</pubDate>
      <link>https://dev.to/onepoint/using-change-data-capture-or-outbox-pattern-in-microservices-for-decentralized-data-propagation-4fii</link>
      <guid>https://dev.to/onepoint/using-change-data-capture-or-outbox-pattern-in-microservices-for-decentralized-data-propagation-4fii</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;When it comes to &lt;strong&gt;&lt;em&gt;Event Driven Architectures&lt;/em&gt;&lt;/strong&gt;, people use to think about &lt;strong&gt;Fan-Out pattern&lt;/strong&gt;, maybe &lt;strong&gt;Event-Sourcing&lt;/strong&gt;... But there are numerous patterns that are working well with events.&lt;/p&gt;

&lt;p&gt;When you're having multiple microservices with each their own database, you may face &lt;strong&gt;&lt;em&gt;data propagation&lt;/em&gt;&lt;/strong&gt; challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data propagation challenge in microservices
&lt;/h2&gt;

&lt;p&gt;Let's take a simple example with a blog:&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%2F25e5hzuqea5zhdfisa80.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%2F25e5hzuqea5zhdfisa80.png" alt="Microservices" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;User microservice&lt;/strong&gt;: handle user's stuff and have basic information about registered users with its own users database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Article microservice&lt;/strong&gt;: is responsible of CRUD on published articles.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But here is the thing : an article is written and edited by a user. So if my user is updating some information, like, for example, his username, every articles have to be updated to match the new name and not the old one.&lt;/p&gt;

&lt;p&gt;This is where data propagation may occur. There are other solutions to tackle this problem but data propagation is a popular one.&lt;/p&gt;

&lt;p&gt;The purpose of data propagation is to be able to detect data changes and to inform interested microservices with this change  to properly handle it their way. In our example, we simply wanna update our username in article microservice whenever updated in uses microservice as follows.&lt;/p&gt;

&lt;p&gt;1 - User create an article&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%2Fwhhlclrdn9fekx9k1om1.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%2Fwhhlclrdn9fekx9k1om1.png" alt="Article creation" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2 - User change his username calling only user microservice&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%2F5rmeapotwkyjt6zv5zry.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%2F5rmeapotwkyjt6zv5zry.png" alt="Username update" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3 - Username update must be propagated to article&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%2Fdgivv06h6yo7r3lx09ph.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%2Fdgivv06h6yo7r3lx09ph.png" alt="Username update propagation" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Common approaches
&lt;/h2&gt;

&lt;p&gt;A pretty common, but not optimal approach I often see, is to use Fan-out pattern to fire multiple events from the business logic or data layer of microservices and to publish it into a topic. The problem with this approach is that it makes you write code to fire events whenever a data change occur and add complexity in those layers.&lt;/p&gt;

&lt;p&gt;So, how do CDC pattern helps us to do it in a better way ?&lt;/p&gt;

&lt;h2&gt;
  
  
  The concept of Change Data Capture
&lt;/h2&gt;

&lt;p&gt;CDC consist in being able to determine what changed in a database and to react to this change.&lt;br&gt;
In Event Driven Architectures, CDC react to changes with events through topics, queues or streams.&lt;/p&gt;

&lt;p&gt;A good example of CDC oriented database is &lt;strong&gt;AWS DynamoDB&lt;/strong&gt;. With the &lt;strong&gt;&lt;em&gt;DynamoDB Stream&lt;/em&gt;&lt;/strong&gt; option activated, every change in every item of the database is sent through a stream as a shard. Each shard contains the nature of the change and a previous and new state.&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%2Fzls3grsef4g42a3k73n6.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%2Fzls3grsef4g42a3k73n6.png" alt="DynamoDB Stream" width="757" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can natively react to shards with AWS lambdas for example but also, within any of your applications using AWS SDK with the programing language you're using.&lt;/p&gt;

&lt;h2&gt;
  
  
  The outbox pattern alternative
&lt;/h2&gt;

&lt;p&gt;Also, if you are in a relational context and work wih an SQL database, you have to be aware of the Outbox pattern. The &lt;strong&gt;Transactional Outbox pattern&lt;/strong&gt; consist in sending events only whenever a RDBMS transaction is fully achieved assuming that there are no desync of data across the distributed system.&lt;/p&gt;

&lt;p&gt;A well known technology that is implemeting this pattern id &lt;strong&gt;Debezium&lt;/strong&gt;. It's watching the transactions within a RDBMS to send events into a Kafka topic anytime the data is changing.&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%2Fn7bvyq0n5dyr4fcn3tz7.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%2Fn7bvyq0n5dyr4fcn3tz7.png" alt="Debezium" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Outbox pattern with Debezium in our context
&lt;/h2&gt;

&lt;p&gt;In our first example, we have an SQL database so Debezium should be a good fit to achieve our data propagation.&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%2F7ruedmvzcb5qjtiwiuit.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%2F7ruedmvzcb5qjtiwiuit.png" alt="Outbox in action" width="800" height="604"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user name is updated in his own database&lt;/li&gt;
&lt;li&gt;The change is detected by Debezium&lt;/li&gt;
&lt;li&gt;Debezium fires an event into a topic with the previous usernmae and the new userName&lt;/li&gt;
&lt;li&gt;Article microservice is subscribed to the topic and react to the event by triggering an update of all of the articles written by the previous userName setting the authorName to new userName.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Finally, we saw that there are several ways to achieve data propagation in a distributed system. Fan-out can bring some extra code and complexity that could be handled by some technologies using CDC or Outbox pattern like DynamoDB Streams, Debezium, Redis pub/sub...&lt;/p&gt;

&lt;p&gt;As always, those methods must be used whenever you feel it's answering the problem you're facing and not applied everywhere without consideration. But it's good to know that it exists to avoid introducing unnecessary complexity into the code.&lt;/p&gt;

</description>
      <category>development</category>
      <category>eventdriven</category>
      <category>systemdesign</category>
      <category>architecture</category>
    </item>
    <item>
      <title>High-performance Chat with TypeScript, Websockets &amp; Redis in 10min !</title>
      <dc:creator>Meidi Airouche</dc:creator>
      <pubDate>Tue, 06 Aug 2024 14:50:17 +0000</pubDate>
      <link>https://dev.to/onepoint/high-performance-chat-with-websocket-redis-in-10min--3337</link>
      <guid>https://dev.to/onepoint/high-performance-chat-with-websocket-redis-in-10min--3337</guid>
      <description>&lt;p&gt;The purpose of this article is to understand the basics of websockets and cache with a common known example : a Chat. &lt;/p&gt;

&lt;p&gt;Usually, a Chat have to be really reactive with very good performance. There are many ways to achieve different levels of performance. &lt;/p&gt;

&lt;p&gt;In this article, we'll build a basic sample high-performance Chat together with Typescript, Redis and Websockets. I'll guide you step-by-step as if I was doing it with you.&lt;/p&gt;

&lt;p&gt;First, let's take a look at our architecture.&lt;/p&gt;

&lt;h1&gt;
  
  
  Architecture
&lt;/h1&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%2Fs4voiw5wcjwg6mnasm6y.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%2Fs4voiw5wcjwg6mnasm6y.png" alt="Architecture" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To the keep things simple, we'll be doing the frontend in plain HTML/JS without framework&lt;/li&gt;
&lt;li&gt;The Nodejs server will be written with express as it's most known. &lt;/li&gt;
&lt;li&gt;A Redis server to cache messages&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Tips : If you wanna enhance performance further, you can opt for another framework like fastify, websocket.io, uWebSocket or whatever you want. We'll stay with express as it's well commonly known.&lt;/p&gt;

&lt;h1&gt;
  
  
  Backend
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Project structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;docker-compose&lt;/span&gt;&lt;span class="nc"&gt;.yml&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;Dockerfile&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;src&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;index&lt;/span&gt;&lt;span class="nc"&gt;.ts&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;server&lt;/span&gt;&lt;span class="nc"&gt;.ts&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;redisClient&lt;/span&gt;&lt;span class="nc"&gt;.ts&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;   &lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="nt"&gt;types&lt;/span&gt;&lt;span class="nc"&gt;.ts&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt; &lt;span class="nt"&gt;tsconfig&lt;/span&gt;&lt;span class="nc"&gt;.json&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt; &lt;span class="nt"&gt;package&lt;/span&gt;&lt;span class="nc"&gt;.json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create the nodejs project
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm init
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and feed the package.json file with the following configuration :&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;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chat-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&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.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;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dist/index.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&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;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tsc"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"start"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node dist/index.js"&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;"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;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.17.1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"redis"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.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;"ws"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.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="nl"&gt;"devDependencies"&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;"@types/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;"^16.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;"@types/ws"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^8.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;"typescript"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.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;h2&gt;
  
  
  Install dependencies into your project
&lt;/h2&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 ws redis 
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save-dev&lt;/span&gt; typescript @types/node @types/ws @types/express @types/redis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If not already done, don't forget to configure your tsconfig.json :&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;"compilerOptions"&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;"target"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ES6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"module"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"commonjs"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"outDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"rootDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./src"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"strict"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"esModuleInterop"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"skipLibCheck"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&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;h2&gt;
  
  
  Coding
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Redis client configuration
&lt;/h3&gt;

&lt;p&gt;Let’s create our Redis configuration in a dedicated file &lt;code&gt;./src/redisClient.ts&lt;/code&gt;. Here, we're connecting the client to Redis and we listen for errors to raise it in the console.&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;createClient&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redis&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;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;url&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://redis:6379&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// we'll create the docker image later&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&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;err&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;console&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Redis Client 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;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&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;client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

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

&lt;/div&gt;



&lt;h3&gt;
  
  
  Message type or interface
&lt;/h3&gt;

&lt;p&gt;We’ll be creating an interface (create a type if you prefer) to structure our Chat messages in &lt;code&gt;./src/chatMessage.ts&lt;/code&gt;. Let’s keep it simple and have only 3 attributes :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;username&lt;/strong&gt;: the name of the message author&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;message&lt;/strong&gt;: the content of the message&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;timestamp&lt;/strong&gt;: date and hour of the message as a timestamp
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ChatMessage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;
  
  
  Http &amp;amp; Websocket servers
&lt;/h3&gt;

&lt;p&gt;Here, we’ll be creating two servers in &lt;code&gt;./src/server.ts&lt;/code&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTTP server with express to handle http calls&lt;/li&gt;
&lt;li&gt;Websocket server to handle websocket messages
&lt;/li&gt;
&lt;/ul&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;express&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;express&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;WebSocketServer&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;ws&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;redisClient&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;./redisClient&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;ChatMessage&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;./chatMessage&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&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="nx"&gt;res&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="s2"&gt;Chat server is running&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Web server is running on http://localhost:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;wss&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;WebSocketServer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;server&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;connection&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;ws&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;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Client connected&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Send chat history to new client&lt;/span&gt;
  &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lRange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chat_message&lt;/span&gt;&lt;span class="dl"&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="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&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;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;message&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;ws&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="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&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;console&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error retrieving messages from Redis&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&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="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&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;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ChatMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&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;messageString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Save message to Redis&lt;/span&gt;
    &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rPush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chat_messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;messageString&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;redisClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lTrim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;chat_messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Keep only the last 100 messages&lt;/span&gt;

    &lt;span class="c1"&gt;// Broadcast message to all clients&lt;/span&gt;
    &lt;span class="nx"&gt;wss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clients&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;client&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readyState&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;OPEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;client&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="nx"&gt;messageString&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="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;close&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Client disconnected&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="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WebSocket server is running on ws://localhost:3000&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;So, what are we doing here :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we setup the Web and WebSocket servers.&lt;/li&gt;
&lt;li&gt;Second, on the websocket connection, we pull the Chat history from redis&lt;/li&gt;
&lt;li&gt;Third, we listen for new messages and record them in redis, keeping only the 100 last message anytime&lt;/li&gt;
&lt;li&gt;Fourth, we broadcast each messages to all the connected clients of the Chat&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you wanna go further, you can implement an observer pattern where each websocket client is an observer. But for now, let's keep the things simple.&lt;/p&gt;

&lt;p&gt;For barrels fans, don’t forget to add your app entrypoint in &lt;code&gt;./src/index.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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./server&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;You can launch the server with :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm run build
npm start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Frontend
&lt;/h1&gt;

&lt;p&gt;As we said it previously, we'll build a simple example which does not take account of best practices for the article. Create a single &lt;code&gt;index.hml&lt;/code&gt; with the following code :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Chat&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"chat"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"messages"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"username"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Username"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"message"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Message"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;onclick=&lt;/span&gt;&lt;span class="s"&gt;"sendMessage()"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Send&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ws&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;WebSocket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ws://localhost:3000&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;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onmessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&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;li&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;li&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`[&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleTimeString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;] &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;li&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sendMessage&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;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&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;message&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;ws&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="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So what are we doing here :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We setup the html document to have the needed fields and button to send a message&lt;/li&gt;
&lt;li&gt;We setup the websocket connection with the server&lt;/li&gt;
&lt;li&gt;We publish every message to the websocket anytime the button is pressed calling the function sendMessage()&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  All together with docker compose
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Create a Dockerfile for the server
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Use official Nodejs image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18&lt;/span&gt;

&lt;span class="c"&gt;# Work directory&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="c"&gt;# Copy package.json &amp;amp; package-lock.json&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="c"&gt;# Install dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;

&lt;span class="c"&gt;# Copy sources files&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Compile Typescript&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Expose web server port&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;

&lt;span class="c"&gt;# Start the server&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["npm", "start"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a Docker compose file to assemble
&lt;/h2&gt;

&lt;p&gt;Let's assemble the web server and Radis server inside a docker-compose.yml file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;redis&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:latest&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;6379:6379"&lt;/span&gt;

  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;chat-app&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/usr/src/app&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm start&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Building and starting the whole stack
&lt;/h2&gt;

&lt;p&gt;To build and run the whole backend stack with docker images, use :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker-compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open your index.html file and start sending messages. We're done ! A high-performance chat with websocket and Redis !&lt;/p&gt;

&lt;h1&gt;
  
  
  Sources
&lt;/h1&gt;

&lt;p&gt;Link : &lt;a href="https://github.com/mairouche/high-performance-chat?tab=readme-ov-file" rel="noopener noreferrer"&gt;GitHub Repository&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope it helps to understand basics. After that, you might be willing to take a look at Observer pattern and framworks like socket.io. Enjoy !&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>redis</category>
      <category>websocket</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
