<?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: Ali Zgheib</title>
    <description>The latest articles on DEV Community by Ali Zgheib (@alizgheib).</description>
    <link>https://dev.to/alizgheib</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%2F1113474%2Fd3779146-5194-446f-9987-63e490a6e630.png</url>
      <title>DEV Community: Ali Zgheib</title>
      <link>https://dev.to/alizgheib</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alizgheib"/>
    <language>en</language>
    <item>
      <title>AWS Community Builders Program 2026 – How and Why to apply</title>
      <dc:creator>Ali Zgheib</dc:creator>
      <pubDate>Thu, 15 Jan 2026 10:30:58 +0000</pubDate>
      <link>https://dev.to/alizgheib/aws-community-builders-program-2026-how-and-why-to-apply-1550</link>
      <guid>https://dev.to/alizgheib/aws-community-builders-program-2026-how-and-why-to-apply-1550</guid>
      <description>&lt;p&gt;There is a huge difference between building alone and building with a global network backing you up. That difference is the &lt;a href="https://aws.amazon.com/developer/community/community-builders/" rel="noopener noreferrer"&gt;&lt;strong&gt;AWS Community Builders program&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The application window for the 2026 Cycle is officially open until &lt;strong&gt;January 21st, 2026&lt;/strong&gt;. Quite simply: If you love AWS and love sharing what you learn, &lt;strong&gt;this program was designed for you&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Here is a breakdown of what the program really is, why you should apply, and how to get in.&lt;/p&gt;




&lt;h2&gt;
  
  
  What is the AWS Community Builders Program?
&lt;/h2&gt;

&lt;p&gt;Most people believe the AWS Community Builders program is reserved for those who are highly skilled, heavily certified, or already well known in the public domain. This assumption alone discourages many strong candidates before they even consider applying.&lt;/p&gt;

&lt;p&gt;In reality, AWS is not selecting experts. They are selecting &lt;strong&gt;Builders&lt;/strong&gt;. &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%2F03yknrqnsgkoej7yst09.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%2F03yknrqnsgkoej7yst09.png" alt="AWS Experts vs AWS Builders" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These are builders who learn continuously, share openly, and show up consistently. It is not about being the smartest person in the room. It is about having the curiosity to learn and the discipline to share that journey with others.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Apply? (The Benefits)
&lt;/h2&gt;

&lt;p&gt;Beyond just being a "nice community," this program can fast-track your cloud career. Here are the four main benefits you unlock as a member:&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%2Fdgpz6u1jxwhm3moqiosn.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%2Fdgpz6u1jxwhm3moqiosn.png" alt="Infographic: Four quadrants displaying the benefits - $500 Credits, Private Access, Global Network, and Exclusive Swag" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Financial Support &amp;amp; Training
&lt;/h3&gt;

&lt;p&gt;First, the resources backing your learning are substantial:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;$500 in AWS credits:&lt;/strong&gt; This allows you to experiment with advanced services and build complex demos without worrying about the bill.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Certification Voucher:&lt;/strong&gt; You receive one voucher for an AWS certification exam of your choice.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Cloud Academy:&lt;/strong&gt; A one-year subscription gives you access to their entire library of courses and hands-on labs to level up your skills.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Exclusive Access
&lt;/h3&gt;

&lt;p&gt;You get an "insider edge" with the platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Direct Access:&lt;/strong&gt; Join private sessions with AWS service teams to ask questions directly to the engineers building the tools.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Early Access &amp;amp; Insights:&lt;/strong&gt; Get sneak peeks at upcoming AWS features under NDA, allowing you to experiment and shape new services with your feedback.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. The Community Network
&lt;/h3&gt;

&lt;p&gt;You join a private &lt;strong&gt;Slack community&lt;/strong&gt; where you connect with like-minded people who are learning and sharing just like you. This is your chance to learn from experts, find mentors, and connect with other AWS Heroes.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Swag &amp;amp; Discounts
&lt;/h3&gt;

&lt;p&gt;Finally, the fun stuff. You get a &lt;strong&gt;welcome kit&lt;/strong&gt; filled with exclusive gear like backpacks, mugs, caps, and stickers. More importantly, you get a &lt;strong&gt;discount for AWS events&lt;/strong&gt; like re:Invent, making attending cloud conferences much more affordable.&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%2Fjeprof1qdyfz1wmf892a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjeprof1qdyfz1wmf892a.jpg" alt="Photo: The actual Swag Kit displayed on a desk, featuring the AWS Backpack, Mug, and Stickers" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Who is Eligible? (Show Your Work)
&lt;/h2&gt;

&lt;p&gt;You don't have to be an expert, but you do need to show that you are helping others learn. There are many ways to do this:&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%2Fxy856fd299mtmk6j6839.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%2Fxy856fd299mtmk6j6839.png" alt="Diagram: A central circle labeled " width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;Blogging:&lt;/strong&gt; Publishing deep-dive articles on Medium, Dev.to, or your personal blog.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Video:&lt;/strong&gt; Creating YouTube tutorials, technical guides, or how-to videos about an existing or new AWS service.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Social Media:&lt;/strong&gt; Sharing valuable AWS insights and tips on LinkedIn, Instagram, or TikTok to spark discussions.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Community Support:&lt;/strong&gt; Answering questions in forums, Reddit, or AWS re:Post to help others get unblocked.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Speaking:&lt;/strong&gt; Giving talks at cloud meetups or AWS events, whether remote or in-person.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The key is being consistent and genuine. If you are helping the community by sharing valuable content, you are eligible.&lt;/p&gt;




&lt;h2&gt;
  
  
  How to Apply
&lt;/h2&gt;

&lt;p&gt;The application for the 2026 cycle is open until &lt;strong&gt;January 21, 2026&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://aws.amazon.com/developer/community/community-builders/" rel="noopener noreferrer"&gt;&lt;strong&gt;submit your application here&lt;/strong&gt;&lt;/a&gt;. To apply, you will need to log in with your free &lt;strong&gt;AWS Builder ID&lt;/strong&gt;. Once you are in, fill out the form. It is short and asks for basic information about you and your content.&lt;/p&gt;

&lt;p&gt;It's straightforward, but don't rush it. Take your time to gather your best links to your content before hitting submit.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; If you are reading this after January 21st, the application will be closed. However, you can use the same link to join the &lt;strong&gt;waitlist&lt;/strong&gt; to be notified the moment the next cycle opens.&lt;/p&gt;
&lt;/blockquote&gt;




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

&lt;p&gt;I’ve been building on my own for a while, but this year, I'm applying because I want to be part of this community.&lt;/p&gt;

&lt;p&gt;If you decide to apply, drop a comment and let me know. I'm rooting for you. Good luck, and happy building!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>community</category>
      <category>cloud</category>
      <category>networking</category>
    </item>
    <item>
      <title>🔥 This AWS Lambda Update Changes Everything (Durable Functions)</title>
      <dc:creator>Ali Zgheib</dc:creator>
      <pubDate>Sat, 10 Jan 2026 17:36:42 +0000</pubDate>
      <link>https://dev.to/alizgheib/this-aws-lambda-update-changes-everything-durable-functions-30d2</link>
      <guid>https://dev.to/alizgheib/this-aws-lambda-update-changes-everything-durable-functions-30d2</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;: In December 2025, AWS released Lambda Durable Functions. Your Lambda can now run for &lt;strong&gt;366 days&lt;/strong&gt; (not 15 minutes), automatically checkpoint progress, suspend during waits without charges, handle retries with built-in strategies, wait for external callbacks like human approvals, and process batches with concurrency control. All in a single Lambda function.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Are Lambda Durable Functions?
&lt;/h2&gt;

&lt;p&gt;Lambda Durable Functions extends Lambda to support long-running, stateful workflows that can pause, wait, and resume. Unlike standard Lambda functions (max 15 minutes), durable functions can run for up to 366 days through checkpoint-and-replay.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key capabilities:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Automatic checkpointing after each operation&lt;/li&gt;
&lt;li&gt;Zero-cost suspension during waits (Lambda suspends)&lt;/li&gt;
&lt;li&gt;Built-in retry with configurable strategies&lt;/li&gt;
&lt;li&gt;External callback support (human approvals, webhooks)&lt;/li&gt;
&lt;li&gt;Batch processing with per-item checkpoints&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;This tutorial uses TypeScript and Serverless Framework for infrastructure-as-code.&lt;/strong&gt; You can also use your favorite programming language, console, or any infrastructure-as-code tool like CDK, SAM, Terraform, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enable Durable Execution
&lt;/h3&gt;

&lt;p&gt;Configure your Lambda function to support durable execution in &lt;code&gt;serverless.yml&lt;/code&gt;:&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;functions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;myFunction&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;handler.main&lt;/span&gt;
    &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;900&lt;/span&gt;                      &lt;span class="c1"&gt;# Lambda execution timeout (seconds, max 900 = 15 min)&lt;/span&gt;
    &lt;span class="na"&gt;durableConfig&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;executionTimeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;86400&lt;/span&gt;         &lt;span class="c1"&gt;# Workflow timeout (seconds, max 31,622,400 = 366 days)&lt;/span&gt;
      &lt;span class="na"&gt;retentionPeriodInDays&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;7&lt;/span&gt;        &lt;span class="c1"&gt;# Keep execution history for 7 days&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Parameter explanations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;timeout&lt;/code&gt;&lt;/strong&gt;: Maximum time for a &lt;em&gt;single Lambda invocation&lt;/em&gt; (max 15 minutes). Your function is replayed multiple times, and each replay must complete within this limit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;executionTimeout&lt;/code&gt;&lt;/strong&gt;: Maximum time for the &lt;em&gt;entire workflow&lt;/em&gt; across all replays (max 366 days). This is how long your durable function can run from start to finish, including all waits.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;retentionPeriodInDays&lt;/code&gt;&lt;/strong&gt;: How long AWS keeps your execution history and checkpoint logs after completion (1-90 days). Used for debugging and observability.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example scenario:&lt;/strong&gt; You have a workflow that processes a payment, waits 2 hours, then ships an order.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Set &lt;code&gt;timeout: 60&lt;/code&gt; because each individual Lambda execution (processing payment, then later shipping order) completes in under 60 seconds&lt;/li&gt;
&lt;li&gt;Set &lt;code&gt;executionTimeout: 7200&lt;/code&gt; (2 hours) because the entire workflow from start to finish takes 2 hours (including the wait)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Set Up the Durable Execution SDK
&lt;/h3&gt;

&lt;p&gt;Durable functions &lt;strong&gt;require the SDK&lt;/strong&gt; - it's not optional. The SDK handles checkpoint-and-replay, manages execution state, and provides the durable operations you'll use in your code. Without it, you'd need to manually implement all state management, checkpoint tracking, and recovery logic yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Available languages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;TypeScript
&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;AWS will add support for more languages over time.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @aws/durable-execution-sdk-js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Wrap Your Handler
&lt;/h3&gt;

&lt;p&gt;Wrap your Lambda handler with &lt;code&gt;withDurableExecution&lt;/code&gt; to enable durable execution:&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;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DurableContext&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;@aws/durable-execution-sdk-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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;async &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="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DurableContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Your durable workflow code here&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;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="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 &lt;code&gt;DurableContext&lt;/code&gt; gives you access to durable operations including &lt;code&gt;step()&lt;/code&gt;, &lt;code&gt;wait()&lt;/code&gt;, &lt;code&gt;parallel()&lt;/code&gt;, &lt;code&gt;map()&lt;/code&gt;, &lt;code&gt;waitForCallback()&lt;/code&gt;, and several others for building long-running workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Durable Execution Works
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Checkpoint and Replay
&lt;/h3&gt;

&lt;p&gt;Durable functions run multiple times during their lifecycle. Each time Lambda invokes your function, it replays your code from the beginning - but skips completed operations by reading from the checkpoint log.&lt;/p&gt;

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

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Step 1: Charge payment&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;charge&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;charge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;processPayment&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;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 2: Wait 2 hours&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;7200&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="c1"&gt;// Step 3: Ship order&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipment&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ship&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;createShipment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;orderId&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="nx"&gt;shipment&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Execution timeline:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Invocation 1 (T+0):
┌─────────────────────────────────────────────────┐
│ [charge ✓] → checkpoint saved                   │
│ [wait 2h...] → Lambda suspends (no charges)     │
└─────────────────────────────────────────────────┘
                    ⏳ 2 hours pass...

Invocation 2 (T+2h):
┌─────────────────────────────────────────────────┐
│ [charge ⚡cached] ← reads from checkpoint       │
│ [wait ⚡skipped] ← already completed            │
│ [ship ✓] → checkpoint saved                     │
│ Return result ✓                                 │
└─────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;During the 2-hour wait, no Lambda runs. Zero charges.&lt;/p&gt;

&lt;h3&gt;
  
  
  Determinism Requirements
&lt;/h3&gt;

&lt;p&gt;Replay depends on your code producing the same results every time it runs. Any code outside durable operations must be deterministic - meaning it returns the same output for the same input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Non-deterministic operations must be wrapped:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ❌ Wrong: Random value changes on each replay&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;save&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;saveWithId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// ✅ Correct: Random value generated once, checkpointed&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;generate-id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;save&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;saveWithId&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Wrap these in steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Random values (&lt;code&gt;Math.random()&lt;/code&gt;, &lt;code&gt;uuid()&lt;/code&gt;, &lt;code&gt;uuidv4()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Timestamps (&lt;code&gt;Date.now()&lt;/code&gt;, &lt;code&gt;new Date()&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;External API calls&lt;/li&gt;
&lt;li&gt;Database queries&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Core Operations
&lt;/h2&gt;

&lt;p&gt;The SDK provides several operations for building durable workflows. Each operation creates checkpoints automatically, ensuring your function can resume from any point.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.step()
&lt;/h3&gt;

&lt;p&gt;Executes business logic with automatic checkpointing and retry. Once a step succeeds, it never re-executes - the checkpointed result is used on replay.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;process-payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;paymentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Database calls, API requests, any side-effecting operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.wait()
&lt;/h3&gt;

&lt;p&gt;Pauses execution for a specified duration. The SDK creates a checkpoint, terminates the function invocation, and schedules resumption. When the wait completes, Lambda invokes your function again.&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;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt; &lt;span class="c1"&gt;// Wait 1 hour&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Delays between operations, rate limiting, scheduled actions.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.parallel()
&lt;/h3&gt;

&lt;p&gt;Executes multiple operations concurrently with optional concurrency control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parallel&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processTask1&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processTask2&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processTask3&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Independent operations that can run simultaneously.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.map()
&lt;/h3&gt;

&lt;p&gt;Concurrently executes an operation on each item in an array with optional concurrency control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&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;context&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;itemArray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;task&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;processItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Batch processing, parallel data transformation.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.waitForCallback()
&lt;/h3&gt;

&lt;p&gt;Suspends execution until an external system submits a callback. The SDK creates a callback, executes your submitter function with the callback ID, and waits for the result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;external-api&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&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;await&lt;/span&gt; &lt;span class="nf"&gt;submitToExternalAPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestData&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;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;minutes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&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;The external system receives the &lt;code&gt;callbackId&lt;/code&gt; and sends the result back using the Lambda API (&lt;code&gt;SendDurableExecutionCallbackSuccess&lt;/code&gt; or &lt;code&gt;SendDurableExecutionCallbackFailure&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Human approvals, webhook integrations, external system coordination.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.createCallback()
&lt;/h3&gt;

&lt;p&gt;Creates a callback and returns both a promise and callback ID. You send the callback ID to an external system, which submits the result using the Lambda API (&lt;code&gt;SendDurableExecutionCallbackSuccess&lt;/code&gt; or &lt;code&gt;SendDurableExecutionCallbackFailure&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callbackId&lt;/span&gt;&lt;span class="p"&gt;]&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;approval&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;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;sendApprovalRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requestData&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;approval&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;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Advanced scenarios where you need the callback ID before suspending.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.invoke()
&lt;/h3&gt;

&lt;p&gt;Invokes another Lambda function and waits for its result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invoke-processor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;arn:aws:lambda:us-east-1:123456789012:function:processor&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;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;inputData&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Function composition, workflow decomposition, calling other Lambda functions.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.waitForCondition()
&lt;/h3&gt;

&lt;p&gt;Polls for a condition with automatic checkpointing between attempts. The SDK executes your check function, creates a checkpoint with the result, waits according to your strategy, and repeats until the condition is met.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForCondition&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&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;status&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;checkJobStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;jobId&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&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;initialState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;jobId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;job-123&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pending&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;waitStrategy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
      &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&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;shouldContinue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;shouldContinue&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="na"&gt;delay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;30&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;&lt;strong&gt;Use for:&lt;/strong&gt; Polling external systems, waiting for resources to be ready, implementing retry with backoff.&lt;/p&gt;

&lt;h3&gt;
  
  
  context.runInChildContext()
&lt;/h3&gt;

&lt;p&gt;Creates an isolated execution context for grouping operations. Child contexts have their own checkpoint log and can contain multiple steps, waits, and other operations. The SDK treats the entire child context as a single unit for retry and recovery.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;runInChildContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;batch-processing&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;childCtx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;processBatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;childCtx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Use for:&lt;/strong&gt; Organizing complex workflows, implementing sub-workflows, isolating operations that should retry together.&lt;/p&gt;




&lt;h2&gt;
  
  
  Complete Example: Order Fulfillment Workflow
&lt;/h2&gt;

&lt;p&gt;Here's a real-world example combining multiple operations:&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;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;DurableContext&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;@aws/durable-execution-sdk-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;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;withDurableExecution&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="k"&gt;async &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="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;orderId&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;items&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="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DurableContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Step 1: Process payment&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payment&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;process-payment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;paymentService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;charge&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;orderId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Step 2: Wait 1 hour for fraud check window&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;wait&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

    &lt;span class="c1"&gt;// Step 3: Parallel operations - reserve inventory and calculate shipping&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;inventory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;]&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parallel&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
      &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;reserve-inventory&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="nx"&gt;inventoryService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reserve&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;items&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="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;calculate-shipping&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="nx"&gt;shippingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculate&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;orderId&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="c1"&gt;// Step 4: Wait for external approval&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;approval&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;waitForCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;order-approval&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ctx&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;await&lt;/span&gt; &lt;span class="nx"&gt;notificationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendApprovalRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackId&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;orderId&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;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;hours&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;24&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;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;approval&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;approved&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;rejected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;orderId&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;orderId&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Step 5: Process each item&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;shipments&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;context&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;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="nx"&gt;ctx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ship-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
          &lt;span class="nx"&gt;shippingService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;shipItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shipping&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;address&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="c1"&gt;// Step 6: Send confirmation&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;step&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;send-confirmation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;notificationService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendConfirmation&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;orderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shipments&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;completed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;orderId&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;orderId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;shipments&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 workflow demonstrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sequential steps&lt;/strong&gt; with automatic checkpointing (payment, confirmation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-based waits&lt;/strong&gt; for fraud checks (no charges during wait)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Parallel execution&lt;/strong&gt; for independent operations (inventory + shipping)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;External callbacks&lt;/strong&gt; for order approval with 24-hour timeout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Batch processing&lt;/strong&gt; with &lt;code&gt;map()&lt;/code&gt; for shipping multiple items&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The entire workflow runs for 25+ hours (1-hour fraud check + 24-hour approval window) while only consuming compute during active operations.&lt;/p&gt;




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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" rel="noopener noreferrer"&gt;AWS Lambda Durable Functions Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.npmjs.com/package/@aws/durable-execution-sdk-js" rel="noopener noreferrer"&gt;@aws/durable-execution-sdk-js on npm&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Have you tried Lambda Durable Functions yet? What workflows are you building with them? Share your experiences and questions in the comments below!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>lambda</category>
      <category>serverless</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Stop Using AWS Access Keys in GitHub Actions: The OIDC Guide You Need</title>
      <dc:creator>Ali Zgheib</dc:creator>
      <pubDate>Mon, 22 Dec 2025 22:24:16 +0000</pubDate>
      <link>https://dev.to/alizgheib/stop-using-aws-access-keys-in-github-actions-the-oidc-guide-you-need-4c8l</link>
      <guid>https://dev.to/alizgheib/stop-using-aws-access-keys-in-github-actions-the-oidc-guide-you-need-4c8l</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;OpenID Connect (OIDC) allows your GitHub Actions workflows to access resources in Amazon Web Services (AWS) without storing long-lived AWS credentials as GitHub secrets. Whether you're deploying Lambda functions, updating S3 buckets, managing EC2 instances, or using any AWS service, this guide shows you how to transition from using AWS access keys to OIDC authentication.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why OIDC Instead of Access Keys?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Access Keys (Traditional Method):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ Long-lived credentials that never expire&lt;/li&gt;
&lt;li&gt;❌ Must be rotated manually&lt;/li&gt;
&lt;li&gt;❌ If leaked, remain valid until manually revoked&lt;/li&gt;
&lt;li&gt;❌ Stored as GitHub secrets&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;OIDC (Modern Method):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Short-lived tokens that expire automatically&lt;/li&gt;
&lt;li&gt;✅ No credentials to rotate&lt;/li&gt;
&lt;li&gt;✅ Tokens are automatically invalidated after use&lt;/li&gt;
&lt;li&gt;✅ Fine-grained access control with trust policies&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Before proceeding, ensure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An AWS account with IAM permissions&lt;/li&gt;
&lt;li&gt;A GitHub repository&lt;/li&gt;
&lt;li&gt;Basic understanding of IAM roles and policies&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Step 1: Add GitHub OIDC Provider to AWS
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to the &lt;strong&gt;IAM Console&lt;/strong&gt; in AWS&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Identity providers&lt;/strong&gt; → &lt;strong&gt;Add provider&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Select &lt;strong&gt;OpenID Connect&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configure the provider:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Provider URL&lt;/strong&gt;: &lt;code&gt;https://token.actions.githubusercontent.com&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audience&lt;/strong&gt;: &lt;code&gt;sts.amazonaws.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Add provider&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 2: Create IAM Role with Trust Policy
&lt;/h2&gt;

&lt;p&gt;Navigate to &lt;strong&gt;IAM&lt;/strong&gt; → &lt;strong&gt;Roles&lt;/strong&gt; → &lt;strong&gt;Create role&lt;/strong&gt; to begin.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Select Trusted Entity
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Select &lt;strong&gt;Web identity&lt;/strong&gt; as the trusted entity type&lt;/li&gt;
&lt;li&gt;Configure the identity provider using the dropdowns:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identity provider&lt;/strong&gt;: Select &lt;code&gt;token.actions.githubusercontent.com&lt;/code&gt; from the dropdown&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Audience&lt;/strong&gt;: Select &lt;code&gt;sts.amazonaws.com&lt;/code&gt; from the dropdown&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub organization&lt;/strong&gt;: Enter your organization or personal username (e.g., &lt;code&gt;AliZgheib&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub repository&lt;/strong&gt; (optional): Enter &lt;code&gt;*&lt;/code&gt; to allow all repositories, or specify a specific repo name&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub branch&lt;/strong&gt; (optional): Enter &lt;code&gt;*&lt;/code&gt; to allow all branches, or specify a specific branch like &lt;code&gt;main&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Next&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip&lt;/strong&gt;: Using &lt;code&gt;*&lt;/code&gt; for repository and branch gives you flexibility, but for better security, specify exact repository and branch names in production.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Step 2: Add Permissions
&lt;/h3&gt;

&lt;p&gt;Attach the necessary permissions for your deployment based on what AWS services you're using:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Common AWS Services:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Lambda &amp;amp; API Gateway&lt;/strong&gt;: &lt;code&gt;AWSLambdaFullAccess&lt;/code&gt;, &lt;code&gt;AmazonAPIGatewayAdministrator&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3&lt;/strong&gt;: &lt;code&gt;AmazonS3FullAccess&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EC2&lt;/strong&gt;: &lt;code&gt;AmazonEC2FullAccess&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ECS/Fargate&lt;/strong&gt;: &lt;code&gt;AmazonECS_FullAccess&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFormation/CDK/Terraform&lt;/strong&gt;: &lt;code&gt;CloudFormationFullAccess&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;General deployments&lt;/strong&gt;: &lt;code&gt;IAMFullAccess&lt;/code&gt; (or more restricted custom policy)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In production, create a custom policy with least-privilege permissions specific to your needs.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Next&lt;/strong&gt; to continue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Name, Review, and Create
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Name the role&lt;/strong&gt;: Enter a descriptive name (e.g., &lt;code&gt;GitHubToAWSOIDC&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Description&lt;/strong&gt; (optional): Add a description like "Role for GitHub Actions to deploy to AWS via OIDC"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Review&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Step 1: Select trusted entities&lt;/strong&gt;: Verify your GitHub org/repo settings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 2: Add permissions&lt;/strong&gt;: Verify the policies you attached&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Step 3: Add tags&lt;/strong&gt; (optional): Add tags if needed for organization&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Create role&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Copy the Role ARN
&lt;/h3&gt;

&lt;p&gt;After the role is created successfully, find and copy the &lt;strong&gt;Role ARN&lt;/strong&gt; (e.g., &lt;code&gt;arn:aws:iam::123456789012:role/GitHubToAWSOIDC&lt;/code&gt;). You'll need this for the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Understanding the Trust Policy (Reference)
&lt;/h3&gt;

&lt;p&gt;AWS automatically generates a trust policy based on your selections. Here's what it looks like:&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;"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;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="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;"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;"sts:AssumeRoleWithWebIdentity"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&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;"Federated"&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:iam::YOUR_ACCOUNT_ID:oidc-provider/token.actions.githubusercontent.com"&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;"Condition"&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;"StringEquals"&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;"token.actions.githubusercontent.com:aud"&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;"sts.amazonaws.com"&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;"StringLike"&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;"token.actions.githubusercontent.com:sub"&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;"repo:YOUR_ORG/*"&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key elements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;token.actions.githubusercontent.com:aud&lt;/code&gt;&lt;/strong&gt;: Ensures the token is intended for AWS STS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;token.actions.githubusercontent.com:sub&lt;/code&gt;&lt;/strong&gt;: Restricts access based on your GitHub org/repo/branch selections

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;repo:YOUR_ORG/*&lt;/code&gt; means any repository under your organization, any branch&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: For most use cases, the trust policy generated by AWS from the UI is sufficient. You can manually edit it later if you need more specific control (e.g., specific repository, branch, or environment restrictions).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Step 3: Add GitHub Repository Secret
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Go to your GitHub repository&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Secrets and variables&lt;/strong&gt; → &lt;strong&gt;Actions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Add a new repository secret:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Name&lt;/strong&gt;: &lt;code&gt;AWS_ROLE_ARN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Value&lt;/strong&gt;: Your IAM role ARN (e.g., &lt;code&gt;arn:aws:iam::123456789012:role/GitHubToAWSOIDC&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 4: Update GitHub Actions Workflow
&lt;/h2&gt;

&lt;p&gt;Update your &lt;code&gt;.github/workflows/deploy.yml&lt;/code&gt; to use OIDC instead of access keys:&lt;/p&gt;

&lt;h3&gt;
  
  
  Before (Access Keys):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS Credentials (Access Keys)&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;aws-access-key-id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-secret-access-key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After (OIDC):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;   &lt;span class="c1"&gt;# Required for requesting the JWT&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;    &lt;span class="c1"&gt;# Required for actions/checkout&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS Credentials (OIDC)&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ROLE_ARN }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Changes:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Added &lt;code&gt;permissions&lt;/code&gt; block&lt;/strong&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;id-token: write&lt;/code&gt; allows GitHub to create a JWT token&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;contents: read&lt;/code&gt; allows checking out the repository&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Replaced credentials&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removed &lt;code&gt;aws-access-key-id&lt;/code&gt; and &lt;code&gt;aws-secret-access-key&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;role-to-assume&lt;/code&gt; with the IAM role ARN&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Updated step name&lt;/strong&gt;: Changed from "Access Keys" to "OIDC" for clarity&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Step 5: Clean Up Old Secrets (Optional)
&lt;/h2&gt;

&lt;p&gt;After confirming OIDC works successfully, remove the old access key secrets:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Go to &lt;strong&gt;Settings&lt;/strong&gt; → &lt;strong&gt;Secrets and variables&lt;/strong&gt; → &lt;strong&gt;Actions&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Delete &lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Delete &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Important&lt;/strong&gt;: Delete these secrets only after verifying OIDC authentication works!&lt;/p&gt;

&lt;h2&gt;
  
  
  Complete Workflow Example
&lt;/h2&gt;

&lt;p&gt;Here's a complete workflow example deploying to AWS (this example uses Serverless Framework, but the OIDC configuration works with any deployment tool):&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;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy Lambda to AWS&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
  &lt;span class="na"&gt;workflow_dispatch&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;id-token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;write&lt;/span&gt;
      &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;read&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Checkout code&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup Node.js&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-node@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;node-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;22'&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Configure AWS Credentials (OIDC)&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;aws-actions/configure-aws-credentials@v4&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;role-to-assume&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ROLE_ARN }}&lt;/span&gt;
          &lt;span class="na"&gt;aws-region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;us-east-1&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npm install&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to AWS&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;npx serverless deploy --verbose&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Testing the Setup
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Commit and push your changes to the &lt;code&gt;main&lt;/code&gt; branch&lt;/li&gt;
&lt;li&gt;Navigate to &lt;strong&gt;Actions&lt;/strong&gt; tab in your GitHub repository&lt;/li&gt;
&lt;li&gt;Monitor the workflow run&lt;/li&gt;
&lt;li&gt;Verify the "Configure AWS Credentials (OIDC)" step succeeds&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Troubleshooting
&lt;/h2&gt;

&lt;p&gt;If your deployment fails, the most common issue is &lt;strong&gt;insufficient permissions&lt;/strong&gt;. Ensure your IAM role has all the necessary permissions for the AWS services you're deploying to. If you're using granular (least-privilege) permissions instead of the full access policies, you may need to add specific permissions based on the error messages in your GitHub Actions logs.&lt;/p&gt;

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

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Use specific conditions&lt;/strong&gt;: Restrict the trust policy to specific branches or environments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least privilege permissions&lt;/strong&gt;: Attach only the minimum required permissions to the IAM role&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitor usage&lt;/strong&gt;: Enable AWS CloudTrail to audit role assumptions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regular reviews&lt;/strong&gt;: Periodically review and update trust policies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use environments&lt;/strong&gt;: For production deployments, use GitHub environments with protection rules&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Comparison Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Access Keys&lt;/th&gt;
&lt;th&gt;OIDC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Credential lifetime&lt;/td&gt;
&lt;td&gt;Permanent&lt;/td&gt;
&lt;td&gt;Temporary&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotation required&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets to manage&lt;/td&gt;
&lt;td&gt;2 per AWS account&lt;/td&gt;
&lt;td&gt;1 per IAM role&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Security risk if leaked&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Setup complexity&lt;/td&gt;
&lt;td&gt;Simple&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

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

&lt;p&gt;By switching from AWS access keys to OIDC, you've improved your deployment security by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Eliminating long-lived credentials&lt;/li&gt;
&lt;li&gt;Reducing secret management overhead&lt;/li&gt;
&lt;li&gt;Implementing fine-grained access control&lt;/li&gt;
&lt;li&gt;Following AWS and GitHub security best practices&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The initial setup requires more configuration, but the long-term security and maintenance benefits make OIDC the recommended approach for production deployments.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect" rel="noopener noreferrer"&gt;GitHub OIDC Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_providers_create_oidc.html" rel="noopener noreferrer"&gt;AWS IAM OIDC Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/aws-actions/configure-aws-credentials" rel="noopener noreferrer"&gt;aws-actions/configure-aws-credentials&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Have you made the switch to OIDC? Share your experience in the comments below! 👇&lt;/p&gt;

</description>
      <category>aws</category>
      <category>github</category>
      <category>devops</category>
      <category>security</category>
    </item>
    <item>
      <title>🧠 Kiro: From Steering Docs to Specs to Hooks — An Agentic IDE Walkthrough</title>
      <dc:creator>Ali Zgheib</dc:creator>
      <pubDate>Mon, 22 Dec 2025 16:14:34 +0000</pubDate>
      <link>https://dev.to/alizgheib/kiro-from-steering-docs-to-specs-to-hooks-an-agentic-ide-walkthrough-3nbf</link>
      <guid>https://dev.to/alizgheib/kiro-from-steering-docs-to-specs-to-hooks-an-agentic-ide-walkthrough-3nbf</guid>
      <description>&lt;p&gt;Kiro is a new agentic IDE that brings structure and intent back into AI-assisted software development. Instead of generating isolated code snippets from prompts, Kiro introduces a workflow centered around persistent context, structured specifications, and event-driven automation.&lt;/p&gt;

&lt;p&gt;This article walks through the three core building blocks of Kiro: Steering Docs, Specs, and Hooks, and how they work together to support spec-driven development.&lt;/p&gt;

&lt;p&gt;📘 Steering Docs — Persistent Project Context&lt;/p&gt;

&lt;p&gt;Steering docs allow Kiro to understand a project beyond the current prompt. They store long-lived knowledge such as architecture decisions, coding standards, naming conventions, and domain rules.&lt;/p&gt;

&lt;p&gt;These documents are written in markdown and live alongside the codebase. Once defined, Kiro consistently uses them when generating code, reviewing changes, or performing automated tasks. This removes the need to repeatedly explain project context and helps ensure outputs match real-world team standards.&lt;/p&gt;

&lt;p&gt;📐 Specs — Structured Development from Intent&lt;/p&gt;

&lt;p&gt;Specs are the foundation of Kiro’s spec-driven workflow. Instead of jumping directly from a prompt to code, Kiro helps break features into structured documents:&lt;/p&gt;

&lt;p&gt;Requirements — clear functional expectations and acceptance criteria&lt;/p&gt;

&lt;p&gt;Design — technical architecture, data models, and implementation approach&lt;/p&gt;

&lt;p&gt;Tasks — a sequenced list of actionable development steps&lt;/p&gt;

&lt;p&gt;This approach makes complex features easier to reason about, review, and maintain, while keeping AI output aligned with the original intent.&lt;/p&gt;

&lt;p&gt;⚙️ Hooks — Event-Driven Automation&lt;/p&gt;

&lt;p&gt;Hooks enable automation based on IDE events such as file saves, file creation, or commits. When triggered, Kiro can run agent workflows or commands automatically.&lt;/p&gt;

&lt;p&gt;Common use cases include:&lt;/p&gt;

&lt;p&gt;Generating or updating tests when files change&lt;/p&gt;

&lt;p&gt;Keeping documentation in sync with code&lt;/p&gt;

&lt;p&gt;Enforcing project standards and best practices&lt;/p&gt;

&lt;p&gt;Running checks before changes are committed&lt;/p&gt;

&lt;p&gt;Hooks allow Kiro to operate continuously in the background, reducing manual overhead and improving consistency across the codebase.&lt;/p&gt;

&lt;p&gt;🔁 How It All Fits Together&lt;/p&gt;

&lt;p&gt;Steering docs provide long-term context&lt;/p&gt;

&lt;p&gt;Specs provide structure and traceability&lt;/p&gt;

&lt;p&gt;Hooks provide automation and enforcement&lt;/p&gt;

&lt;p&gt;Together, they enable a workflow where AI assists with real engineering work, not just code generation.&lt;/p&gt;

&lt;p&gt;🎥 Video Walkthrough&lt;/p&gt;

&lt;p&gt;A full walkthrough of Kiro, covering steering docs, specs, and hooks in action:&lt;br&gt;
&lt;a href="https://www.youtube.com/watch?v=SPDziEBuWwY" rel="noopener noreferrer"&gt;https://www.youtube.com/watch?v=SPDziEBuWwY&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>githubcopilot</category>
      <category>kiro</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Learn Serverless on AWS: Live Demo &amp; Walkthrough – Wednesday, Aug 27</title>
      <dc:creator>Ali Zgheib</dc:creator>
      <pubDate>Fri, 22 Aug 2025 14:02:05 +0000</pubDate>
      <link>https://dev.to/alizgheib/learn-serverless-on-aws-live-demo-walkthrough-wednesday-aug-27-4jep</link>
      <guid>https://dev.to/alizgheib/learn-serverless-on-aws-live-demo-walkthrough-wednesday-aug-27-4jep</guid>
      <description>&lt;p&gt;Join us on Wednesday, August 27 for an engaging session on Serverless in Action: Building and Deploying APIs on AWS.&lt;br&gt;
We’ll break down what serverless really means, why it matters, and where it shines (and doesn’t). Then, I’ll take you through a live walkthrough: designing, building, testing, deploying, and documenting an API step by step on AWS. This will be a demo-style session—you can watch the process end-to-end and leave with practical insights to apply later.&lt;/p&gt;

&lt;p&gt;Details:&lt;/p&gt;

&lt;p&gt;🗓️ Date: Wednesday, August 27&lt;br&gt;
🕕 Time: 6:00 PM EEST / 7:00 PM GST&lt;br&gt;
📍 Location: Online (Google Meet link shared after registration)&lt;br&gt;
🔗 Register here: &lt;a href="https://www.meetup.com/acc-mena/events/310519152/" rel="noopener noreferrer"&gt;https://www.meetup.com/acc-mena/events/310519152/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Speaker: Ali Zgheib – Founding Engineer at CELITECH, AWS Certified (7x), and ACC community co-lead passionate about knowledge-sharing.&lt;/p&gt;

&lt;p&gt;Whether you’re new to serverless or looking to sharpen your AWS skills, this walkthrough will help you see the concepts in action. Hope to see you there!&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%2F86u3tkz3iuxyd53r0gl3.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%2F86u3tkz3iuxyd53r0gl3.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>How I Built &amp; Deployed 'DevMood' Developer App in 24 Hours with Pulumi &amp; AWS 🔥</title>
      <dc:creator>Ali Zgheib</dc:creator>
      <pubDate>Sun, 06 Apr 2025 19:57:45 +0000</pubDate>
      <link>https://dev.to/alizgheib/how-i-built-deployed-devmood-developer-app-in-24-hours-with-pulumi-29a8</link>
      <guid>https://dev.to/alizgheib/how-i-built-deployed-devmood-developer-app-in-24-hours-with-pulumi-29a8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/pulumi"&gt;Pulumi Deploy and Document Challenge&lt;/a&gt;: Fast Static Website Deployment&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What I Built
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;DevMood&lt;/strong&gt; is a web application designed to enhance a developer's coding experience by offering dev jokes, coding music, and weather updates. The app is hosted on &lt;strong&gt;AWS&lt;/strong&gt; and uses &lt;strong&gt;Pulumi&lt;/strong&gt; for Infrastructure as Code (IaC), ensuring seamless deployment and scalability. The app includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dev Jokes&lt;/strong&gt; 💬: A collection of funny developer jokes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Coding Music 🎶&lt;/strong&gt;: Background music to help stay focused.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Weather Info 🌤️&lt;/strong&gt;: Real-time weather updates based on your location.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Design 📱&lt;/strong&gt;: Adapts to various screen sizes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Live Demo Link
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://d2y1cy8163fewy.cloudfront.net" rel="noopener noreferrer"&gt;DevMood Live Demo&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Project Repo
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/AliZgheib/DevMood" rel="noopener noreferrer"&gt;DevMood GitHub Repo&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  My Journey
&lt;/h1&gt;

&lt;p&gt;When I decided to participate in the &lt;strong&gt;Pulumi Deploy and Document Challenge&lt;/strong&gt;, my goal was to build a project that demonstrates Pulumi’s power in deploying cloud infrastructure on AWS. I had some experience with cloud deployments, but Pulumi provided the opportunity to dive deeper into &lt;strong&gt;Infrastructure as Code&lt;/strong&gt; with a TypeScript-first approach.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Project
&lt;/h3&gt;

&lt;p&gt;The first step was to set up the project structure, including &lt;strong&gt;Next.js&lt;/strong&gt; for the frontend and configuring the backend services on &lt;strong&gt;AWS&lt;/strong&gt; with &lt;strong&gt;Pulumi&lt;/strong&gt;. I used &lt;strong&gt;Tailwind CSS&lt;/strong&gt; for styling to ensure the app was responsive and dynamic across devices. The frontend was a bit tricky in terms of layout, but once I got the hang of it, the combination of Next.js and Tailwind made it much smoother.&lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend Setup
&lt;/h3&gt;

&lt;p&gt;For the frontend, I used &lt;strong&gt;Next.js&lt;/strong&gt; with &lt;strong&gt;Tailwind CSS&lt;/strong&gt; for utility-first styling. Next.js allowed me to implement server-side rendering for better performance, while Tailwind CSS ensured a responsive layout. Here's a preview:&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%2Fonly1t1rn8cy6u0kr0n6.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%2Fonly1t1rn8cy6u0kr0n6.png" alt="DevMood Frontend Preview" width="800" height="363"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure-1 (Static Website Hosting with S3)
&lt;/h3&gt;

&lt;p&gt;For the basic version of &lt;strong&gt;DevMood&lt;/strong&gt;, I used &lt;strong&gt;Amazon S3&lt;/strong&gt;'s static website hosting feature. It’s a cost-effective and scalable solution for hosting the frontend. The infrastructure is managed with &lt;strong&gt;Pulumi&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Components:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 Bucket&lt;/strong&gt;: Stores the static website files (HTML, CSS, JS).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Website Hosting&lt;/strong&gt;: Configured for the app to be served with an index and error document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bucket Policy&lt;/strong&gt;: Ensures public access to the static assets.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="http://dev-mood-1-bucket-81bfedd.s3-website-us-east-1.amazonaws.com/" rel="noopener noreferrer"&gt;Infrastructure-1 Preview&lt;/a&gt;&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%2Fyp1xyhr53frphji19chq.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%2Fyp1xyhr53frphji19chq.png" alt="Infrastructure-1 Diagram" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Infrastructure-2 (Static Website Hosting with S3, CloudFront, and OAC)
&lt;/h3&gt;

&lt;p&gt;For the enhanced version of &lt;strong&gt;DevMood&lt;/strong&gt;, I added &lt;strong&gt;CloudFront&lt;/strong&gt; for content delivery and &lt;strong&gt;Origin Access Control (OAC)&lt;/strong&gt; for security, ensuring that only &lt;strong&gt;CloudFront&lt;/strong&gt; could access the S3 bucket. This optimized infrastructure is also managed by &lt;strong&gt;Pulumi&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Key Components:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;S3 Bucket&lt;/strong&gt;: Hosts static files but with public access restricted to CloudFront.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CloudFront CDN&lt;/strong&gt;: Caches and delivers static content globally, improving performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OAC (Origin Access Control)&lt;/strong&gt;: Ensures that only CloudFront can securely access the S3 files.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://d2y1cy8163fewy.cloudfront.net" rel="noopener noreferrer"&gt;Infrastructure-2 Preview&lt;/a&gt;&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%2Fcs0bb10n32zwmi6yojmo.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%2Fcs0bb10n32zwmi6yojmo.png" alt="Infrastructure-2 Diagram" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Integration (CI)
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;CI pipeline&lt;/strong&gt; ensures that code is continuously linted and checked for quality with each pull request. It lints the &lt;strong&gt;frontend&lt;/strong&gt;, &lt;strong&gt;Infrastructure-1&lt;/strong&gt;, and &lt;strong&gt;Infrastructure-2&lt;/strong&gt; code to ensure consistency and catch errors early in the process. Here's how it works:&lt;/p&gt;

&lt;h4&gt;
  
  
  Steps:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Code Checkout&lt;/strong&gt;: Pulls the latest code from the repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Node.js Setup&lt;/strong&gt;: Installs the latest version of Node.js (v18).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linting&lt;/strong&gt;: Runs the linting process to catch any coding errors or style violations before merging to the main branch.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Technologies Used:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt;: Automates the linting process with pull request triggers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ESLint&lt;/strong&gt;: Used for linting the frontend and infrastructure code.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frd2mkwf6aq2nly0oz79o.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%2Frd2mkwf6aq2nly0oz79o.png" alt="CI Workflow" width="800" height="250"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous Deployment (CD)
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;CD pipeline&lt;/strong&gt; automates the deployment of the application whenever there is a push to the main branch. It deploys &lt;strong&gt;Infrastructure-1&lt;/strong&gt; (Static Website Hosting with S3) and &lt;strong&gt;Infrastructure-2&lt;/strong&gt; (Static Website Hosting with S3, CloudFront, and OAC). Here's how the process works:&lt;/p&gt;

&lt;h4&gt;
  
  
  Steps:
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Code Checkout&lt;/strong&gt;: Pulls the latest code from the repository.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Static Website Build&lt;/strong&gt;: Builds the static website assets from the frontend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS Credentials Configuration&lt;/strong&gt;: Configures AWS access keys for secure deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy Infrastructure-1 via Pulumi&lt;/strong&gt;: Deploys &lt;strong&gt;Infrastructure-1&lt;/strong&gt; by uploading the static website files to the S3 bucket.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deploy Infrastructure-2 via Pulumi&lt;/strong&gt;: Deploys &lt;strong&gt;Infrastructure-2&lt;/strong&gt; by uploading the static website files to the S3 bucket, while ensuring CloudFront and OAC are properly configured for enhanced security and performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Technologies Used:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt;: Automates the deployment process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pulumi GitHub Action&lt;/strong&gt;: Deploys infrastructure as code using &lt;strong&gt;Pulumi&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS GitHub Action&lt;/strong&gt;: Manages AWS deployments and configurations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbeob9e30raadbxjaik90.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%2Fbeob9e30raadbxjaik90.png" alt="CD Workflow" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Using Pulumi
&lt;/h1&gt;

&lt;p&gt;I used &lt;strong&gt;Pulumi&lt;/strong&gt; as my Infrastructure as Code (IaC) tool to deploy all the infrastructure, including &lt;strong&gt;S3 buckets&lt;/strong&gt;, &lt;strong&gt;CloudFront distributions&lt;/strong&gt;, and &lt;strong&gt;Origin Access Control (OAC)&lt;/strong&gt; to secure the S3 bucket. Here's how Pulumi helped me:&lt;/p&gt;

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

&lt;p&gt;Having prior experience with &lt;strong&gt;AWS CDK&lt;/strong&gt; and &lt;strong&gt;Serverless Framework&lt;/strong&gt;, Pulumi’s TypeScript-first approach was both familiar and intuitive. The learning curve was steep at first, but the &lt;strong&gt;Pulumi documentation&lt;/strong&gt; was super helpful in getting me up and running in &lt;strong&gt;less than 24 hours&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-Stack Management
&lt;/h3&gt;

&lt;p&gt;One of the more challenging aspects was managing the different stacks for the &lt;strong&gt;basic static hosting&lt;/strong&gt; and the &lt;strong&gt;optimized version with CloudFront and OAC&lt;/strong&gt;. Pulumi’s multi-stack management feature made it easy to handle the separation of concerns while keeping the infrastructure as code clean and manageable.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pulumi Action
&lt;/h3&gt;

&lt;p&gt;For the &lt;strong&gt;Continuous Deployment (CD)&lt;/strong&gt; setup, I used &lt;strong&gt;Pulumi GitHub Action&lt;/strong&gt; to automate the deployment of my infrastructure. It integrates seamlessly with GitHub Actions and was a perfect fit for managing the deployment pipeline. Pulumi’s action makes it easy to trigger the deployment process and manage the infrastructure via code, ensuring a smooth and reliable CD pipeline.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/pulumi/actions" rel="noopener noreferrer"&gt;Pulumi GitHub Actions&lt;/a&gt; for more information.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In less than &lt;strong&gt;24 hours&lt;/strong&gt;, I successfully built and deployed &lt;strong&gt;DevMood&lt;/strong&gt; using &lt;strong&gt;Pulumi&lt;/strong&gt; and &lt;strong&gt;AWS&lt;/strong&gt;. Despite some challenges with multi-stack management and initial syntax hurdles, Pulumi’s TypeScript-first approach made it easy to automate infrastructure deployment. If you’re looking to simplify your cloud deployments and enjoy the benefits of IaC, I highly recommend giving &lt;strong&gt;Pulumi&lt;/strong&gt; a try.&lt;/p&gt;

&lt;p&gt;Feel free to check out the repo and contribute!&lt;/p&gt;




&lt;p&gt;Thanks for reading and thank you to &lt;strong&gt;Pulumi&lt;/strong&gt; for creating such an amazing tool!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>pulumichallenge</category>
      <category>webdev</category>
      <category>cloud</category>
    </item>
    <item>
      <title>How to deploy a React application to AWS using AWS S3 &amp; AWS CloudFront</title>
      <dc:creator>Ali Zgheib</dc:creator>
      <pubDate>Sun, 09 Jul 2023 00:26:05 +0000</pubDate>
      <link>https://dev.to/alizgheib/how-to-deploy-a-react-application-to-aws-using-aws-s3-aws-cloudfront-42km</link>
      <guid>https://dev.to/alizgheib/how-to-deploy-a-react-application-to-aws-using-aws-s3-aws-cloudfront-42km</guid>
      <description>&lt;p&gt;Hello everyone! I hope that you are doing great on this fine weekend😀&lt;/p&gt;

&lt;p&gt;Previously, I built a face recognition tool for celebrities where I deployed its back-end to AWS using AWS CDK.&lt;/p&gt;

&lt;p&gt;The link for the article can be found here: &lt;a href="https://dev.to/alizgheib/build-a-face-recognition-tool-for-celebrities-using-react-aws-foo"&gt;https://dev.to/alizgheib/build-a-face-recognition-tool-for-celebrities-using-react-aws-foo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Today, I'll be deploying the front-end part (React application) to Amazon Simple Storage Service (S3) while adding a caching solution using AWS CloudFront - So let's do it together!&lt;/p&gt;

&lt;p&gt;I thought that it would be pretty useful to outline our process into steps so that it would be easier for you to follow along.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Build/Deployment Outline:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fix a common issue with React applications (blank page)&lt;/li&gt;
&lt;li&gt;Create a production build&lt;/li&gt;
&lt;li&gt;Create an S3 Bucket on AWS and upload the content of the build 
folder&lt;/li&gt;
&lt;li&gt;Create a CloudFront distribution&lt;/li&gt;
&lt;li&gt;Enabled S3 public access to our bucket and allow access from 
our CloudFront distribution only (using OAC)&lt;/li&gt;
&lt;li&gt;That should be it! Our application should be running now and 
available on over 400+ edge locations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step By Step Guide:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you would like to follow along, feel free to use the codebase available here: &lt;a href="https://github.com/AliZgheib/celebrities-face-recognition/tree/main/front-end" rel="noopener noreferrer"&gt;https://github.com/AliZgheib/celebrities-face-recognition/tree/main/front-end&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's start:&lt;/p&gt;

&lt;p&gt;First of all, there's a small issue that I faced when accessing the deployed application (a blank page kept on showing)&lt;br&gt;
To fix that, we just need to add &lt;code&gt;"homepage": "."&lt;/code&gt; in the &lt;code&gt;package.json&lt;/code&gt; file. &lt;/p&gt;

&lt;p&gt;the &lt;code&gt;package.json&lt;/code&gt; should look as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "front-end",
  "version": "0.1.0",
  "private": true,
  "homepage": ".",
  "dependencies": {
    // project dependencies here
  },
  // other configurations
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's create a production build of the application&lt;/p&gt;

&lt;p&gt;We cd into the project directory&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd front-end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a production build by running the NPM command below:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;After a successful run we should have a build folder similar to the one below:&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%2Fmbpx9k7r7axguhlw4ymw.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%2Fmbpx9k7r7axguhlw4ymw.PNG" alt=" " width="398" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now let's login to the AWS Console and Navigate to the AWS S3 service page.&lt;/p&gt;

&lt;p&gt;We click on the "Create bucket" button to create an S3 bucket that will host our React application code&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%2Ft4f99d23vannocho8yuf.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%2Ft4f99d23vannocho8yuf.PNG" alt=" " width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We name our s3 bucket (ex: &lt;code&gt;celebrities-face-recognition&lt;/code&gt; - it should be globally unique) and we click the "Create bucket" button at the bottom without the need to modify any other options.&lt;/p&gt;

&lt;p&gt;We should see something similar to the image below:&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%2Fnn0mbhxr18l64ueb5sxt.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%2Fnn0mbhxr18l64ueb5sxt.PNG" alt=" " width="800" height="299"&gt;&lt;/a&gt;&lt;br&gt;
Now let's upload the previously created production build to the S3 bucket.&lt;/p&gt;

&lt;p&gt;We click on &lt;code&gt;celebrities-face-recognition&lt;/code&gt; (the name of the bucket you created) and we click on “Upload”.&lt;/p&gt;

&lt;p&gt;We upload the files (&lt;code&gt;index.html&lt;/code&gt;, &lt;code&gt;favicon.ico&lt;/code&gt;, &lt;code&gt;asset-manifest.json&lt;/code&gt;, &lt;code&gt;robots.txt&lt;/code&gt;) and the &lt;code&gt;static&lt;/code&gt; folder separately and at the end, we should have something similar to the list below ready to be uploaded:&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%2F5y7xi8sexityqphkfqf2.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%2F5y7xi8sexityqphkfqf2.PNG" alt=" " width="800" height="728"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we click the "Upload" button at the bottom of the page and after waiting a couple of moments, our project should be successfully uploaded.&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%2F9r8rssrngx6d6dr7bo58.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%2F9r8rssrngx6d6dr7bo58.PNG" alt=" " width="800" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great progress if you are still following along!&lt;/p&gt;

&lt;p&gt;The setup for our S3 bucket is partially ready. We have to add a caching solution to our S3 bucket and expose our website to the web (via AWS CloudFront) and finally, we go back to S3 to update the permissions.&lt;/p&gt;

&lt;p&gt;Let's navigate to the AWS CloudFront service and click on the "Create a CloudFront distribution" button to create a new distribution.&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%2Fbn40mfkvj5l958bjtpmc.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%2Fbn40mfkvj5l958bjtpmc.PNG" alt=" " width="800" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1- We pick &lt;code&gt;celebrities-face-recognition.s3.us-east-1.amazonaws.com&lt;/code&gt; for the Origin domain option&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%2Fytxoyrjq88hosb9u5pyl.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%2Fytxoyrjq88hosb9u5pyl.PNG" alt=" " width="800" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2- Now for the Origin access option:&lt;/p&gt;

&lt;p&gt;2.a- Let's change it from "Public" to "Origin access control settings (recommended)" - OAC is the newer and recommended approach to access your S3 bucket from AWS CloudFront.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;b- Click "Create control setting"&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;c- Click "Create"&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0krdxriszd5zmyqm180g.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%2F0krdxriszd5zmyqm180g.PNG" alt=" " width="752" height="759"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3- For the WAF option: pick whatever fits your needs. For my case, I'll go ahead and disable it&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%2F3paz6scby8le6ywjrc33.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%2F3paz6scby8le6ywjrc33.PNG" alt=" " width="800" height="233"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4- For the Default root object, we enter "index.html" as our &lt;br&gt;
   default object&lt;/p&gt;

&lt;p&gt;5- We click "Create distribution" to create our distribution.&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%2Fgq1waoss63qjnzhxbukk.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%2Fgq1waoss63qjnzhxbukk.PNG" alt=" " width="800" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;that's it for CloudFront, our distribution is now being deployed globally and you should see a screen similar to the one below:&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%2Fp4ekkvixboxshribsha8.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%2Fp4ekkvixboxshribsha8.PNG" alt=" " width="800" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see the distribution domain name: &lt;a href="https://d3b1yxs153bxzh.cloudfront.net" rel="noopener noreferrer"&gt;https://d3b1yxs153bxzh.cloudfront.net&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;However, if we try to access it, we will get an error because S3 is not allowing our CloudFront distribution to access it - let's change that!&lt;/p&gt;

&lt;p&gt;Let's copy the new S3 bucket policy by clicking the "Copy Policy" button at the top right of the screen.&lt;/p&gt;

&lt;p&gt;We navigate back to the AWS S3 service and we open the "permissions" section of our &lt;code&gt;celebrities-face-recognition&lt;/code&gt; bucket.&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%2F9v7njatpsoezzqdk4rgm.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%2F9v7njatpsoezzqdk4rgm.PNG" alt=" " width="800" height="274"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;1- Click the "Edit" button in the "Block public access (bucket settings)" section and make sure to untick all the options then click "Save changes".&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%2F1it0obfj1fvvzpjo2vty.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%2F1it0obfj1fvvzpjo2vty.PNG" alt=" " width="800" height="686"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2- Click the "Edit" button in the "Bucket policy" section and paste the previously copied CloudFront permissions here then click "Save changes".&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%2Fj22mbtk8xcx96i8pv68j.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%2Fj22mbtk8xcx96i8pv68j.PNG" alt=" " width="800" height="366"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Guess what? The distribution is working now 😀 and can be accessed globally at minimal latency - &lt;a href="https://d3b1yxs153bxzh.cloudfront.net" rel="noopener noreferrer"&gt;https://d3b1yxs153bxzh.cloudfront.net&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can go a bit further and link the distribution URL to your domain (ex: &lt;a href="https://www.example.com" rel="noopener noreferrer"&gt;https://www.example.com&lt;/a&gt;) using a DNS provider like GoDaddy, Name Cheap, Route 53, etc.. but that would be outside the scope of this article.&lt;/p&gt;

&lt;p&gt;Please note that the distribution created is for education purposes only and it will be taken down before publishing the article. Use it as a guide to create and publish your distributions.&lt;/p&gt;

&lt;p&gt;Thank you for sticking with me till the end and I would appreciate any feedback in the comments section below.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>webdev</category>
      <category>simple</category>
      <category>react</category>
    </item>
    <item>
      <title>Build a face recognition tool for celebrities using React &amp; AWS</title>
      <dc:creator>Ali Zgheib</dc:creator>
      <pubDate>Thu, 06 Jul 2023 06:53:14 +0000</pubDate>
      <link>https://dev.to/alizgheib/build-a-face-recognition-tool-for-celebrities-using-react-aws-foo</link>
      <guid>https://dev.to/alizgheib/build-a-face-recognition-tool-for-celebrities-using-react-aws-foo</guid>
      <description>&lt;p&gt;Hello everyone, This is my first tech blog on dev.to and in general. So I hope you hold tight while we go on this wild journey 😀&lt;/p&gt;

&lt;p&gt;Today we will be building a tool that can detect the faces of celebrities in a specific photo. The tool will be built using React JS for the front-end and on the back-end we will be using AWS CDK to deploy our infrastructure (APIGateway &amp;amp; AWS Lambda). Our backend will be interacting with AWS Rekognition (Machine learning and face recognition service provided by AWS - &lt;a href="https://aws.amazon.com/rekognition/" rel="noopener noreferrer"&gt;https://aws.amazon.com/rekognition/&lt;/a&gt; )&lt;/p&gt;

&lt;p&gt;I thought that it would be fun to showcase the final results before diving into the implementation steps.&lt;/p&gt;

&lt;p&gt;So let's say we have a celebrities photo as shown below:&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%2Fkjj4g3a48ka9qwdbg46t.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkjj4g3a48ka9qwdbg46t.jpg" alt=" " width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will upload the image to our application:&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%2F114sbf4qlde99yluhfya.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%2F114sbf4qlde99yluhfya.PNG" alt=" " width="699" height="443"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, after submitting the form we will get the results below:&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%2F8ikmkb8n3adg3upf2xll.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%2F8ikmkb8n3adg3upf2xll.PNG" alt=" " width="441" height="190"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I hope you liked the idea of the app and the accuracy of the results.&lt;/p&gt;

&lt;p&gt;Below is a simple architecture diagram created to showcase the final infrastructure and and how all service will be interacting with each other.&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%2Fam2c9sq4q7f5gis3kxnb.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%2Fam2c9sq4q7f5gis3kxnb.PNG" alt=" " width="800" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If that seems too complicated, no worries about it - we will be building it together step by step.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let's start!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First of all, we will start with our front-end (React application) and to do so we can create a basic typescript React project using the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app front-end --template typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After giving it a couple of seconds/minutes, we should have a basic react application that we can use as a base for our application.&lt;/p&gt;

&lt;p&gt;Let's start the application in development mode:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Our application will be simple and will consist of only 1 page which contains the upload file form and a modal to display the results. We will also make use of React states and the Fetch API to be able to interact with our API on the backend (which we will deploy later)&lt;/p&gt;

&lt;p&gt;Lets start with the code of the form:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
  const [file, setFile] = React.useState&amp;lt;File | null&amp;gt;(null);
  const [isLoading, setIsLoading] = React.useState(false);
  const [error, setError] = React.useState&amp;lt;string | null&amp;gt;(null);

  const handleSubmit = async (e: React.FormEvent&amp;lt;HTMLFormElement&amp;gt;) =&amp;gt; {
    // to be implemented later
  };

  const handleFileChange = (e: React.ChangeEvent&amp;lt;HTMLInputElement&amp;gt;) =&amp;gt; {
    if (!e.target.files || e.target.files.length === 0) {
      return setFile(null);
    }

    setFile(e.target.files[0]);
    setError(null);
  };
  return (
    &amp;lt;div className="container"&amp;gt;
      &amp;lt;div className="card"&amp;gt;
        &amp;lt;h3&amp;gt;Detect celebrities through pictures&amp;lt;/h3&amp;gt;
        &amp;lt;div className="drop_box"&amp;gt;
          &amp;lt;h4&amp;gt;Upload File here&amp;lt;/h4&amp;gt;
          &amp;lt;p&amp;gt;Files Supported: PNG &amp;amp; JPG&amp;lt;/p&amp;gt;

          &amp;lt;form onSubmit={handleSubmit}&amp;gt;
            &amp;lt;div className="form"&amp;gt;
              &amp;lt;input
                type="file"
                accept=".png,.jpg"
                id="fileID"
                disabled={isLoading}
                onChange={handleFileChange}
              /&amp;gt;
              &amp;lt;h6 id="file-name"&amp;gt;&amp;lt;/h6&amp;gt;

              &amp;lt;p id="error"&amp;gt;{error}&amp;lt;/p&amp;gt;
              &amp;lt;button
                type="submit"
                className="btn"
                id="submit-btn"
                disabled={isLoading}
              &amp;gt;
                {isLoading ? "Loading..." : "Submit"}
              &amp;lt;/button&amp;gt;
            &amp;lt;/div&amp;gt;
          &amp;lt;/form&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the form element (div with class "card") we can add the modal as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;interface CelebtritiesData {
  celebrityFaces: any[];
  unrecognizedFaces: any[];
}

  const [showModal, setShowModal] = React.useState(false);
  const [celebritiesData, setCelebtritiesData] =
    React.useState&amp;lt;CelebtritiesData | null&amp;gt;(null);

  const handleModalClose = () =&amp;gt; {
    setShowModal(false);
  };

  return (
    &amp;lt;div className="container"&amp;gt;
      {/* upload file form here */}
      {showModal &amp;amp;&amp;amp; (
        &amp;lt;div id="myModal" className="modal"&amp;gt;
          &amp;lt;div className="modal-content"&amp;gt;
            &amp;lt;span className="close" onClick={handleModalClose}&amp;gt;
              &amp;amp;times;
            &amp;lt;/span&amp;gt;

            &amp;lt;div className="modal-actual-content"&amp;gt;
              &amp;lt;h3&amp;gt;
                {`Number of recognized celebrities: ${celebritiesData?.celebrityFaces.length}`}
              &amp;lt;/h3&amp;gt;
              &amp;lt;ul&amp;gt;
                {celebritiesData?.celebrityFaces.map((celebrityFace) =&amp;gt; {
                  return &amp;lt;li&amp;gt;{celebrityFace.Name}&amp;lt;/li&amp;gt;;
                })}
              &amp;lt;/ul&amp;gt;

              {celebritiesData &amp;amp;&amp;amp;
                celebritiesData?.unrecognizedFaces.length &amp;gt; 0 &amp;amp;&amp;amp; (
                  &amp;lt;h5&amp;gt;
                    {`we weren't able to recognize ${celebritiesData?.unrecognizedFaces.length} celebrities: `}
                  &amp;lt;/h5&amp;gt;
                )}
            &amp;lt;/div&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
      )}
    &amp;lt;/div&amp;gt;
  );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full code (including css) can be found here: &lt;a href="https://github.com/AliZgheib/celebrities-face-recognition/tree/main/front-end" rel="noopener noreferrer"&gt;https://github.com/AliZgheib/celebrities-face-recognition/tree/main/front-end&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We still need to add the logic where we convert the image to base64 + send the results to our backend/API (which we will build soon)&lt;/p&gt;

&lt;p&gt;So lets take a break from our react application and deploy our backend using AWS CDK (AWS API Gateway + AWS Lambda)&lt;/p&gt;

&lt;p&gt;First of all there's a list of pre-requisite before we start working with AWS CDK - let's check it together:&lt;/p&gt;

&lt;p&gt;1- Install the recommended version of NodeJS - &lt;a href="https://nodejs.org/en" rel="noopener noreferrer"&gt;https://nodejs.org/en&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2- Install AWS CDK&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g aws-cdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;3- Configure your AWS credentials&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;aws configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;4- Make sure to install typescript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install -g typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now lets create our base AWS CDK project using typescript template&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir back-end
cd back-end
cdk init app --language typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After waiting a couple of seconds/minutes we should have our base AWS CDK project using typescript template.&lt;/p&gt;

&lt;p&gt;An important step that we need to do when setting up AWS CDK on a new AWS account (or new region) is running the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk bootstrap
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That should be for the setup!! Now lets continue coding again.&lt;/p&gt;

&lt;p&gt;If you are not familiar with AWS CDK or what it does. AWS CDK is basically a tool provided by AWS to help us provision infrastructure as code instead of via the console (clickops).&lt;/p&gt;

&lt;p&gt;Infrastructure as code is the future. it will help us write a better code that is reusable, maintainable, and we can review it before deploying the updates to our production environment.&lt;/p&gt;

&lt;p&gt;Now let's provision an API Gateway, a Lambda (which will act as an API endpoint) and add the necessary permissions for the Lambda to be able to interact with AWS Rekognition.&lt;/p&gt;

&lt;p&gt;We add the API Gateway to our CDK stack as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";

import * as apigateway from "aws-cdk-lib/aws-apigateway";


export class BackEndStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here

    const api = new apigateway.RestApi(this, "my-api", {
      description: "api gateway",
      deployOptions: {
        stageName: "dev",
      },
      // 👇 enable CORS
      defaultCorsPreflightOptions: {
        allowHeaders: [
          "Content-Type",
          "X-Amz-Date",
          "Authorization",
          "X-Api-Key",
        ],
        allowMethods: ["OPTIONS", "GET", "POST", "PUT", "PATCH", "DELETE"],
        allowCredentials: true,
        allowOrigins: ["*"],
      },
    });

    // 👇 create an Output for the API URL
    new cdk.CfnOutput(this, "apiUrl", { value: api.url });
  }
}

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

&lt;/div&gt;



&lt;p&gt;Now lets add the Lambda function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import * as path from "path";
import * as lambda from "aws-cdk-lib/aws-lambda";
import { Duration } from "aws-cdk-lib";

    // 👇 define the lambda function
    const rekognitionLambda = new lambda.Function(this, "rekognition-lambda", {
      runtime: lambda.Runtime.NODEJS_18_X,
      handler: "index.main",
      code: lambda.Code.fromAsset(path.join(__dirname, "/../src/rekognition")),
      timeout: Duration.seconds(10),
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see above we specified the Node JS runtime of the Lambda to be v18 and we also passed the handler path to the "code" property.&lt;/p&gt;

&lt;p&gt;We will add the Lambda Logic in a bit.&lt;/p&gt;

&lt;p&gt;Now lets give our Lambda function the necessary IAM permissions to be able to interact with AWS Rekognition.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // 👇 create a policy statement
    const rekognitionLambdaPolicy = new iam.PolicyStatement({
      actions: ["rekognition:RecognizeCelebrities"],
      resources: ["*"],
    });

    // 👇 add the policy to the Function's role
    rekognitionLambda.role?.attachInlinePolicy(
      new iam.Policy(this, "rekognition-lambda-policy", {
        statements: [rekognitionLambdaPolicy],
      })
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will also create a POST /rekognition endpoint under the API and we will assign the Lambda as an integration/proxy which will allow it to read the base64 image in the POST request body -&amp;gt; call AWS Regkonition service and return the response.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    // 👇 add a /rekognition resource
    const rekognitionResource = api.root.addResource("rekognition");

    // 👇 integrate POST /rekognition with rekognitionLambda
    rekognitionResource.addMethod(
      "POST",
      new apigateway.LambdaIntegration(rekognitionLambda, { proxy: true })
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's write the necessary logic for the Lambda function that will validate the "imageBase64" property in the body, forward it to AWS Regkognition service which will analyze the image and output a result. finally, the result will be formatted and returned to our front-end application.&lt;/p&gt;

&lt;p&gt;Lets create a new directory "src/rekognition" in the root of our "back-end" project. Under the "rekognition" folder we will add an "index.ts" file which will contain the actual code of the Lambda function.&lt;/p&gt;

&lt;p&gt;The content of the "index.ts" file should look as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {
  RekognitionClient,
  RecognizeCelebritiesCommand,
} from "@aws-sdk/client-rekognition";

const baseHandler = async (event: any) =&amp;gt; {
  try {
    const { imageBase64 } = JSON.parse(event.body);

    console.log("imageBase64", imageBase64);

    if (!imageBase64) {
      return new Error("imageBase64 is a required");
    }
    const rekognitionClient = new RekognitionClient({});

    const { CelebrityFaces, UnrecognizedFaces } = await rekognitionClient.send(
      new RecognizeCelebritiesCommand({
        Image: { Bytes: Buffer.from(imageBase64, "base64") },
      })
    );
    return {
      celebrityFaces: CelebrityFaces ? CelebrityFaces : [],
      unrecognizedFaces: UnrecognizedFaces ? UnrecognizedFaces : [],
    };
  } catch (error: any) {
    console.log(error);

    return new Error("Something went wrong");
  }
};

const main = async (event: any) =&amp;gt; {
  const response = await baseHandler(event);

  if (response instanceof Error) {
    return {
      headers: {
        "Access-Control-Allow-Origin": "*",
      },
      body: JSON.stringify({
        message: response.message,
      }),
      statusCode: 400,
    };
  }

  return {
    headers: {
      "Access-Control-Allow-Origin": "*",
    },
    body: JSON.stringify(response),
    statusCode: 200,
  };
};

module.exports = { main };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: "imageBase64" is the actual celebrities image that we will convert on the front-end to base64 and pass it in the request body.&lt;/p&gt;

&lt;p&gt;If the code above is too complex, here's what we are doing in short:&lt;/p&gt;

&lt;p&gt;1- We are parsing the request body using JSON.parse&lt;br&gt;
2- We validating that the body contains "imageBase64" property&lt;br&gt;
3- We are initializing the "RekognitionClient" Constructor&lt;br&gt;
4- We are passing the "imageBase64" to Rekognition service and awaiting a response&lt;br&gt;
4- We are destructuring the required data from the response&lt;br&gt;
5- In the main handler we are returning a 200 response if all is good - otherwise, we would return a 400 with the error message.&lt;/p&gt;

&lt;p&gt;The full back-end code can be found here: &lt;a href="https://github.com/AliZgheib/celebrities-face-recognition/tree/main/back-end" rel="noopener noreferrer"&gt;https://github.com/AliZgheib/celebrities-face-recognition/tree/main/back-end&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Phew!! I believe thats it for the back-end code.&lt;/p&gt;

&lt;p&gt;Now lets try to deploy our infrastructure/back-end to AWS by running the commands below:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;Now we deploy the code (follow the prompt - it should be pretty simple):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cdk deploy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After successfully deploying our API &amp;amp; Lambda, we should get the API URL in the output as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://XXX.execute-api.us-east-1.amazonaws.com/dev/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;"XXX" is your actual API ID (yours should be different)&lt;/p&gt;

&lt;p&gt;Based on the above, our API endpoint will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://XXX.execute-api.us-east-1.amazonaws.com/dev/rekognition
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That it for the backend!! Hope you made it through with me&lt;/p&gt;

&lt;p&gt;Now let's go back to our React application to finalize our application.&lt;/p&gt;

&lt;p&gt;In the same main page (or we can move it to a separate helper file for better files organization)&lt;/p&gt;

&lt;p&gt;We add the following helper function that will read the uploaded file and convert it to base64&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const convertFileToBase64 = async (file: any): Promise&amp;lt;any&amp;gt; =&amp;gt; {
  return new Promise((res, rej) =&amp;gt; {
    let reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = function () {
      res(reader.result);
    };
    reader.onerror = function (error) {
      console.log("Error: ", error);
      rej(error);
    };
  });
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we update the "handleSubmit" function that we previously left empty and add the necessary logic to call our POST /rekognition API endpoint:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  const handleSubmit = async (e: React.FormEvent&amp;lt;HTMLFormElement&amp;gt;) =&amp;gt; {
    try {
      e.preventDefault();

      if (!file) {
        return setError("Image not found.");
      }
      setError(null)
      setIsLoading(true);
      const fileBase64 = await convertFileToBase64(file);

      const fileNameClean = fileBase64.split("base64,")[1];

      const rawResponse = await fetch(
        "https://XXX.execute-api.us-east-1.amazonaws.com/dev/rekognition",
        {
          method: "POST",
          headers: {
            Accept: "application/json",
            "Content-Type": "application/json",
          },
          body: JSON.stringify({ imageBase64: fileNameClean }),
        }
      );
      const content = await rawResponse.json();

      setCelebtritiesData(content);
      setShowModal(true);
    } catch (error) {
      setError("Image is invalid or too large.");
    } finally {
      setIsLoading(false);
    }
  };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PS: make sure to replace &lt;code&gt;https://XXX.execute-api.us-east-1.amazonaws.com/dev/rekognition&lt;/code&gt; with your actual API endpoint&lt;/p&gt;

&lt;p&gt;And that should be it!! Now you can try out the application and you should get very similar results to what I show cased at the start.&lt;/p&gt;

&lt;p&gt;I hope you were able to follow along with me and that you enjoyed my article 😀&lt;/p&gt;

&lt;p&gt;If you would like to take the React application to the next level and host it on AWS (using S3 and CloudFront as a caching solution) - Checkout the article that I recently wrote: &lt;a href="https://dev.to/alizgheib/how-to-deploy-a-react-application-to-aws-using-aws-s3-aws-cloudfront-42km"&gt;https://dev.to/alizgheib/how-to-deploy-a-react-application-to-aws-using-aws-s3-aws-cloudfront-42km&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>react</category>
      <category>machinelearning</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
