<?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: Tien Nguyen Huynh</title>
    <description>The latest articles on DEV Community by Tien Nguyen Huynh (@hirdo).</description>
    <link>https://dev.to/hirdo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4080179%2Fca39c16a-9dfa-48c0-87c6-3ba67adc897f.png</url>
      <title>DEV Community: Tien Nguyen Huynh</title>
      <link>https://dev.to/hirdo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/hirdo"/>
    <language>en</language>
    <item>
      <title>Jenkins: Core Concepts and Declarative Pipelines for Modern Developers</title>
      <dc:creator>Tien Nguyen Huynh</dc:creator>
      <pubDate>Wed, 09 Sep 2026 22:28:38 +0000</pubDate>
      <link>https://dev.to/hirdo/jenkins-core-concepts-and-declarative-pipelines-for-modern-developers-2ch0</link>
      <guid>https://dev.to/hirdo/jenkins-core-concepts-and-declarative-pipelines-for-modern-developers-2ch0</guid>
      <description>&lt;p&gt;In the fast-evolving landscape of DevOps, Continuous Integration and Continuous Delivery (CI/CD) have transitioned from being "nice-to-have" to absolute necessities. While modern SaaS platforms like GitHub Actions, GitLab CI, and CircleCI have gained massive popularity, &lt;strong&gt;Jenkins&lt;/strong&gt; remains an undisputed heavyweight champion of the automation world. It powers the build and deployment pipelines of thousands of enterprises globally.&lt;/p&gt;

&lt;p&gt;However, many intermediate developers find Jenkins intimidating. It is often perceived as a legacy tool filled with convoluted UI menus, fragile configurations, and a confusing ecosystem of plugins. &lt;/p&gt;

&lt;p&gt;This guide is designed to change that. We will strip away the noise and focus on the fundamental concepts you need to master Jenkins, transitioning from GUI-based configurations to modern, maintainable &lt;strong&gt;Pipeline-as-Code&lt;/strong&gt; using Declarative Pipelines.&lt;/p&gt;




&lt;h2&gt;
  
  
  Understanding the Core Architecture
&lt;/h2&gt;

&lt;p&gt;Before writing a single line of configuration, it is crucial to understand how Jenkins operates under the hood. Jenkins follows a distributed, master-agent architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. The Controller (formerly Master)
&lt;/h3&gt;

&lt;p&gt;The Controller is the brain of your Jenkins installation. It is responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hosting the Web UI.&lt;/li&gt;
&lt;li&gt;Storing configuration details.&lt;/li&gt;
&lt;li&gt;Parsing and orchestrating the execution of jobs.&lt;/li&gt;
&lt;li&gt;Managing plugins and user authentication.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Crucial rule:&lt;/strong&gt; Do not run heavy build jobs on the Controller. Doing so risks running out of memory or CPU resources, which can take down your entire CI/CD infrastructure.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Agents (formerly Slaves / Workers)
&lt;/h3&gt;

&lt;p&gt;Agents are the workhorses. These are separate machines (virtual machines, bare metal, or Docker containers) that register with the Controller. The Controller delegates job executions to these agents.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Executors
&lt;/h3&gt;

&lt;p&gt;An Executor is a slot for execution of work on a node (Controller or Agent). Think of it as a thread. If an agent has 4 executors, it can run up to 4 build steps concurrently.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Paradigm Shift: Freestyle vs. Pipeline
&lt;/h2&gt;

&lt;p&gt;Historically, developers configured Jenkins using &lt;strong&gt;Freestyle Projects&lt;/strong&gt;. This involved clicking through a long web form, selecting checkboxes, and writing shell scripts in text areas inside the Jenkins UI.&lt;/p&gt;

&lt;p&gt;While easy to start with, Freestyle jobs have severe drawbacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No Version Control:&lt;/strong&gt; Changes to the build process are untracked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Code Review:&lt;/strong&gt; You cannot submit a Pull Request to change a build step.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hard to Replicate:&lt;/strong&gt; If your Jenkins server dies, recreating your complex jobs is a nightmare.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To solve this, Jenkins introduced &lt;strong&gt;Pipelines&lt;/strong&gt;. Pipelines treat your build workflow as code (usually saved as a &lt;code&gt;Jenkinsfile&lt;/code&gt; in your repository). This is the industry standard for modern Jenkins usage.&lt;/p&gt;




&lt;h2&gt;
  
  
  Declarative vs. Scripted Pipelines
&lt;/h2&gt;

&lt;p&gt;Jenkins offers two syntaxes for writing pipelines:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Scripted Pipelines:&lt;/strong&gt; Written in a Groovy-based DSL. Highly flexible, but requires deep knowledge of Groovy and is prone to spaghetti code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Declarative Pipelines:&lt;/strong&gt; A newer, structured schema. It provides a more predictable, opinionated syntax that is easier to read and write.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For 95% of use cases, &lt;strong&gt;Declarative Pipelines&lt;/strong&gt; are the recommended choice. Let's focus on them.&lt;/p&gt;




&lt;h2&gt;
  
  
  Anatomy of a Declarative Pipeline
&lt;/h2&gt;

&lt;p&gt;A Declarative Pipeline must follow a strict, structured block syntax. Here are the foundational blocks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt; &lt;span class="c1"&gt;// Where to run the pipeline&lt;/span&gt;

    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Build'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Commands to compile your code&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's break down the key directives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;pipeline&lt;/code&gt;&lt;/strong&gt;: The outer boundary of your configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;agent&lt;/code&gt;&lt;/strong&gt;: Instructs Jenkins where to run the pipeline. You can target specific labels, run inside a Docker container, or use &lt;code&gt;any&lt;/code&gt; to let Jenkins assign any available agent.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;stages&lt;/code&gt;&lt;/strong&gt;: A sequence of one or more conceptual steps (e.g., Build, Test, Deploy).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;stage&lt;/code&gt;&lt;/strong&gt;: A logical grouping of work. Each stage appears as a distinct column in the Jenkins visualization UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;code&gt;steps&lt;/code&gt;&lt;/strong&gt;: The actual execution block. This is where you run shell scripts, run tests, or call plugins.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Writing a Practical Jenkinsfile
&lt;/h2&gt;

&lt;p&gt;Let's write a realistic, production-ready &lt;code&gt;Jenkinsfile&lt;/code&gt; for a Node.js application. We will include a build phase, a testing phase with error handling, and post-execution cleanup.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;docker&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="s1"&gt;'node:18-alpine'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;APP_ENV&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'staging'&lt;/span&gt;
        &lt;span class="n"&gt;API_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'https://api.staging.example.com'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Install Dependencies'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Installing project dependencies...'&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s1"&gt;'npm ci'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Lint &amp;amp; Format'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Checking code style...'&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s1"&gt;'npm run lint'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Run Tests'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Running unit tests...'&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s1"&gt;'npm run test'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Build'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Building production assets...'&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s1"&gt;'npm run build'&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;post&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;always&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Cleaning up workspace...'&lt;/span&gt;
            &lt;span class="n"&gt;deleteDir&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// Clean up directory to keep agent clean&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;success&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Pipeline completed successfully!'&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;failure&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Pipeline failed. Sending notifications...'&lt;/span&gt;
            &lt;span class="c1"&gt;// Integrate with Slack, Email, or Discord here&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why this approach works:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Isolation (&lt;code&gt;agent { docker ... }&lt;/code&gt;):&lt;/strong&gt; Instead of installing Node.js globally on the Jenkins agent, Jenkins dynamically spins up a Docker container, runs the build steps inside it, and terminates it when finished. This ensures pristine build environments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clean Execution Environment (&lt;code&gt;post { always { deleteDir() } }&lt;/code&gt;):&lt;/strong&gt; Prevents disk space issues on the Jenkins agent by cleaning up files after the run completes, whether it succeeded or failed.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Handling Credentials Safely
&lt;/h2&gt;

&lt;p&gt;Hardcoding API keys, SSH keys, or passwords in your &lt;code&gt;Jenkinsfile&lt;/code&gt; is a major security vulnerability. Jenkins provides a built-in &lt;strong&gt;Credentials Provider&lt;/strong&gt; to store secrets securely.&lt;/p&gt;

&lt;p&gt;To use credentials inside your Declarative Pipeline, use the &lt;code&gt;credentials()&lt;/code&gt; helper method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight groovy"&gt;&lt;code&gt;&lt;span class="n"&gt;pipeline&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;
    &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Fetch credentials stored with ID 'my-db-password' in Jenkins GUI&lt;/span&gt;
        &lt;span class="n"&gt;DB_PASSWORD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;credentials&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'my-db-password'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;stages&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Database Migration'&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// The secret is automatically masked as **** in the console output&lt;/span&gt;
                &lt;span class="n"&gt;sh&lt;/span&gt; &lt;span class="s2"&gt;"echo \"Connecting with password: $DB_PASSWORD\""&lt;/span&gt;
            &lt;span class="o"&gt;}&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: Jenkins automatically filters console output to mask secrets with `&lt;/em&gt;**&lt;em&gt;` if they are printed by accident.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Jenkins Best Practices for Developers
&lt;/h2&gt;

&lt;p&gt;As you begin configuring your own pipelines, keep these architectural best practices in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Keep Jenkinsfiles in Source Control:&lt;/strong&gt; Treat your pipelines exactly like your source code. Code-review them via pull requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Ephemeral Agents:&lt;/strong&gt; Avoid running builds on raw servers where historical artifacts can cause "it worked on my machine" issues. Utilize Docker-based agents or Kubernetes pods.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Minimize Console Output:&lt;/strong&gt; Do not output enormous log files to the console, as this can degrade Jenkins performance and clog memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Leverage Shared Libraries:&lt;/strong&gt; If you find yourself copying and pasting the exact same logic across 10 different &lt;code&gt;Jenkinsfiles&lt;/code&gt;, extract that logic into a &lt;strong&gt;Jenkins Shared Library&lt;/strong&gt; written in Groovy. This allows you to centralize pipeline logic and keep individual repository pipelines slim.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;Jenkins doesn't have to be a dark art. By ignoring legacy UI-based configurations and dedicating yourself to &lt;strong&gt;Declarative Pipelines&lt;/strong&gt;, you can build reliable, secure, and scalable CI/CD pipelines as part of your application development lifecycle.&lt;/p&gt;

&lt;p&gt;Start small: convert one of your existing project builds into a basic 3-stage &lt;code&gt;Jenkinsfile&lt;/code&gt;, test it locally using a Docker-based Jenkins container, and gradually build up to complex multi-stage deployments. Happy building!&lt;/p&gt;

</description>
      <category>jenkins</category>
      <category>cicd</category>
      <category>devops</category>
      <category>automation</category>
    </item>
    <item>
      <title>Beyond the Static: The Ultimate Guide to Serverless Website Deployment Platforms</title>
      <dc:creator>Tien Nguyen Huynh</dc:creator>
      <pubDate>Thu, 03 Sep 2026 10:58:19 +0000</pubDate>
      <link>https://dev.to/hirdo/beyond-the-static-the-ultimate-guide-to-serverless-website-deployment-platforms-286f</link>
      <guid>https://dev.to/hirdo/beyond-the-static-the-ultimate-guide-to-serverless-website-deployment-platforms-286f</guid>
      <description>&lt;p&gt;Remember when deploying a website meant setting up an Apache server, configuring FTP credentials, and hoping your database didn't crash overnight? &lt;/p&gt;

&lt;p&gt;Today, the landscape is entirely different. We build modern, highly dynamic web applications using frameworks like Next.js, Nuxt, Remix, and SvelteKit. To host these frameworks efficiently, we rely on &lt;strong&gt;serverless architecture&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;In a serverless paradigm, you don't manage virtual machines or container orchestration. Instead, your frontend assets are distributed globally via CDNs, and your dynamic backend logic runs inside ephemeral, auto-scaling environments (like Cloudflare Workers, AWS Lambda, or Vercel Functions). &lt;/p&gt;

&lt;p&gt;But with so many platforms vying for your attention, how do you choose the right one? In this guide, we will break down the top serverless deployment platforms, categorized by their strengths, developer experience (DX), and underlying architecture.&lt;/p&gt;




&lt;h2&gt;
  
  
  Category 1: The Developer Experience Champions (Frontend-First)
&lt;/h2&gt;

&lt;p&gt;These platforms are optimized for frontend developers who want zero-configuration deployments, seamless Git integration, and instant preview environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Vercel
&lt;/h3&gt;

&lt;p&gt;As the creators of Next.js, Vercel is the gold standard for developer experience. It is designed to deploy frontend frameworks with virtually no configuration.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Vercel automatically detects your framework, configures the build steps, splits your API routes into serverless/edge functions, and serves static assets from their global Edge Network.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Features:&lt;/strong&gt; Instant git-push deployments, collaborative preview deployments with visual comments, and built-in analytics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Runtimes:&lt;/strong&gt; Supports both Node.js Serverless Functions (AWS Lambda under the hood) and V8-based Edge Functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Code Example: A simple Vercel API Route (Next.js App Router)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// app/api/hello/route.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;runtime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;edge&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Run this on Vercel's global edge network&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;GET&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello from Vercel Edge!&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;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Content-Type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best For:&lt;/strong&gt; Next.js projects, teams prioritizing fast iteration/collaboration, and Jamstack sites requiring minimal backend configuration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Netlify
&lt;/h3&gt;

&lt;p&gt;Netlify pioneered the "Jamstack" movement and remains one of the strongest alternatives to Vercel. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Similar to Vercel, Netlify connects to your Git provider, builds your project, and deploys it to its custom "Application Delivery Network."&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Features:&lt;/strong&gt; Netlify Forms (automatic form handling without a backend), Netlify Identity (user authentication), and Background Functions (for long-running async tasks up to 15 minutes).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best For:&lt;/strong&gt; Nuxt, Astro, and SvelteKit applications, or teams looking for out-of-the-box form and identity management.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Category 2: The Edge Powerhouses (Performance &amp;amp; Cost-Efficiency)
&lt;/h2&gt;

&lt;p&gt;If you want the absolute fastest global response times and zero cold starts at a fraction of the cost, edge-first platforms are your answer.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Cloudflare Pages &amp;amp; Workers
&lt;/h3&gt;

&lt;p&gt;Cloudflare is built differently. Instead of relying on traditional AWS Lambda-style virtual containers, Cloudflare runs code on V8 Isolates across their massive global network of 300+ data centers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;How it works:&lt;/strong&gt; Cloudflare Pages handles static asset hosting, while Cloudflare Workers handle dynamic logic. They integrate seamlessly, letting you deploy full-stack applications (like Remix or SvelteKit) entirely at the edge.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Features:&lt;/strong&gt; Virtually zero cold starts, incredibly generous free tier (100k requests/day for Workers), and native integrations with edge-native storage like KV (Key-Value), D1 (SQL Database), and R2 (Object Storage).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Code Example: Cloudflare Pages Function
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// functions/api/greet.js&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;onRequest&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="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello from Cloudflare Edge!&lt;/span&gt;&lt;span class="dl"&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;new&lt;/span&gt; &lt;span class="nc"&gt;Response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;content-type&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Unmatched global latency, highly cost-efficient, immune to standard serverless cold starts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; V8 isolate environment has limitations. You cannot run arbitrary Node.js binaries or libraries that rely heavily on native C++ extensions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best For:&lt;/strong&gt; High-traffic applications, real-time APIs, globally distributed users, and cost-conscious side projects.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Category 3: The Infrastructure Heavyweights (Maximum Control)
&lt;/h2&gt;

&lt;p&gt;For enterprise systems or applications requiring deep integrations with databases, queues, and container services, deploying directly to raw cloud infrastructure is often necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. AWS (Amplify &amp;amp; SST)
&lt;/h3&gt;

&lt;p&gt;While raw AWS Lambda can be daunting to configure manually, modern tools have bridged the developer experience gap.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Amplify:&lt;/strong&gt; AWS’s managed hosting service for frontend frameworks. It provides hosting, authentication, and database generation with a Git-based workflow similar to Vercel.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SST (Serverless Stack):&lt;/strong&gt; An open-source framework that lets you deploy modern full-stack apps directly to your own AWS account using AWS CDK. It compiles SvelteKit, Next.js, or Astro apps into pure AWS infrastructure (S3, CloudFront, Lambda, API Gateway).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Code Example: SST Configuration (sst.config.ts)
&lt;/h4&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;SSTConfig&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;sst&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NextjsSite&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;sst/constructs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_input&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-serverless-app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;us-east-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nf"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;stack&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;NextjsSite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addOutputs&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="na"&gt;SiteUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;site&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;satisfies&lt;/span&gt; &lt;span class="nx"&gt;SSTConfig&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Complete ownership of your cloud infrastructure, zero markup on AWS billing, access to the entire AWS catalog (SQS, EventBridge, RDS).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Steeper learning curve, complex IAM configuration, and potential cost surprises if your security controls aren't configured properly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best For:&lt;/strong&gt; Mid-to-large-scale companies already using AWS, projects requiring long-running backend background jobs, and heavy database-driven applications.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Category 4: The Backend-as-a-Service (BaaS) Ecosystems
&lt;/h2&gt;

&lt;p&gt;If your serverless website is deeply integrated with real-time data or user authentications, hosting with a BaaS provider can simplify your architecture.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Firebase Hosting + Cloud Functions
&lt;/h3&gt;

&lt;p&gt;Google's Firebase is a veteran in the serverless space. It integrates static web hosting with serverless functions and a real-time NoSQL database (Firestore).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Excellent SDKs for mobile and web, real-time listeners out of the box, robust local emulator suite.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cons:&lt;/strong&gt; Hard vendor lock-in to Google Cloud Platform; Firestore querying can feel restrictive.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  6. Supabase (Self-hosted or Cloud)
&lt;/h3&gt;

&lt;p&gt;Often called the open-source Firebase alternative, Supabase provides hosting for Edge Functions alongside a fully-featured Postgres database.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pros:&lt;/strong&gt; Real Postgres database (not NoSQL), built-in Row-Level Security (RLS), instant REST/GraphQL APIs generated from your database schema.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best For:&lt;/strong&gt; Database-heavy applications that need relational integrity, real-time subscriptions, and fast serverless edge functions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Choosing the Right Platform: The Decision Matrix
&lt;/h2&gt;

&lt;p&gt;To help you decide, here is a quick reference table based on your project priorities:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Primary Strength&lt;/th&gt;
&lt;th&gt;Ideal Use Case&lt;/th&gt;
&lt;th&gt;Cost at Scale&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Vercel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Developer Experience &amp;amp; Next.js integration&lt;/td&gt;
&lt;td&gt;Corporate websites, SaaS frontends, Next.js apps&lt;/td&gt;
&lt;td&gt;Moderate to High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Netlify&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Jamstack features (Forms, Identity)&lt;/td&gt;
&lt;td&gt;Content sites, multi-framework apps&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cloudflare Pages&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Cost, raw speed, global distribution&lt;/td&gt;
&lt;td&gt;Real-time APIs, high-traffic tools, microservices&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS / SST&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Architecture control, ownership&lt;/td&gt;
&lt;td&gt;Enterprise apps, high-volume production systems&lt;/td&gt;
&lt;td&gt;Very Low (Raw AWS cost)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Supabase / Firebase&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Integrated real-time database &amp;amp; Auth&lt;/td&gt;
&lt;td&gt;Dynamic CRUD apps, dashboards, mobile-web hybrids&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;There has never been a better time to build serverless websites. If you want the fastest route to production with high collaborative velocity, &lt;strong&gt;Vercel&lt;/strong&gt; remains the king. If you want ultra-low latencies and to minimize your hosting bill, &lt;strong&gt;Cloudflare Pages &amp;amp; Workers&lt;/strong&gt; are unbeatable.&lt;/p&gt;

&lt;p&gt;For those who need the reliability, scalability, and safety of owning their own AWS cloud without the complexity, &lt;strong&gt;SST&lt;/strong&gt; is the future of full-stack serverless deployment.&lt;/p&gt;

&lt;p&gt;What is your go-to platform for serverless hosting? Let me know in the comments below!&lt;/p&gt;

</description>
      <category>serverless</category>
      <category>webdev</category>
      <category>cloud</category>
      <category>devops</category>
    </item>
    <item>
      <title>Why Developers Should Use Bitwarden for Credential Management</title>
      <dc:creator>Tien Nguyen Huynh</dc:creator>
      <pubDate>Mon, 31 Aug 2026 09:30:58 +0000</pubDate>
      <link>https://dev.to/hirdo/why-developers-should-use-bitwarden-for-credential-management-96f</link>
      <guid>https://dev.to/hirdo/why-developers-should-use-bitwarden-for-credential-management-96f</guid>
      <description>&lt;h2&gt;
  
  
  Introduction: The Developer's Credential Dilemma
&lt;/h2&gt;

&lt;p&gt;As developers, we manage dozens—if not hundreds—of sensitive credentials daily. From database connection strings and SSH keys to API tokens and third-party service logins, keeping track of these secrets securely without destroying developer velocity is a constant challenge.&lt;/p&gt;

&lt;p&gt;Far too often, developers fall into bad habits: reusing simple passwords, storing raw API keys in unencrypted &lt;code&gt;.env&lt;/code&gt; files committed to Git, or sharing production tokens over Slack. These practices are major security risks.&lt;/p&gt;

&lt;p&gt;While there are many password managers on the market, &lt;strong&gt;Bitwarden&lt;/strong&gt; has rapidly become the preferred choice for software engineers and DevOps teams. In this article, we will explore why Bitwarden is uniquely suited for developers, examine its developer-centric feature set, and walk through practical CLI examples.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. True Open-Source Transparency
&lt;/h2&gt;

&lt;p&gt;For security software, trust is paramount. Closed-source proprietary password managers force you to trust the vendor's claims without verification. Bitwarden flips this model on its head.&lt;/p&gt;

&lt;p&gt;The entire Bitwarden codebase—including web vaults, mobile applications, desktop clients, browser extensions, and backend infrastructure—is 100% open source under GPLv3 and AGPLv3 licenses. You can inspect the source code directly on GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Open Source Matters for Security:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public Auditing:&lt;/strong&gt; Security researchers and the global developer community continuously audit the code for vulnerabilities.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Hidden Backdoors:&lt;/strong&gt; Transparency ensures there are no intentional backdoors or tracking mechanisms.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Longevity:&lt;/strong&gt; Even if the company behind Bitwarden were to disappear, the software and server implementations could be maintained by the community.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Developer-First Workflows: The Bitwarden CLI (&lt;code&gt;bw&lt;/code&gt;)
&lt;/h2&gt;

&lt;p&gt;Most password managers focus exclusively on GUI interfaces designed for non-technical users. Bitwarden provides a full-featured Command Line Interface (CLI) that allows developers to interact with their vault directly from the terminal or automate tasks within shell scripts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installing the Bitwarden CLI
&lt;/h3&gt;

&lt;p&gt;You can install &lt;code&gt;bw&lt;/code&gt; via NPM, Homebrew, or direct binary downloads:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Via NPM&lt;/span&gt;
npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; @bitwarden/cli

&lt;span class="c"&gt;# Via Homebrew (macOS)&lt;/span&gt;
brew &lt;span class="nb"&gt;install &lt;/span&gt;bitwarden-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Practical CLI Usage
&lt;/h3&gt;

&lt;p&gt;Once installed, you can authenticate and unlock your vault dynamically in scripts without exposing plain-text master passwords.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Log in to your Bitwarden account&lt;/span&gt;
bw login

&lt;span class="c"&gt;# 2. Unlock your vault to get a session key&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;BW_SESSION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;bw unlock &lt;span class="nt"&gt;--raw&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# 3. Search for items in JSON format using jq&lt;/span&gt;
bw list items &lt;span class="nt"&gt;--search&lt;/span&gt; &lt;span class="s2"&gt;"Stripe API"&lt;/span&gt; | jq &lt;span class="s1"&gt;'.[0].fields[] | select(.name=="Secret Key").value'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By leveraging the &lt;code&gt;bw&lt;/code&gt; CLI, you can inject secret values directly into application environments during local execution or automated testing, eliminating the need to store static secrets on your local disk.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. End-to-End Encryption Architecture
&lt;/h2&gt;

&lt;p&gt;Bitwarden uses zero-knowledge, end-to-end encryption. All vault data is encrypted on your local device &lt;em&gt;before&lt;/em&gt; it is ever transmitted to synchronization servers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Cryptographic Details:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Symmetric Encryption:&lt;/strong&gt; Vault items are encrypted using &lt;strong&gt;AES-CBC 256-bit&lt;/strong&gt; encryption.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key Derivation:&lt;/strong&gt; Master key generation uses &lt;strong&gt;PBKDF2 SHA-256&lt;/strong&gt; (with configurable iteration counts) or &lt;strong&gt;Argon2id&lt;/strong&gt; (the state-of-the-art memory-hard key derivation function).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-Knowledge Architecture:&lt;/strong&gt; Bitwarden employees cannot read your vault data, reset your master password, or access your decrypted items. Encryption keys are derived entirely from your master password and stored in memory only when unlocked.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Self-Hosting Capabilities
&lt;/h2&gt;

&lt;p&gt;Many organizations operate under strict compliance constraints (such as HIPAA, SOC2, or GDPR) or simply prefer to keep infrastructure internal. Bitwarden officially supports self-hosted deployments using Docker containers.&lt;/p&gt;

&lt;p&gt;For individual developers or light-resource homelabs, there is also &lt;strong&gt;Vaultwarden&lt;/strong&gt;, an alternative backend written in Rust that is fully compatible with official Bitwarden clients while using minimal RAM.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker Compose Example for Official Deployment
&lt;/h3&gt;

&lt;p&gt;Bitwarden provides a streamlined installation script for Docker environments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Download the installation script&lt;/span&gt;
curl &lt;span class="nt"&gt;-sH&lt;/span&gt; &lt;span class="s1"&gt;'Cache-Control: no-cache'&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; bitwarden.sh https://raw.githubusercontent.com/bitwarden/self-host/main/bitwarden.sh

&lt;span class="c"&gt;# Make script executable and run&lt;/span&gt;
&lt;span class="nb"&gt;chmod&lt;/span&gt; +x bitwarden.sh
./bitwarden.sh &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Self-hosting gives you complete control over your database, backups, network firewalls, and audit logs.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Bitwarden Secrets Manager for CI/CD Pipelines
&lt;/h2&gt;

&lt;p&gt;Beyond basic user password management, Bitwarden offers &lt;strong&gt;Bitwarden Secrets Manager&lt;/strong&gt;, tailored specifically for DevOps engineers and software development teams.&lt;/p&gt;

&lt;p&gt;Secrets Manager centralizes infrastructure secrets, environment variables, and API tokens across multi-cloud infrastructure and CI/CD tools (like GitHub Actions, GitLab CI, and Kubernetes).&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Advantages over Standalone Key-Value Stores:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Unified Access Control:&lt;/strong&gt; Manage developer personal access logins and infrastructure machine tokens from a centralized administrative control plane.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native Integrations:&lt;/strong&gt; First-party SDKs available for Node.js, Python, Go, and Rust.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secret Rotation &amp;amp; Auditing:&lt;/strong&gt; Complete history of who accessed or modified environment keys.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Example using Bitwarden Secrets Manager Python SDK
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bitwarden_sdk&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;BitwardenClient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;DeviceType&lt;/span&gt;

&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BitwardenClient&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;login_access_token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;access_token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;secrets&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;00000000-0000-0000-0000-000000000000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Retrieved DB Secret: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion: Elevate Your Security Posture
&lt;/h2&gt;

&lt;p&gt;Managing credentials shouldn't be an afterthought or a friction point in your development pipeline. Bitwarden strikes an optimal balance between top-tier security, developer accessibility, and open-source flexibility.&lt;/p&gt;

&lt;p&gt;Whether you are looking for a personal password manager with CLI capabilities, self-hosting a vault for your team, or managing infrastructure secrets in production, Bitwarden provides a modern ecosystem designed for engineering needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Next Steps:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Sign up for a free account or spin up a self-hosted instance.&lt;/li&gt;
&lt;li&gt;Install the &lt;code&gt;bw&lt;/code&gt; CLI tool and experiment with scripting credential retrievals.&lt;/li&gt;
&lt;li&gt;Migrate away from plain-text credentials in &lt;code&gt;.env&lt;/code&gt; files once and for all!&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>security</category>
      <category>devops</category>
      <category>productivity</category>
      <category>tools</category>
    </item>
    <item>
      <title>Under the Hood: 5 JavaScript Fundamentals Every Intermediate Dev Should Master</title>
      <dc:creator>Tien Nguyen Huynh</dc:creator>
      <pubDate>Mon, 31 Aug 2026 04:15:21 +0000</pubDate>
      <link>https://dev.to/hirdo/under-the-hood-5-javascript-fundamentals-every-intermediate-dev-should-master-3bic</link>
      <guid>https://dev.to/hirdo/under-the-hood-5-javascript-fundamentals-every-intermediate-dev-should-master-3bic</guid>
      <description>&lt;p&gt;We’ve all been there: you can build full-stack web applications, write React components with ease, or deploy Node.js microservices, yet every now and then, a subtle JavaScript bug leaves you scratching your head for hours. &lt;/p&gt;

&lt;p&gt;Often, these bugs stem not from complex framework intricacies, but from a shaky understanding of &lt;strong&gt;core JavaScript fundamentals&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;In this article, we'll strip away the abstractions and look under the hood at five fundamental concepts that every intermediate JavaScript developer should deeply understand.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Execution Context and the Temporal Dead Zone
&lt;/h2&gt;

&lt;p&gt;Before any JavaScript code runs, the JavaScript engine creates an &lt;strong&gt;Execution Context&lt;/strong&gt;. Think of it as an environment that manages the code currently being evaluated.&lt;/p&gt;

&lt;p&gt;An Execution Context consists of two phases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Creation Phase&lt;/strong&gt;: The engine allocates memory for variables and functions (Hoisting).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Execution Phase&lt;/strong&gt;: The engine executes the code line-by-line.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Hoisting: &lt;code&gt;var&lt;/code&gt; vs. &lt;code&gt;let&lt;/code&gt; / &lt;code&gt;const&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Many developers believe &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; aren't hoisted. They actually are, but they behave differently due to the &lt;strong&gt;Temporal Dead Zone (TDZ)&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: undefined (hoisted &amp;amp; initialized to undefined)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// ReferenceError: Cannot access 'b' before initialization&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;var&lt;/code&gt; is hoisted, memory is allocated and immediately initialized with &lt;code&gt;undefined&lt;/code&gt;. When &lt;code&gt;let&lt;/code&gt; and &lt;code&gt;const&lt;/code&gt; are hoisted, memory is allocated, but they remain &lt;strong&gt;uninitialized&lt;/strong&gt;. The time between entering the scope and reaching the variable declaration is the Temporal Dead Zone.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Demystifying &lt;code&gt;this&lt;/code&gt; Once and For All
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;this&lt;/code&gt; keyword is notoriously confusing because its value is determined &lt;strong&gt;how a function is called&lt;/strong&gt;, not where it is defined (with the exception of arrow functions).&lt;/p&gt;

&lt;p&gt;Here are the 4 primary rules of &lt;code&gt;this&lt;/code&gt; binding:&lt;/p&gt;

&lt;h3&gt;
  
  
  Implicit Binding
&lt;/h3&gt;

&lt;p&gt;When a function is called as a method of an object, &lt;code&gt;this&lt;/code&gt; points to that object.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Alex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hello, I am &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Hello, I am Alex&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Explicit Binding
&lt;/h3&gt;

&lt;p&gt;Using &lt;code&gt;.call()&lt;/code&gt;, &lt;code&gt;.apply()&lt;/code&gt;, or &lt;code&gt;.bind()&lt;/code&gt;, you explicitly define what &lt;code&gt;this&lt;/code&gt; refers to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;showRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; is a &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;role&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Sarah&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;showRole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Frontend Engineer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Output: Sarah is a Frontend Engineer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Arrow Functions
&lt;/h3&gt;

&lt;p&gt;Arrow functions do &lt;strong&gt;not&lt;/strong&gt; have their own &lt;code&gt;this&lt;/code&gt;. They lexically bind &lt;code&gt;this&lt;/code&gt;, inheriting it from the surrounding outer scope.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&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;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setInterval&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seconds&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Works as expected because arrow function inherits 'this' from start()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Closures: Power, Memory, and Encapsulation
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;closure&lt;/strong&gt; is created when a function is defined inside another function, allowing the inner function to retain access to variables in the outer function's lexical scope—even after the outer function has finished executing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Practical Use Case: Data Encapsulation
&lt;/h3&gt;

&lt;p&gt;JavaScript didn't always have private class fields (&lt;code&gt;#private&lt;/code&gt;). Closures provided a way to create private variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;createCounter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Private state&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&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;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;decrement&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="o"&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;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nf"&gt;getCount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCounter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 1&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt; &lt;span class="c1"&gt;// 2&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// undefined (cannot be accessed directly!)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Watch Out for Memory Leaks
&lt;/h3&gt;

&lt;p&gt;Because closure variables are retained in memory as long as the inner function is reachable, holding references unnecessarily can prevent Garbage Collection and cause memory leaks.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Event Loop: Microtasks vs. Macrotasks
&lt;/h2&gt;

&lt;p&gt;JavaScript is single-threaded, meaning it can only perform one task at a time. Concurrency is handled by the &lt;strong&gt;Event Loop&lt;/strong&gt;, which coordinates the Call Stack, Microtask Queue, and Macrotask (Callback) Queue.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Order of Execution
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Execute all synchronous code on the &lt;strong&gt;Call Stack&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;When the Call Stack is empty, execute &lt;strong&gt;all&lt;/strong&gt; tasks in the &lt;strong&gt;Microtask Queue&lt;/strong&gt; (Promises, &lt;code&gt;queueMicrotask&lt;/code&gt;, &lt;code&gt;MutationObserver&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Execute &lt;strong&gt;one&lt;/strong&gt; task from the &lt;strong&gt;Macrotask Queue&lt;/strong&gt; (&lt;code&gt;setTimeout&lt;/code&gt;, &lt;code&gt;setInterval&lt;/code&gt;, I/O, UI rendering).&lt;/li&gt;
&lt;li&gt;Repeat.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Consider this classic interview question:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1: Sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2: Macrotask (setTimeout)&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="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;3: Microtask (Promise)&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;4: Sync&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output:&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;1: Sync
4: Sync
3: Microtask (Promise)
2: Macrotask (setTimeout)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even with a delay of &lt;code&gt;0ms&lt;/code&gt;, &lt;code&gt;setTimeout&lt;/code&gt; must wait for the Microtask Queue to completely clear before it gets pushed onto the Call Stack.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Prototypal Inheritance Beyond &lt;code&gt;class&lt;/code&gt; Syntax
&lt;/h2&gt;

&lt;p&gt;ES6 introduced the &lt;code&gt;class&lt;/code&gt; keyword, making JavaScript look like classic object-oriented languages. However, under the hood, JavaScript still uses &lt;strong&gt;prototypal inheritance&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every object in JavaScript has a internal link to another object called its &lt;strong&gt;prototype&lt;/strong&gt; (&lt;code&gt;[[Prototype]]&lt;/code&gt;). When you attempt to access a property on an object, JavaScript searches the object itself first, then traverses up the prototype chain until it finds it or reaches &lt;code&gt;null&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sayHi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Hi, my name is &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dev&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Maya&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sayHi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Output: Hi, my name is Maya&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;__proto__&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Understanding this mechanic is critical when extending built-in objects, writing high-performance code, or working with legacy codebases.&lt;/p&gt;




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

&lt;p&gt;Frameworks come and go, but core JavaScript mechanics remain constant. Mastering execution contexts, scoping rules, &lt;code&gt;this&lt;/code&gt; binding, closures, the event loop, and prototypes will make you a far better troubleshooter and architect.&lt;/p&gt;

&lt;p&gt;The next time you encounter an unexpected value or asynchronous bug, take a step back and think about what the engine is doing behind the scenes!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Shift Left: Why Security Mindset is a Non-Negotiable Developer Skill</title>
      <dc:creator>Tien Nguyen Huynh</dc:creator>
      <pubDate>Mon, 31 Aug 2026 04:15:04 +0000</pubDate>
      <link>https://dev.to/hirdo/shift-left-why-security-mindset-is-a-non-negotiable-developer-skill-4m09</link>
      <guid>https://dev.to/hirdo/shift-left-why-security-mindset-is-a-non-negotiable-developer-skill-4m09</guid>
      <description>&lt;p&gt;For a long time, software development followed a predictable pipeline: developers wrote code, pushed features, and handed the application over to the Security or SecOps team right before release. If security issues were found, tickets were created, deadlines were pushed, and frustrations flared.&lt;/p&gt;

&lt;p&gt;Today, that model is dead. With continuous integration and rapid deployment pipelines, waiting until the end of the release cycle to address security is like building a house, painting it, and only then checking if the foundation is made of sand.&lt;/p&gt;

&lt;p&gt;Security is no longer just a specialized role—it is a core software engineering skill. Here is why having security knowledge makes you a significantly better developer and how it changes the way you write code.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Catching Vulnerabilities Early is Cheaper and Faster
&lt;/h2&gt;

&lt;p&gt;The "Shift Left" philosophy isn't just industry jargon; it's basic economics. According to the Systems Sciences Institute at IBM, fixing a security bug in production costs &lt;strong&gt;up to 30 times more&lt;/strong&gt; than fixing it during the design or development phase.&lt;/p&gt;

&lt;p&gt;When you understand basic attack vectors while writing code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You write secure code on the first pass.&lt;/li&gt;
&lt;li&gt;You avoid long code-review friction cycles.&lt;/li&gt;
&lt;li&gt;You protect your application from costly data breaches and downtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. You Are the First Line of Defense
&lt;/h2&gt;

&lt;p&gt;Automated tools (SAST, DAST, dependency scanners) are great, but they are far from perfect. They miss context-specific business logic flaws that human attackers excel at exploiting.&lt;/p&gt;

&lt;p&gt;Consider a common vulnerability like &lt;strong&gt;Insecure Direct Object Reference (IDOR)&lt;/strong&gt;. An automated scanner won't know if User A should have access to User B's invoices—only you, the developer who understands the domain logic, can enforce proper authorization checks.&lt;/p&gt;

&lt;p&gt;Let's look at how code evolves when a developer understands security context.&lt;/p&gt;

&lt;h3&gt;
  
  
  Bad Example: Insecure API Endpoint
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Vulnerable Express.js route&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/documents/: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="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// IDOR Vulnerability: Fetching document directly by ID without checking ownership&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;documents&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&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="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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Document not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Good Example: Authorization Enforced
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Secure Express.js route with authorization check&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/documents/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authenticateUser&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;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nb"&gt;document&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;collection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;documents&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;findOne&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&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="na"&gt;ownerId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="c1"&gt;// Ensures user can only access their own document&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="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Use 404 or 403 to prevent resource enumeration&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Document not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  3. SQL Injection is Still Alive Today
&lt;/h2&gt;

&lt;p&gt;Despite decades of warnings, flaws like SQL Injection (SQLi) and Cross-Site Scripting (XSS) consistently rank high on the &lt;strong&gt;OWASP Top 10&lt;/strong&gt;. Why? Because developers often rely on string concatenation when building queries under pressure.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vulnerable Python SQL Query
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Vulnerable to SQL Injection
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE username = &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;'"&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# If username is: admin' --
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Secure Parameterized Query
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Secure using parameterized queries
&lt;/span&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_user_profile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;query&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT * FROM users WHERE username = %s&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetchone&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Understanding how parameterized queries work under the hood separates amateur developers from software engineers who build resilient systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Third-Party Dependencies Are a Massive Attack Vector
&lt;/h2&gt;

&lt;p&gt;Modern software engineering is largely about composing open-source packages. While npm, PyPI, and Crates.io accelerate development, they also introduce supply chain risks.&lt;/p&gt;

&lt;p&gt;A developer with security awareness doesn't just &lt;code&gt;npm install&lt;/code&gt; blindly. They understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dependency Auditing&lt;/strong&gt;: Regularly running &lt;code&gt;npm audit&lt;/code&gt; or using tools like Snyk and Dependabot.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Typosquatting &amp;amp; Malicious Packages&lt;/strong&gt;: Verifying package names, maintainer reputation, and release history.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pinning Dependency Versions&lt;/strong&gt;: Preventing unexpected code updates from pulling compromised releases into production builds.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Security Knowledge Elevates Your Career
&lt;/h2&gt;

&lt;p&gt;Senior developers aren't defined by how quickly they write code; they are defined by their ability to design system architectures that are reliable, scalable, and &lt;strong&gt;secure&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When you demonstrate security awareness during code reviews, system design interviews, and architectural discussions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;You gain trust from engineering leadership.&lt;/li&gt;
&lt;li&gt;You reduce technical debt and compliance headaches (GDPR, SOC2, HIPAA).&lt;/li&gt;
&lt;li&gt;You stand out as a well-rounded engineer capable of taking end-to-end responsibility.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Essential Security Habits to Start Today
&lt;/h2&gt;

&lt;p&gt;You don't need a degree in cybersecurity to write secure software. Incorporate these four habits into your daily workflow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Never Trust User Input&lt;/strong&gt;: Sanitize and validate every piece of data coming from query parameters, request bodies, headers, and external APIs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Practice the Principle of Least Privilege&lt;/strong&gt;: Ensure services, database credentials, and API keys only have the minimum permissions necessary to function.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automate Static Analysis&lt;/strong&gt;: Add linters with security rules (e.g., &lt;code&gt;eslint-plugin-security&lt;/code&gt;) to your local setup and CI/CD pipelines.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep Secrets Out of Code&lt;/strong&gt;: Store API keys and database URIs in environment variables and secret management vaults—never commit them to Git.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Writing code that works is only half the job. Writing code that continues to work securely in an untrusted environment is what true software craftsmanship is all about.&lt;/p&gt;

&lt;p&gt;By taking the time to understand common security vulnerabilities and adopting defensive coding practices, you protect your users, save your organization from devastating security incidents, and elevate your career as an engineer.&lt;/p&gt;

&lt;p&gt;What security practices do you implement in your daily workflow? Share your tips in the comments below!&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>programming</category>
      <category>devops</category>
    </item>
    <item>
      <title>Mastering Keycloak: Essential Concepts Every Developer Should Know for Application Security</title>
      <dc:creator>Tien Nguyen Huynh</dc:creator>
      <pubDate>Mon, 31 Aug 2026 04:14:53 +0000</pubDate>
      <link>https://dev.to/hirdo/mastering-keycloak-essential-concepts-every-developer-should-know-for-application-security-1idc</link>
      <guid>https://dev.to/hirdo/mastering-keycloak-essential-concepts-every-developer-should-know-for-application-security-1idc</guid>
      <description>&lt;p&gt;Managing authentication and authorization in modern web applications can quickly become a maintenance nightmare. Between handling password resets, multi-factor authentication (MFA), social logins, and role-based access control (RBAC), building an in-house solution consumes valuable time that could be spent on core business logic.&lt;/p&gt;

&lt;p&gt;Enter &lt;strong&gt;Keycloak&lt;/strong&gt;: an open-source Identity and Access Management (IAM) solution maintained by Red Hat. Keycloak acts as a centralized authentication server that supports industry standards like &lt;strong&gt;OAuth 2.0&lt;/strong&gt;, &lt;strong&gt;OpenID Connect (OIDC)&lt;/strong&gt;, and &lt;strong&gt;SAML 2.0&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Whether you are building a microservices architecture or a single-page application (SPA), understanding Keycloak's foundation is crucial. In this guide, we will break down the essential Keycloak concepts and look at how to integrate it into your application workflow.&lt;/p&gt;




&lt;h2&gt;
  
  
  Core Concepts: Demystifying Keycloak Terminology
&lt;/h2&gt;

&lt;p&gt;To work effectively with Keycloak, you need to understand its core building blocks. Let's look at how Keycloak organizes users, permissions, and applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Realms
&lt;/h3&gt;

&lt;p&gt;A &lt;strong&gt;Realm&lt;/strong&gt; is a management space inside Keycloak that manages a set of users, credentials, roles, and clients. It provides an isolated domain where entities cannot access resources in another realm.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Master Realm&lt;/strong&gt;: Created by default. It contains the administrative accounts used to manage Keycloak itself. &lt;em&gt;Rule of thumb: Never use the Master realm for managing your application users.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Custom Realms&lt;/strong&gt;: You create custom realms (e.g., &lt;code&gt;company-dev&lt;/code&gt;, &lt;code&gt;my-app-production&lt;/code&gt;) for your actual applications.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Clients
&lt;/h3&gt;

&lt;p&gt;In Keycloak terminology, a &lt;strong&gt;Client&lt;/strong&gt; is an entity that requests Keycloak to authenticate a user. Clients can be front-end web apps, mobile apps, backend REST APIs, or third-party services.&lt;/p&gt;

&lt;p&gt;Keycloak categorizes clients based on their ability to keep credentials secret:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Public Clients&lt;/strong&gt;: Cannot hold client secrets safely (e.g., React/Vue SPAs, React Native mobile apps). They must use the &lt;strong&gt;Authorization Code Flow with PKCE&lt;/strong&gt; (Proof Key for Code Exchange).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Confidential Clients&lt;/strong&gt;: Backend applications capable of maintaining a client secret securely (e.g., Node.js Express, Spring Boot, Ruby on Rails apps).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bearer-only Clients&lt;/strong&gt;: Backend APIs that do not initiate logins themselves; they only verify incoming HTTP bearer tokens (JWTs).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Users, Groups, and Roles
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Users&lt;/strong&gt;: Individual entities that log into your applications.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Groups&lt;/strong&gt;: Collections of users. Roles assigned to a group are automatically inherited by its members.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Roles&lt;/strong&gt;: Permissions granted to users. Keycloak supports two levels of roles:

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Realm Roles&lt;/strong&gt;: Global permissions valid across all clients inside the realm (e.g., &lt;code&gt;global-admin&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client Roles&lt;/strong&gt;: Permissions specific to a particular client (e.g., &lt;code&gt;reports-service-viewer&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Authentication Flow in Action
&lt;/h2&gt;

&lt;p&gt;When using OpenID Connect (OIDC) with Keycloak, a typical login flow for a Single Page Application with a Backend API looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Login Request&lt;/strong&gt;: User clicks "Login" in the React/Vue frontend.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redirect to Keycloak&lt;/strong&gt;: Frontend redirects the user to Keycloak's login page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Authenticates&lt;/strong&gt;: User enters credentials (and MFA if configured).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Authorization Code&lt;/strong&gt;: Keycloak redirects back to the frontend with a short-lived authorization code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Exchange&lt;/strong&gt;: Frontend exchanges the code (and PKCE verifier) for tokens via Keycloak's token endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Token Issue&lt;/strong&gt;: Keycloak returns an &lt;strong&gt;Access Token (JWT)&lt;/strong&gt;, &lt;strong&gt;ID Token&lt;/strong&gt;, and &lt;strong&gt;Refresh Token&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;API Requests&lt;/strong&gt;: Frontend attaches the Access Token in the &lt;code&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/code&gt; header on backend requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Token Validation&lt;/strong&gt;: The backend API verifies the JWT's signature and claims without calling Keycloak every time.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Quick Start: Running Keycloak with Docker
&lt;/h2&gt;

&lt;p&gt;The fastest way to experiment with Keycloak locally is via Docker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; keycloak_dev &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;KEYCLOAK_ADMIN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;KEYCLOAK_ADMIN_PASSWORD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;admin &lt;span class="se"&gt;\&lt;/span&gt;
  quay.io/keycloak/keycloak:24.0.0 &lt;span class="se"&gt;\&lt;/span&gt;
  start-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once running, navigate to &lt;code&gt;http://localhost:8080&lt;/code&gt;, access the &lt;strong&gt;Admin Console&lt;/strong&gt;, log in with &lt;code&gt;admin/admin&lt;/code&gt;, and create a new realm (e.g., &lt;code&gt;dev-realm&lt;/code&gt;).&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Example: Validating Keycloak JWTs in a Node.js Backend
&lt;/h2&gt;

&lt;p&gt;Backend services need to verify the JWT tokens sent by client applications. Instead of querying Keycloak on every incoming HTTP request, backend APIs download Keycloak's public keys via &lt;strong&gt;JWKS (JSON Web Key Set)&lt;/strong&gt; to verify signatures locally.&lt;/p&gt;

&lt;p&gt;Here is how you can implement token verification in a Node.js / Express application using &lt;code&gt;jsonwebtoken&lt;/code&gt; and &lt;code&gt;jwks-rsa&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jsonwebtoken&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;jwksClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;jwks-rsa&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;KEYCLOAK_URL&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:8080&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;REALM_NAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dev-realm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Configure JWKS client to fetch public keys from Keycloak&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;jwksClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;jwksUri&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;KEYCLOAK_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/realms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;REALM_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/protocol/openid-connect/certs`&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Helper to get signing key from JWKS&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getSigningKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;kid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&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="nx"&gt;err&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;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;signingKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getPublicKey&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nf"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;signingKey&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;// Authentication Middleware&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;authenticateToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authHeader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;authorization&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;authHeader&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;authHeader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&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;token&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;issuer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;KEYCLOAK_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/realms/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;REALM_NAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;algorithms&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RS256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Token verification failed:&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Attach decoded user payload to request&lt;/span&gt;
    &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;next&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;// Protected endpoint&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/protected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;authenticateToken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Access granted to secure resource!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preferred_username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;realm_access&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;roles&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Backend running on port 3000&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inspecting User Roles in the JWT
&lt;/h3&gt;

&lt;p&gt;When Keycloak issues an access token, it includes realm and client roles inside the payload:&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;"exp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1710000000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"iss"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http://localhost:8080/realms/dev-realm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"preferred_username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"johndoe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"john@example.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"realm_access"&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;"roles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"developer"&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;"resource_access"&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;"my-backend-api"&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;"roles"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"read:reports"&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;Your backend middleware can inspect &lt;code&gt;realm_access.roles&lt;/code&gt; or &lt;code&gt;resource_access.&amp;lt;client&amp;gt;.roles&lt;/code&gt; to enforce fine-grained access policies.&lt;/p&gt;




&lt;h2&gt;
  
  
  Essential Best Practices for Production
&lt;/h2&gt;

&lt;p&gt;If you are planning to deploy Keycloak to production, keep these operational rules in mind:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Always Use HTTPS&lt;/strong&gt;: OAuth tokens are sensitive authorization credentials. Transmitting them over unencrypted HTTP exposes your app to man-in-the-middle (MitM) attacks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep Token Lifetimes Short&lt;/strong&gt;: Set Access Token expiration to short durations (e.g., 5 to 15 minutes). Rely on Refresh Tokens to get new access tokens seamlessly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use Realm Export/Import for CI/CD&lt;/strong&gt;: Keycloak allows exporting realm configurations to JSON format. Keep your realm settings in source control and import them during deployment pipelines rather than configuring production realms manually through the UI.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never Store Secrets in Front-end Code&lt;/strong&gt;: Always use &lt;strong&gt;PKCE&lt;/strong&gt; for browser and mobile applications. Client secrets belong strictly on server-side code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use an External Database&lt;/strong&gt;: Keycloak ships with an embedded H2 database by default. Never use H2 in production; connect Keycloak to a resilient PostgreSQL or MySQL cluster instead.&lt;/li&gt;
&lt;/ol&gt;




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

&lt;p&gt;Keycloak takes the heavy lifting out of application security by providing a battle-tested, standard-compliant authorization service. By mastering basic concepts like &lt;strong&gt;Realms&lt;/strong&gt;, &lt;strong&gt;Clients&lt;/strong&gt;, &lt;strong&gt;Scopes&lt;/strong&gt;, and &lt;strong&gt;JWKS-based token verification&lt;/strong&gt;, you can easily integrate secure single sign-on and role management into any modern software architecture.&lt;/p&gt;

&lt;p&gt;Have you used Keycloak in production, or are you exploring it for your next project? Let me know your thoughts and questions in the comments below!&lt;/p&gt;

</description>
      <category>keycloak</category>
      <category>security</category>
      <category>oauth2</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Codex vs Cursor vs Claude Code: Choosing the Right AI Coding Assistant</title>
      <dc:creator>Tien Nguyen Huynh</dc:creator>
      <pubDate>Mon, 31 Aug 2026 04:14:40 +0000</pubDate>
      <link>https://dev.to/hirdo/codex-vs-cursor-vs-claude-code-choosing-the-right-ai-coding-assistant-5cch</link>
      <guid>https://dev.to/hirdo/codex-vs-cursor-vs-claude-code-choosing-the-right-ai-coding-assistant-5cch</guid>
      <description>&lt;p&gt;The developer landscape has shifted dramatically over the past few years. We have moved from simple syntax highlighting and basic tab-completion to fully context-aware, agentic AI assistants capable of building entire features across complex codebases.&lt;/p&gt;

&lt;p&gt;Today, three prominent paradigms dominate the AI-assisted development space:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI Codex&lt;/strong&gt; (and its underlying legacy/API ecosystem, which laid the foundation for tools like GitHub Copilot).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cursor&lt;/strong&gt; (the AI-native VS Code fork designed from the ground up for deep codebase integration).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; (Anthropic’s agentic CLI tool powered by Claude 3.5 Sonnet, bringing AI directly into your terminal).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you are an intermediate developer trying to streamline your stack, deciding between these tools can be confusing. Are you better off with inline completion, an AI-native editor, or a CLI agent? Let’s dissect their strengths, architecture, real-world performance, and ideal use cases.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. OpenAI Codex: The Pioneer of Code Generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Released by OpenAI, Codex was a fine-tuned descendant of GPT-3 trained on billions of lines of public GitHub code. While OpenAI deprecated the standalone Codex API endpoint in favor of general-purpose models (like GPT-4o and GPT-4o-mini), "Codex" remains synonymous with the inline auto-complete paradigm that powered the early versions of GitHub Copilot.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inline Autocomplete:&lt;/strong&gt; Low-latency suggestions as you type comments or function signatures.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broad Model Support:&lt;/strong&gt; Modern derivatives leverage OpenAI’s fast speculative decoding models for real-time completion.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Integration Flexibility:&lt;/strong&gt; Can be embedded into almost any editor via plugins (Neovim, JetBrains, VS Code).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where It Shines
&lt;/h3&gt;

&lt;p&gt;Codex-style inline tools excel at &lt;strong&gt;micro-completions&lt;/strong&gt;. When writing boilerplate code, standard algorithms, or predictable interface types, inline completion provides seamless velocity without breaking your flow state.&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;// Example: Quick utility function generated via inline prompt&lt;/span&gt;
&lt;span class="c1"&gt;// Function to validate and sanitize an email address&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;sanitizeEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&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="kr"&gt;string&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;trimmed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;toLowerCase&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;emailRegex&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sr"&gt;/^&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9._%+-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+@&lt;/span&gt;&lt;span class="se"&gt;[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z0-9.-&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;+&lt;/span&gt;&lt;span class="se"&gt;\.[&lt;/span&gt;&lt;span class="sr"&gt;a-zA-Z&lt;/span&gt;&lt;span class="se"&gt;]{2,}&lt;/span&gt;&lt;span class="sr"&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;emailRegex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;trimmed&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Invalid email format&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;trimmed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Where It Falls Short
&lt;/h3&gt;

&lt;p&gt;Traditional Codex workflows struggle with &lt;strong&gt;broad project context&lt;/strong&gt;. Because inline completions rely heavily on open files or small token windows, they often lack awareness of cross-file abstractions, custom utility libraries, or repository-wide architectural patterns.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Cursor: The AI-Native IDE Standard
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Cursor is not just an extension; it is a full fork of VS Code engineered specifically around AI interaction. It integrates localized codebase indexing, context querying (&lt;code&gt;@codebase&lt;/code&gt;), and multi-file editing features directly into the editor UI.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Repository Indexing:&lt;/strong&gt; Scans vector embeddings of your entire repository for deep context lookup.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composer (Multi-file Edits):&lt;/strong&gt; Generates, refactors, and updates code across multiple files simultaneously using &lt;code&gt;Cmd + I&lt;/code&gt; or &lt;code&gt;Cmd + K&lt;/code&gt; interfaces.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model Agnostic Flexibility:&lt;/strong&gt; Allows you to switch between Claude 3.5 Sonnet, GPT-4o, and custom local models seamlessly.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Privacy Controls:&lt;/strong&gt; Offers privacy mode where code is not stored or used for model training.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where It Shines
&lt;/h3&gt;

&lt;p&gt;Cursor shines when working inside complex, modern web applications (like Next.js, React, or microservices). If you need to refactor a component and automatically update its corresponding API route, types, and unit tests, Cursor's &lt;strong&gt;Composer&lt;/strong&gt; handles multi-file mutations smoothly inside a visual diff editor.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="c1"&gt;// User prompts Cursor Composer:&lt;/span&gt;
&lt;span class="c1"&gt;// "Refactor UserProfile to use Server Actions and update the TypeScript interface in @types/user.ts"&lt;/span&gt;

&lt;span class="c1"&gt;// Cursor updates types/user.ts and components/UserProfile.tsx simultaneously:&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;UserProfileProps&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;userId&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;initialData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;email&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="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;UserProfile&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;initialData&lt;/span&gt; &lt;span class="p"&gt;}:&lt;/span&gt; &lt;span class="nx"&gt;UserProfileProps&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Cursor generates inline server action integration&lt;/span&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FormData&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;newName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;formData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&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;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userId&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="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;newName&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt; &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;updateName&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt; &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;initialData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;form&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Where It Falls Short
&lt;/h3&gt;

&lt;p&gt;Cursor requires leaving your default terminal-centric environment if you prefer lightweight text editors (like Helix or Neovim). Additionally, UI multi-file diffing can occasionally become slow on massive monorepos.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Claude Code: The Terminal-Native Agent
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;Claude Code is Anthropic’s developer agent operating directly inside your command-line interface (CLI). Powered by &lt;strong&gt;Claude 3.5 Sonnet&lt;/strong&gt;, Claude Code doesn't just write text—it acts as an agent that reads your repo structure, runs bash commands, executes git operations, executes tests, and fixes syntax errors autonomously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CLI First:&lt;/strong&gt; Runs natively in your terminal alongside your existing shell tools and text editors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool Use &amp;amp; Execution:&lt;/strong&gt; Can run terminal commands like &lt;code&gt;npm test&lt;/code&gt;, &lt;code&gt;git status&lt;/code&gt;, or &lt;code&gt;pytest&lt;/code&gt;, observe output errors, and self-correct code autonomously.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deep Reasoning:&lt;/strong&gt; Leverages Claude 3.5 Sonnet’s top-tier logic capabilities for architecture decisions and debugging complex logical edge cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Where It Shines
&lt;/h3&gt;

&lt;p&gt;Claude Code excels at &lt;strong&gt;autonomous problem solving and task completion&lt;/strong&gt;. You can issue high-level commands, and Claude Code executes the cycle of edit-test-fix without constant user hand-holding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example CLI command in Claude Code terminal&lt;/span&gt;
&lt;span class="nv"&gt;$ &lt;/span&gt;claude &lt;span class="s2"&gt;"Fix all failing tests in the /tests/auth directory and commit the changes with a descriptive message"&lt;/span&gt;

&lt;span class="c"&gt;# Claude Code executes under the hood:&lt;/span&gt;
&lt;span class="c"&gt;# 1. Runs `npm test tests/auth`&lt;/span&gt;
&lt;span class="c"&gt;# 2. Analyzes stack trace outputs&lt;/span&gt;
&lt;span class="c"&gt;# 3. Edits auth service files&lt;/span&gt;
&lt;span class="c"&gt;# 4. Re-runs tests to verify pass state&lt;/span&gt;
&lt;span class="c"&gt;# 5. Executes `git commit -am 'fix(auth): update token expiration check logic'`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Where It Falls Short
&lt;/h3&gt;

&lt;p&gt;Because it runs in the terminal, it lacks visual rich-text UI components for inline side-by-side diff review (unlike Cursor). It can also consume token credits quickly if left on complex loop-based debugging tasks.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparison Breakdown
&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;OpenAI Codex (Legacy / Copilot)&lt;/th&gt;
&lt;th&gt;Cursor IDE&lt;/th&gt;
&lt;th&gt;Claude Code (CLI)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Interface&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Inline plugin / Chat sidebar&lt;/td&gt;
&lt;td&gt;VS Code Fork (GUI)&lt;/td&gt;
&lt;td&gt;Terminal / Command Line&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Context Window Scope&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;File-level / Localized&lt;/td&gt;
&lt;td&gt;Entire Repository Vector Index&lt;/td&gt;
&lt;td&gt;Project Workspace / Bash Context&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Agentic Execution&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Moderate (Composer mode)&lt;/td&gt;
&lt;td&gt;High (Runs bash, git, tests)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multi-File Refactoring&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Weak&lt;/td&gt;
&lt;td&gt;Excellent (Visual Diffs)&lt;/td&gt;
&lt;td&gt;Excellent (File mutations)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Editor Flexibility&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Works in Neovim, JetBrains, VS Code&lt;/td&gt;
&lt;td&gt;Requires Cursor IDE&lt;/td&gt;
&lt;td&gt;Agnostic (Runs in any shell)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Primary Engine&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;GPT-4o / Codex variants&lt;/td&gt;
&lt;td&gt;Multi-model (Sonnet 3.5 default)&lt;/td&gt;
&lt;td&gt;Claude 3.5 Sonnet&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Which Tool Should You Choose?
&lt;/h2&gt;

&lt;p&gt;Choosing the right tool comes down to your primary development style:&lt;/p&gt;

&lt;h3&gt;
  
  
  Pick OpenAI Codex / GitHub Copilot if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You want simple, low-friction inline completions.&lt;/li&gt;
&lt;li&gt;You use specialized IDEs like JetBrains WebStorm/CLion or Vim/Neovim and don't want to switch editors.&lt;/li&gt;
&lt;li&gt;You prioritize speed and tab-completion over complex agentic workflows.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pick Cursor if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You are already a VS Code user and want an upgraded experience.&lt;/li&gt;
&lt;li&gt;You prefer visual diffs when reviewing code generated across multiple files.&lt;/li&gt;
&lt;li&gt;You want a hybrid workflow: low-latency inline completions combined with high-level prompt generation (&lt;code&gt;Cmd+K&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pick Claude Code if:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;You live in the terminal (tmux, Neovim, zsh).&lt;/li&gt;
&lt;li&gt;You want an agent that can test its own code, inspect build failures, and execute git commands.&lt;/li&gt;
&lt;li&gt;You deal with complex refactoring tasks where logical reasoning and step-by-step troubleshooting are crucial.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;The software engineering landscape is moving past simple code completion. While &lt;strong&gt;Codex&lt;/strong&gt; paved the way for AI-driven autocompletion, tools like &lt;strong&gt;Cursor&lt;/strong&gt; and &lt;strong&gt;Claude Code&lt;/strong&gt; represent the next stage of agentic execution. &lt;/p&gt;

&lt;p&gt;Many senior engineers are adopting a hybrid approach: using &lt;strong&gt;Cursor&lt;/strong&gt; for visual frontend work and multi-file code editing, alongside &lt;strong&gt;Claude Code&lt;/strong&gt; in the terminal for complex debugging, test suite repairs, and git automations. Try incorporating one of these advanced tools into your daily workflow to see your productivity multiply!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Docker for Developers: From Zero to Production-Ready Containers</title>
      <dc:creator>Tien Nguyen Huynh</dc:creator>
      <pubDate>Sun, 30 Aug 2026 16:40:09 +0000</pubDate>
      <link>https://dev.to/hirdo/docker-for-developers-from-zero-to-production-ready-containers-8f8</link>
      <guid>https://dev.to/hirdo/docker-for-developers-from-zero-to-production-ready-containers-8f8</guid>
      <description>&lt;p&gt;Every modern developer encounters Docker eventually. You have likely run &lt;code&gt;docker run -p 8080:80 nginx&lt;/code&gt; or copied a snippet from a README to get a local database running. But moving from blindly running commands to structuring production-grade container workflows requires a deeper understanding of how Docker operates under the hood.&lt;/p&gt;

&lt;p&gt;In this article, we will move beyond the basics of containerization. We will explore core container concepts, build a highly optimized multi-stage Dockerfile for a web application, orchestrate local environments with Docker Compose, and review production best practices that keep your images small and secure.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Demystifying the Core Architecture
&lt;/h2&gt;

&lt;p&gt;Before writing code, let us clear up common misconceptions about Docker components.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image&lt;/strong&gt;: A read-only template containing your application code, runtime, system tools, libraries, and dependencies. Think of an image as a class definition in OOP.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Container&lt;/strong&gt;: A runnable instance of an image. It is isolated from the host machine and other containers using Linux &lt;code&gt;namespaces&lt;/code&gt; (for isolation) and &lt;code&gt;cgroups&lt;/code&gt; (for resource limiting). Think of a container as an object instantiated from a class.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Volume&lt;/strong&gt;: Persistent storage detached from the container lifecycle. Because containers are ephemeral by default, any data written inside a container disappears when it is destroyed. Volumes mount a directory from the host OS into the container.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Network&lt;/strong&gt;: The abstraction layer allowing containers to communicate with each other or with external services.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Writing a Production-Grade Dockerfile
&lt;/h2&gt;

&lt;p&gt;A simple Dockerfile gets your app running, but an optimized Dockerfile ensures fast CI/CD builds, minimal attack surfaces, and tiny deployment artifacts.&lt;/p&gt;

&lt;p&gt;Let's look at a typical &lt;strong&gt;Node.js application&lt;/strong&gt;. Here is a common mistake beginners make:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Bad Dockerfile Example&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What is wrong with this approach?
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Massive image size&lt;/strong&gt;: &lt;code&gt;node:18&lt;/code&gt; is based on a full Debian distribution, weighing around 1GB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken build cache&lt;/strong&gt;: Copying &lt;code&gt;.&lt;/code&gt; before running &lt;code&gt;npm install&lt;/code&gt; invalidates Docker's layer cache on &lt;em&gt;every single code change&lt;/em&gt;, forcing node modules to reinstall every time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security risk&lt;/strong&gt;: The application runs as the root user inside the container.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  The Optimized Multi-Stage Approach
&lt;/h3&gt;

&lt;p&gt;Multi-stage builds allow you to use a heavy base image to compile dependencies and a lightweight image to run the final app.&lt;/p&gt;

&lt;p&gt;Here is how to structure it properly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Stage 1: Build &amp;amp; Dependencies&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="c"&gt;# Copy package manifests first to leverage Docker layer caching&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="c"&gt;# Install all dependencies (including devDependencies for building)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm ci

&lt;span class="c"&gt;# Copy remaining source code&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="c"&gt;# Build application (if using TypeScript or bundlers)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm run build

&lt;span class="c"&gt;# Prune non-production dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;npm prune &lt;span class="nt"&gt;--production&lt;/span&gt;

&lt;span class="c"&gt;# ---------------------------------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Stage 2: Production Execution&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;node:18-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runner&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/src/app&lt;/span&gt;

&lt;span class="c"&gt;# Set production environment&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; NODE_ENV=production&lt;/span&gt;

&lt;span class="c"&gt;# Create a non-privileged system user&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;addgroup &lt;span class="nt"&gt;-g&lt;/span&gt; 1001 &lt;span class="nt"&gt;-S&lt;/span&gt; nodejs &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    adduser &lt;span class="nt"&gt;-S&lt;/span&gt; nodejs &lt;span class="nt"&gt;-u&lt;/span&gt; 1001 &lt;span class="nt"&gt;-G&lt;/span&gt; nodejs

&lt;span class="c"&gt;# Copy built assets and production node_modules from builder&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /usr/src/app/package*.json ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /usr/src/app/node_modules ./node_modules&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /usr/src/app/dist ./dist&lt;/span&gt;

&lt;span class="c"&gt;# Change ownership to non-root user&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nodejs&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "dist/server.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Key Improvements Made:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Minimal Base Image&lt;/strong&gt;: Switching to &lt;code&gt;alpine&lt;/code&gt; reduces the base footprint down to ~150MB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layer Caching&lt;/strong&gt;: &lt;code&gt;package*.json&lt;/code&gt; is copied separately before &lt;code&gt;npm ci&lt;/code&gt;. Re-building after changing application logic takes seconds instead of minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Stage Build&lt;/strong&gt;: Development dependencies and build tools stay in the &lt;code&gt;builder&lt;/code&gt; stage, keeping the &lt;code&gt;runner&lt;/code&gt; image lean.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Least Privilege Security&lt;/strong&gt;: Setting &lt;code&gt;USER nodejs&lt;/code&gt; prevents potential container breakout exploits from obtaining host root access.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Don't Forget &lt;code&gt;.dockerignore&lt;/code&gt;!
&lt;/h2&gt;

&lt;p&gt;Just as &lt;code&gt;.gitignore&lt;/code&gt; keeps clutter out of your Git repository, a &lt;code&gt;.dockerignore&lt;/code&gt; file prevents unneeded files from entering the Docker build context. Sending gigabytes of local node modules or git history over to the Docker daemon slows down your builds.&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;.dockerignore&lt;/code&gt; file alongside your Dockerfile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;node_modules
npm-debug.log
.git
.gitignore
Dockerfile
docker-compose.yml
README.md
dist
.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Local Environment Orchestration with Docker Compose
&lt;/h2&gt;

&lt;p&gt;Applications rarely live in isolation. You usually need an app server, a database, and perhaps a caching layer like Redis.&lt;/p&gt;

&lt;p&gt;Rather than executing long &lt;code&gt;docker run&lt;/code&gt; commands manually, use &lt;strong&gt;Docker Compose&lt;/strong&gt; to define your stack declaratively in &lt;code&gt;docker-compose.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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.8'&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;context&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
      &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;runner&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3000:3000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;PORT=3000&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;DATABASE_URL=postgres://devuser:secretpass@db:5432/devdb&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;condition&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;service_healthy&lt;/span&gt;
    &lt;span class="na"&gt;restart&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unless-stopped&lt;/span&gt;

  &lt;span class="na"&gt;db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:15-alpine&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_USER&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devuser&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;secretpass&lt;/span&gt;
      &lt;span class="na"&gt;POSTGRES_DB&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;devdb&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;pgdata:/var/lib/postgresql/data&lt;/span&gt;
    &lt;span class="na"&gt;healthcheck&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CMD-SHELL"&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pg_isready&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-U&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;devuser&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;-d&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;devdb"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;5s&lt;/span&gt;
      &lt;span class="na"&gt;retries&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;

&lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pgdata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Useful Compose Commands:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Start all services in background: &lt;code&gt;docker compose up -d&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;View aggregated stream logs: &lt;code&gt;docker compose logs -f&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Stop and remove containers + networks: &lt;code&gt;docker compose down&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Destroy persistent volumes: &lt;code&gt;docker compose down -v&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Essential CLI Commands for Debugging
&lt;/h2&gt;

&lt;p&gt;When a container refuses to start or acts unexpectedly, these commands will save your sanity:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Inspect container logs&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker logs &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="nt"&gt;--tail&lt;/span&gt; 100 &amp;lt;container_id_or_name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Execute an interactive shell inside a running container&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;container_id_or_name&amp;gt; sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Check running container metrics (CPU, Memory, Network I/O)&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker stats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Clean up unused images, containers, and volumes&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;   docker system prune &lt;span class="nt"&gt;-a&lt;/span&gt; &lt;span class="nt"&gt;--volumes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Summary Checklist for Developers
&lt;/h2&gt;

&lt;p&gt;To ensure your application is containerized cleanly, keep these rules in mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;Leverage layer caching&lt;/strong&gt;: Put commands that change infrequently (installing dependencies) near the top of your Dockerfile.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Use lightweight base images&lt;/strong&gt;: Prefer &lt;code&gt;alpine&lt;/code&gt; or &lt;code&gt;slim&lt;/code&gt; tags over default full distributions.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Utilize multi-stage builds&lt;/strong&gt;: Keep build tools out of runtime images.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Never run as root&lt;/strong&gt;: Create and switch to a non-root system user inside the Dockerfile.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Include a &lt;code&gt;.dockerignore&lt;/code&gt;&lt;/strong&gt;: Do not transfer heavy build outputs or confidential &lt;code&gt;.env&lt;/code&gt; files to the build context.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;Store state outside containers&lt;/strong&gt;: Use named volumes or managed database services for persistent storage.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Containerization transforms software delivery from predictable local builds to dependable production deployments. Master these fundamentals, and your workflows will be faster, safer, and far easier to maintain.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>webdev</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
