{"id":190643,"date":"2026-04-09T13:02:35","date_gmt":"2026-04-09T13:02:35","guid":{"rendered":"https:\/\/randomnerdtutorials.com\/?p=190643"},"modified":"2026-04-09T13:02:38","modified_gmt":"2026-04-09T13:02:38","slug":"esp-idf-esp32-web-server","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp-idf-esp32-web-server\/","title":{"rendered":"ESP-IDF: ESP32 Simple Web Server (Serve HTML Page)"},"content":{"rendered":"\n<p>This guide shows how to build a simple local web server with the ESP32 programmed with ESP-IDF that serves a simple HTML web page. This web page can then be accessed on your local network. This example can then be further expanded to add buttons or text fields to control and monitor the ESP32 GPIOs.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Page.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Simple Web Server Serve HTML Page\" class=\"wp-image-190971\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Page.jpg?w=1920&amp;quality=100&amp;strip=all&amp;ssl=1 1920w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Page.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Page.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Page.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Page.jpg?resize=1536%2C864&amp;quality=100&amp;strip=all&amp;ssl=1 1536w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p class=\"rntbox rntclgray\"><strong>Using Arduino IDE?<\/strong> Follow this tutorial instead: <a href=\"https:\/\/randomnerdtutorials.com\/esp32-web-server-beginners-guide\/\">Building an ESP32 Web Server: The Complete Guide for Beginners (Arduino IDE)<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<p>Before following this guide, you need to install the ESP-IDF extension on VS Code IDE (Microsoft Visual Studio Code). Follow the next guide to install it, if you haven&#8217;t already:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/programming-esp32-esp-idf-vs-code\/\"><strong>Getting Started Guide:<\/strong> Programming ESP32 with ESP-IDF using VS Code<\/a><\/li>\n<\/ul>\n\n\n\n<p>You will also need an <a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noopener\" title=\"\">ESP32 development board<\/a> model of your choice.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"intro-web-servers\">Introducing Web Servers<\/h2>\n\n\n\n<p>In simple terms, a web server is a \u201ccomputer\u201d that delivers web pages. It stores the website\u2019s files, including HTML documents and related assets like images, CSS style sheets, fonts, and other files. When a user makes a request, the server sends those files to the user\u2019s web browser.<\/p>\n\n\n\n<p>When you access a web page in your browser, you\u2019re actually sending a request to a server using HTTP. This protocol handles how information is requested and delivered on the Internet. The server then responds by sending the web page you asked for, also through HTTP.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Client-Server (ESP32 as a Server)<\/h3>\n\n\n\n<p>When you type a URL in your browser, your device (the client) sends a request to a server using the Hypertext Transfer Protocol (HTTP). The server receives the request and responds\u2014also via HTTP\u2014by sending back the web page.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"271\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/esp32-client-server-communication-f.png?resize=750%2C271&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Client Server Communication explained\" class=\"wp-image-169421\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/esp32-client-server-communication-f.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/esp32-client-server-communication-f.png?resize=300%2C108&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>Throughout this tutorial, we\u2019ll treat the ESP32 as the server, and you, using your browser, as the client.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">ESP-IDF: ESP32 Web Server<\/h3>\n\n\n\n<p>For this tutorial, let\u2019s take a look at a practical example with the ESP32 that acts as a local web server in the local network.<\/p>\n\n\n\n<p>Typically, a web server with the ESP32 in the local network looks like this: the ESP32 running as a web server is connected via Wi-Fi to your router. Your computer, smartphone, or tablet, are also connected to your router via Wi-Fi or Ethernet cable. So, the ESP32 and your browser are on the same network.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"750\" height=\"200\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-Web-Server-Wi-Fi-Client-Connected-1.png?resize=750%2C200&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Acting as a Web Server\" class=\"wp-image-169429\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-Web-Server-Wi-Fi-Client-Connected-1.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-Web-Server-Wi-Fi-Client-Connected-1.png?resize=300%2C80&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>When you type the ESP32 IP address in your browser, you are sending an HTTP request to your ESP32. Then, the ESP32 responds with a response that can contain a value, a reading, HTML text to display a web page, or any other data.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"214\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-Web-Server-Wi-Fi-Clients-Request-Response.png?resize=750%2C214&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP32 Web Server Request Response\" class=\"wp-image-169430\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-Web-Server-Wi-Fi-Clients-Request-Response.png?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/04\/ESP32-Web-Server-Wi-Fi-Clients-Request-Response.png?resize=300%2C86&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p>In this particular tutorial, when you type the ESP32 IP address in your web browser, the ESP32 will respond by sending HTML text to create a simple web page (the page shown in the picture below).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"628\" height=\"385\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Web-Page-Demonstration.png?resize=628%2C385&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Simple Web Server Demonstration Serve HTML Web Page\" class=\"wp-image-190761\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Web-Page-Demonstration.png?w=628&amp;quality=100&amp;strip=all&amp;ssl=1 628w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Web-Page-Demonstration.png?resize=300%2C184&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 628px) 100vw, 628px\" \/><\/figure><\/div>\n\n\n<p>For simplicity, we&#8217;re creating this very simple web page. This example can then be further expanded to add buttons or text fields to control and monitor the ESP32 GPIOs (we&#8217;ll cover this in future tutorials).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Creating an ESP-IDF Template App Project for the ESP32<\/h2>\n\n\n\n<p>The ESP-IDF extension provides an easy way to create a project from scratch with all the required files and configurations generated automatically.<\/p>\n\n\n\n<p>To create a new ESP-IDF project on VS Code, follow these steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open the ESP-IDF Espressif extension<\/li>\n\n\n\n<li>Expand the &#8220;<strong>Advanced<\/strong>&#8221; menu<\/li>\n\n\n\n<li>Click the &#8220;<strong>New Project Wizard<\/strong>&#8221; option<\/li>\n\n\n\n<li>Choose the &#8220;<strong>Use ESP-IDF v5.4.1<\/strong>&#8221; to select the framework version<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"937\" height=\"742\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Create-Open-New-Project-Wizard-Menu.png?resize=937%2C742&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Create Open New Project Wizard Menu\" class=\"wp-image-170511\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Create-Open-New-Project-Wizard-Menu.png?w=937&amp;quality=100&amp;strip=all&amp;ssl=1 937w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Create-Open-New-Project-Wizard-Menu.png?resize=300%2C238&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Create-Open-New-Project-Wizard-Menu.png?resize=768%2C608&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 937px) 100vw, 937px\" \/><\/figure><\/div>\n\n\n<p>A new window opens, you need to fill in these fields:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Project Name:<\/strong> type the desired project name;<\/li>\n\n\n\n<li><strong>Enter Project Directory:<\/strong> click the folder icon and select the target folder to save all your project files. You can use any directory. <strong>Note:<\/strong> <u>do NOT use a Google Drive \/ One Drive \/ Dropbox folder<\/u>, because it will write\/create many files during the building process\u2014if it&#8217;s on a cloud folder, this process might be extremely slow;<\/li>\n\n\n\n<li><strong>ESP-IDF Target:<\/strong> select the target device chip, I&#8217;m using an ESP32 with the <strong>esp32s3<\/strong> chip;<\/li>\n\n\n\n<li><strong>ESP-IDF Board:<\/strong> for the esp32s3 chip, I also need to select the configuration: ESP32-S chip (via builtin USB-JTAG);<\/li>\n\n\n\n<li><strong>Serial Port:<\/strong> while having your ESP32 board connected to your computer, select the correct COM port number that refers to your ESP32;<\/li>\n\n\n\n<li><strong>Choose Template:<\/strong> click the blue button to create a new project using a template.<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"983\" height=\"856\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Create-Open-New-Project-Wizard-Menu-Select-Directory-Board-Template.png?resize=983%2C856&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Create Open New Project Wizard Menu Select Directory Board Template\" class=\"wp-image-170512\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Create-Open-New-Project-Wizard-Menu-Select-Directory-Board-Template.png?w=983&amp;quality=100&amp;strip=all&amp;ssl=1 983w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Create-Open-New-Project-Wizard-Menu-Select-Directory-Board-Template.png?resize=300%2C261&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Create-Open-New-Project-Wizard-Menu-Select-Directory-Board-Template.png?resize=768%2C669&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 983px) 100vw, 983px\" \/><\/figure><\/div>\n\n\n<p>In the menu, select the &#8220;<strong>ESP-IDF Templates<\/strong>&#8221; sample project and press the &#8220;<strong>Create project using template sample project<\/strong>&#8221; button.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1178\" height=\"744\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Create-New-Sample-Project-using-IDF-Template.png?resize=1178%2C744&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Create New Sample Project using IDF Template\" class=\"wp-image-187415\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Create-New-Sample-Project-using-IDF-Template.png?w=1178&amp;quality=100&amp;strip=all&amp;ssl=1 1178w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Create-New-Sample-Project-using-IDF-Template.png?resize=300%2C189&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Create-New-Sample-Project-using-IDF-Template.png?resize=1024%2C647&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Create-New-Sample-Project-using-IDF-Template.png?resize=768%2C485&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1178px) 100vw, 1178px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">Opening the ESP-IDF Project on VS Code<\/h3>\n\n\n\n<p>After a few seconds, a notification will appear in a new window in VS Code. You can click &#8220;<strong>Open Project<\/strong>&#8221; to open the newly created ESP-IDF sample project template.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"503\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Open-New-Project-Sample.png?resize=1024%2C503&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Open New Project Sample\" class=\"wp-image-187416\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Open-New-Project-Sample.png?resize=1024%2C503&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Open-New-Project-Sample.png?resize=300%2C147&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Open-New-Project-Sample.png?resize=768%2C377&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/01\/ESP-IDF-ESP32-Open-New-Project-Sample.png?w=1231&amp;quality=100&amp;strip=all&amp;ssl=1 1231w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p><strong>IMPORTANT:<\/strong> if you didn&#8217;t see the notification that allows you to automatically open the ESP-IDF project on VS Code, you can easily do it by following these instructions:<\/p>\n\n\n\n<p>Go to <strong>File <\/strong>&gt; <strong>Open Folder&#8230;<\/strong><\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"396\" height=\"315\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-Folder-VS-Code-File-Menu.png?resize=396%2C315&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Open Project Folder VS Code File Menu\" class=\"wp-image-170518\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-Folder-VS-Code-File-Menu.png?w=396&amp;quality=100&amp;strip=all&amp;ssl=1 396w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-Folder-VS-Code-File-Menu.png?resize=300%2C239&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 396px) 100vw, 396px\" \/><\/figure><\/div>\n\n\n<p>Browse on your computer for the <em>esp-idf-project folder<\/em> (your project folder name that you&#8217;ve previously defined) and &#8220;<strong>Select Folder<\/strong>&#8220;.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"667\" height=\"366\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-VS-Code-Select-Folder.png?resize=667%2C366&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Open Project VS Code Select Folder\" class=\"wp-image-170517\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-VS-Code-Select-Folder.png?w=667&amp;quality=100&amp;strip=all&amp;ssl=1 667w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-VS-Code-Select-Folder.png?resize=300%2C165&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 667px) 100vw, 667px\" \/><\/figure><\/div>\n\n\n<p>That&#8217;s it! Your new ESP-IDF project template has been successfully created and opened.<\/p>\n\n\n\n<p>ESP-IDF generates many files, folders, and subfolders for your project. For this guide, I recommend keeping all the default files unchanged; we will only modify the <em>main.c<\/em> file.<\/p>\n\n\n\n<p>The example code will be written in the <em>main.c<\/em> file. To open it, follow these instructions:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Open the project explorer by clicking the first icon on the left sidebar.<\/li>\n\n\n\n<li>Select your project folder name, in my case it&#8217;s &#8220;<strong>ESP-IDF-PROJECT<\/strong>&#8220;.<\/li>\n\n\n\n<li>Expand the &#8220;<strong>main<\/strong>&#8221; folder.<\/li>\n\n\n\n<li>Click the &#8220;<strong><em>main.c<\/em><\/strong>&#8221; file.<\/li>\n\n\n\n<li>The default <em>main.c<\/em> template file loads in the code window.<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"907\" height=\"571\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-in-a-VS-Code-Browse-to-Main-C-File.png?resize=907%2C571&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Open Project in a VS Code Browse to Main C File\" class=\"wp-image-170514\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-in-a-VS-Code-Browse-to-Main-C-File.png?w=907&amp;quality=100&amp;strip=all&amp;ssl=1 907w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-in-a-VS-Code-Browse-to-Main-C-File.png?resize=300%2C189&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/ESP-IDF-ESP32-Open-Project-in-a-VS-Code-Browse-to-Main-C-File.png?resize=768%2C483&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 907px) 100vw, 907px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"Kconfig-projbuild\">Create the Wi-Fi Config Options File &#8211; Kconfig.projbuild<\/h2>\n\n\n\n<p>The <em>Kconfig.projbuild<\/em> file in ESP-IDF is a configuration file placed in a project&#8217;s main folder to define custom options in the SDK Configuration Editor (menuconfig tool). This allows users to set specific settings like strings or values that will be used during build configuration.<\/p>\n\n\n\n<p>To create the <em>Kconfig.projbuild<\/em> file, go to the File Explorer left sidebar and right-click on top of the <em>main <\/em>folder. Then, select the &#8220;<strong>New File&#8230;<\/strong>&#8221; option:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"626\" height=\"416\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Create-new-file-main-folder-Kconfig-projbuild.png?resize=626%2C416&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Create new file main folder Kconfig projbuild\" class=\"wp-image-190719\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Create-new-file-main-folder-Kconfig-projbuild.png?w=626&amp;quality=100&amp;strip=all&amp;ssl=1 626w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Create-new-file-main-folder-Kconfig-projbuild.png?resize=300%2C199&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 626px) 100vw, 626px\" \/><\/figure><\/div>\n\n\n<p>Name the new file exactly as follows: <span class=\"rnthl rntliteral\"><em>Kconfig.projbuild<\/em><\/span> and copy the content (shown after the following screenshot) to your newly created file.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1012\" height=\"512\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Kconfig-projbuild-Wi-Fi-Configuration-File.png?resize=1012%2C512&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Kconfig projbuild Wi-Fi Configuration File\" class=\"wp-image-190721\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Kconfig-projbuild-Wi-Fi-Configuration-File.png?w=1012&amp;quality=100&amp;strip=all&amp;ssl=1 1012w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Kconfig-projbuild-Wi-Fi-Configuration-File.png?resize=300%2C152&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Kconfig-projbuild-Wi-Fi-Configuration-File.png?resize=768%2C389&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 1012px) 100vw, 1012px\" \/><\/figure><\/div>\n\n\n<pre class=\"wp-block-code\"><code>menu \"Wi-Fi Configuration\"\n    config ESP_WIFI_SSID\n        string \"WiFi SSID\"\n        help\n            SSID (network name) you want to connect to.\n\n    config ESP_WIFI_PASSWORD\n        string \"WiFi Password\"\n        help\n            Password of the Wi-Fi network you want to connect to.\nendmenu<\/code><\/pre>\n\n\n\n<p>Save the file content. This will create a new menu called &#8220;<em>Wi-Fi Configuration<\/em>&#8221; in the SDK Configuration Editor where you can type you SSID and Password, so the ESP can connect to your network.<\/p>\n\n\n\n<p>Having the <em>Kconfig.projbuild<\/em> file prepared, click the gear icon to open the SDK Configuration Editor (menuconfig).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"655\" height=\"444\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Open-SDK-Configuration-Editor-Menuconfig-Wi-Fi-Configuration.png?resize=655%2C444&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"Open SDK Configuration Editor Menuconfig Wi-Fi Configuration\" class=\"wp-image-190723\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Open-SDK-Configuration-Editor-Menuconfig-Wi-Fi-Configuration.png?w=655&amp;quality=100&amp;strip=all&amp;ssl=1 655w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/Open-SDK-Configuration-Editor-Menuconfig-Wi-Fi-Configuration.png?resize=300%2C203&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 655px) 100vw, 655px\" \/><\/figure><\/div>\n\n\n<p>Now, instead of typing your network credentials inside the <em>main.c<\/em> file, you can configure them in the menuconfig tool. Follow these next steps:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Search for &#8220;<strong>wifi<\/strong>&#8220;;<\/li>\n\n\n\n<li>Type your SSID and Password in the fields;<\/li>\n\n\n\n<li>Press the &#8220;<strong>Save<\/strong>&#8221; button to apply the changes.<\/li>\n<\/ol>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"414\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/SDK-Configuration-Editor-Menuconfig-Kconfig-projbuild-Wi-Fi-Configuration-SSID-Password.png?resize=1024%2C414&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"SDK Configuration Editor Menuconfig Kconfig projbuild Wi-Fi Configuration SSID Password\" class=\"wp-image-190722\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/SDK-Configuration-Editor-Menuconfig-Kconfig-projbuild-Wi-Fi-Configuration-SSID-Password.png?resize=1024%2C414&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/SDK-Configuration-Editor-Menuconfig-Kconfig-projbuild-Wi-Fi-Configuration-SSID-Password.png?resize=300%2C121&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/SDK-Configuration-Editor-Menuconfig-Kconfig-projbuild-Wi-Fi-Configuration-SSID-Password.png?resize=768%2C310&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/SDK-Configuration-Editor-Menuconfig-Kconfig-projbuild-Wi-Fi-Configuration-SSID-Password.png?w=1175&amp;quality=100&amp;strip=all&amp;ssl=1 1175w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Code: ESP32 Simple Web Server using ESP-IDF<\/h2>\n\n\n\n<p>Copy the following code to the <em>main.c<\/em> file. This code serves a basic HTML web page hosted on an ESP32 with some text content.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*  \n  Rui Santos &amp; Sara Santos - Random Nerd Tutorials\n  https:\/\/RandomNerdTutorials.com\/esp-idf-esp32-web-server\/\n*\/\n#include &lt;stdio.h&gt;\n#include &lt;string.h&gt;\n#include &quot;freertos\/FreeRTOS.h&quot;\n#include &quot;freertos\/task.h&quot;\n#include &quot;esp_system.h&quot;\n#include &quot;esp_wifi.h&quot;\n#include &quot;esp_event.h&quot;\n#include &quot;esp_log.h&quot;\n#include &quot;nvs_flash.h&quot;\n#include &quot;esp_netif.h&quot;\n#include &quot;esp_http_server.h&quot;\n#include &quot;sdkconfig.h&quot;\n\n#define MY_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID\n#define MY_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD\n\nstatic const char *TAG = &quot;web_server&quot;;\n\n\/\/ HTML web page to serve \nstatic const char *html_page = \n    &quot;&lt;!DOCTYPE html&gt;&quot;\n    &quot;&lt;html&gt;&quot;\n    &quot;&lt;head&gt;&quot;\n    &quot;&lt;title&gt;ESP-IDF: ESP32 Web Server&lt;\/title&gt;&quot;\n    &quot;&lt;meta name=\\&quot;viewport\\&quot; content=\\&quot;width=device-width, initial-scale=1\\&quot;&gt;&quot;\n    &quot;&lt;\/head&gt;&quot;\n    &quot;&lt;body&gt;&quot;\n    &quot;&lt;h1&gt;ESP-IDF: ESP32 Web Server&lt;\/h1&gt;&quot;\n    &quot;&lt;p&gt;Hello from ESP32!&lt;\/p&gt;&quot;\n    &quot;&lt;\/body&gt;&quot;\n    &quot;&lt;\/html&gt;&quot;;\n\n\/\/ (Another option) HTML web page to serve (can be defined as a raw string literal for better readability)\n\/*\nstatic const char *html_page = R&quot;raw(\n&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;ESP-IDF: ESP32 Web Server&lt;\/title&gt;\n    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;h1&gt;ESP-IDF: ESP32 Web Server&lt;\/h1&gt;\n    &lt;p&gt;Hello from ESP32!&lt;\/p&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n)raw&quot;;*\/\n\n\/\/ HTTP GET handler for root &quot;\/&quot;\nstatic esp_err_t root_get_handler(httpd_req_t *req)\n{\n    httpd_resp_set_type(req, &quot;text\/html&quot;);\n    httpd_resp_send(req, html_page, HTTPD_RESP_USE_STRLEN);\n    return ESP_OK;\n}\n\n\/\/ Start the HTTP server\nstatic httpd_handle_t start_web_server(void)\n{\n    httpd_config_t config = HTTPD_DEFAULT_CONFIG();\n    httpd_handle_t server = NULL;\n\n    if (httpd_start(&amp;server, &amp;config) == ESP_OK) {\n        ESP_LOGI(TAG, &quot;HTTP server started on port %d&quot;, config.server_port);\n        \n        \/\/ Register URI handler\n        httpd_uri_t uri_get = {\n            .uri       = &quot;\/&quot;,\n            .method    = HTTP_GET,\n            .handler   = root_get_handler,\n            .user_ctx  = NULL\n        };\n        httpd_register_uri_handler(server, &amp;uri_get);\n        \n        return server;\n    }\n    \n    ESP_LOGE(TAG, &quot;Failed to start HTTP server&quot;);\n    return NULL;\n}\n\n\/\/ Wi-Fi and IP event handler\nstatic void wifi_event_handler(void* arg, esp_event_base_t event_base,\n                               int32_t event_id, void* event_data)\n{\n    if (event_base == WIFI_EVENT &amp;&amp; event_id == WIFI_EVENT_STA_START) {\n        ESP_LOGI(TAG, &quot;Wi-Fi STA started. Connecting to %s...&quot;, MY_ESP_WIFI_SSID);\n        esp_wifi_connect();\n    } else if (event_base == WIFI_EVENT &amp;&amp; event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        ESP_LOGW(TAG, &quot;Wi-Fi disconnected. Retrying connection...&quot;);\n        esp_wifi_connect();\n    } else if (event_base == IP_EVENT &amp;&amp; event_id == IP_EVENT_STA_GOT_IP) {\n        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;\n        ESP_LOGI(TAG, &quot;Got IP Address: &quot; IPSTR, IP2STR(&amp;event-&gt;ip_info.ip));\n        ESP_LOGI(TAG, &quot;Web Server ready! Access at http:\/\/&quot; IPSTR &quot;\/&quot;, IP2STR(&amp;event-&gt;ip_info.ip));\n    }\n}\n\nvoid app_main(void)\n{\n    \/\/ Initialize NVS\n    esp_err_t ret = nvs_flash_init();\n    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n        ESP_ERROR_CHECK(nvs_flash_erase());\n        ret = nvs_flash_init();\n    }\n    ESP_ERROR_CHECK(ret);\n\n    \/\/ Initialize TCP\/IP stack and event loop\n    ESP_ERROR_CHECK(esp_netif_init());\n    ESP_ERROR_CHECK(esp_event_loop_create_default());\n\n    \/\/ Create default Wi-Fi STA interface\n    esp_netif_create_default_wifi_sta();\n\n    \/\/ Initialize Wi-Fi\n    wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\n    ESP_ERROR_CHECK(esp_wifi_init(&amp;cfg));\n\n    \/\/ Register event handlers\n    ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,\n                                                        ESP_EVENT_ANY_ID,\n                                                        &amp;wifi_event_handler,\n                                                        NULL, NULL));\n    ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,\n                                                        IP_EVENT_STA_GOT_IP,\n                                                        &amp;wifi_event_handler,\n                                                        NULL, NULL));\n\n    \/\/ Configure Wi-Fi STA\n    wifi_config_t wifi_config = {\n        .sta = {\n            .ssid = MY_ESP_WIFI_SSID,\n            .password = MY_ESP_WIFI_PASS,\n        },\n    };\n    ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\n    ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &amp;wifi_config));\n    ESP_ERROR_CHECK(esp_wifi_start());\n\n    \/\/ Start the web server (it will be ready once IP is assigned)\n    httpd_handle_t server = start_web_server();\n    if (server) {\n        ESP_LOGI(TAG, &quot;Web Server initialized. Waiting for Wi-Fi connection...&quot;);\n    }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/Random-Nerd-Tutorials\/raw\/master\/Projects\/ESP-IDF\/wifi_simple_web_server\/wifi_simple_web_server.c\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>In this section, we&#8217;ll take a look at the code to see how it works.<\/p>\n\n\n\n<p><strong>Libraries<\/strong><\/p>\n\n\n\n<p>We start by including the required libraries:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span class=\"rnthl rntliteral\">stdio.h<\/span> &#8211; the standard C library will be used for the <span class=\"rnthl rntliteral\">printf<\/span> function that prints the debugging information in the serial monitor;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">string.h<\/span> &#8211; the standard C library used for string manipulation;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">FreeRTOS.h<\/span> &#8211; provides the core FreeRTOS types and functions;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">task.h<\/span> &#8211; allows to use task management;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">esp_system.h<\/span> &#8211; system level functions like restart and hardware info;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">esp_wifi.h<\/span> &#8211; library for Wi-Fi configuration (station and access point modes and connection options);<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">esp_event.h<\/span> &#8211; handles events like Wi-Fi status changes;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">esp_log.h<\/span> &#8211; offers a framework to format log messages in the serial monitor for debugging;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">nvs_flash.h<\/span> &#8211; stores key-value data in non-volatile storage (NVS) memory persistently ;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">esp_netif.h<\/span> &#8211; provides the network interface;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">esp_http_server.h<\/span> &#8211; library to create an HTTP server and handle HTTP requests\/responses;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">sdkconfig.h<\/span> &#8211; includes the project&#8217;s configuration file.<\/li>\n<\/ul>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#include &lt;stdio.h&gt;\n#include &lt;string.h&gt;\n#include \"freertos\/FreeRTOS.h\"\n#include \"freertos\/task.h\"\n#include \"esp_system.h\"\n#include \"esp_wifi.h\"\n#include \"esp_event.h\"\n#include \"esp_log.h\"\n#include \"nvs_flash.h\"\n#include \"esp_netif.h\"\n#include \"esp_http_server.h\"\n#include \"sdkconfig.h\"<\/code><\/pre>\n\n\n\n<p><strong>Wi-Fi Configuration<\/strong><\/p>\n\n\n\n<p>These variables will be retrieved from the <strong>menuconfig<\/strong> options as described in the previous section &#8220;<a href=\"#Kconfig-projbuild\" title=\"\">Create the Wi-Fi Config Options File &#8211; Kconfig.projbuild<\/a>&#8220;.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>#define MY_ESP_WIFI_SSID      CONFIG_ESP_WIFI_SSID\n#define MY_ESP_WIFI_PASS      CONFIG_ESP_WIFI_PASSWORD<\/code><\/pre>\n\n\n\n<p><strong>Logging Tag<\/strong><\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">&#8220;web_server&#8221;<\/span> prefix will be used to log all the debugging messages.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>static const char *TAG = \"web_server\";<\/code><\/pre>\n\n\n\n<p><strong>HTML Web Page<\/strong><\/p>\n\n\n\n<p>This is the HTML web page that will be sent to the connected client. You can either do as shown below where each line is inside quotation marks.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>static const char *html_page = \n    \"&lt;!DOCTYPE html&gt;\"\n    \"&lt;html&gt;\"\n    \"&lt;head&gt;\"\n    \"&lt;title&gt;ESP-IDF: ESP32 Web Server&lt;\/title&gt;\"\n    \"&lt;meta name=\\\"viewport\\\" content=\\\"width=device-width, initial-scale=1\\\"&gt;\"\n    \"&lt;\/head&gt;\"\n    \"&lt;body&gt;\"\n    \"&lt;h1&gt;ESP-IDF: ESP32 Web Server&lt;\/h1&gt;\"\n    \"&lt;p&gt;Hello from ESP32!&lt;\/p&gt;\"\n    \"&lt;\/body&gt;\"\n    \"&lt;\/html&gt;\";<\/code><\/pre>\n\n\n\n<p>Or you can use the <span class=\"rnthl rntliteral\">R&#8221;raw(<\/span> to have the full web page inside without quotation marks.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>static const char *html_page = R\"raw(\n&lt;!DOCTYPE html&gt;\n&lt;html&gt;\n&lt;head&gt;\n    &lt;title&gt;ESP-IDF: ESP32 Web Server&lt;\/title&gt;\n    &lt;meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"&gt;\n&lt;\/head&gt;\n&lt;body&gt;\n    &lt;h1&gt;ESP-IDF: ESP32 Web Server&lt;\/h1&gt;\n    &lt;p&gt;Hello from ESP32!&lt;\/p&gt;\n&lt;\/body&gt;\n&lt;\/html&gt;\n)raw\";<\/code><\/pre>\n\n\n\n<p><strong>HTTP GET Handler<\/strong><\/p>\n\n\n\n<p>This function (<span class=\"rnthl rntliteral\">root_get_handler<\/span>) runs every time a client enters the ESP IP address in the browser (this makes a request to the root <span class=\"rnthl rntliteral\">\/<\/span> web page). The <span class=\"rnthl rntliteral\">httpd_resp_set_type<\/span> function tells the browser that the file to be sent is in HTML format. Finally, the <span class=\"rnthl rntliteral\">httpd_resp_send<\/span> sends the <span class=\"rnthl rntliteral\">html_page<\/span> to the client.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>static esp_err_t root_get_handler(httpd_req_t *req)\n{\n    httpd_resp_set_type(req, \"text\/html\");\n    httpd_resp_send(req, html_page, HTTPD_RESP_USE_STRLEN);\n    return ESP_OK;\n}<\/code><\/pre>\n\n\n\n<p><strong>Start the HTTP Web Server<\/strong><\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">start_web_server()<\/span> function starts by configuring the server (uses the default port 80):<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>httpd_config_t config = HTTPD_DEFAULT_CONFIG();\nhttpd_handle_t server = NULL;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">httpd_start(&amp;server, &amp;config)<\/span> starts the actual HTTP web server and starts listening to connections on port 80, so a client can connect to it. Then, we register the route, so when someone opens the <span class=\"rnthl rntliteral\">\/<\/span> URL, it runs the <span class=\"rnthl rntliteral\">root_get_handler()<\/span> function that sends the <span class=\"rnthl rntliteral\">html_page<\/span> variable defined earlier.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>if (httpd_start(&amp;server, &amp;config) == ESP_OK) {\n    ESP_LOGI(TAG, \"HTTP server started on port %d\", config.server_port);\n        \n    \/\/ Register URI handler\n    httpd_uri_t uri_get = {\n        .uri       = \"\/\",\n        .method    = HTTP_GET,\n        .handler   = root_get_handler,\n        .user_ctx  = NULL\n    };\n    httpd_register_uri_handler(server, &amp;uri_get);\n        \n    return server;\n}<\/code><\/pre>\n\n\n\n<p>If it fails to start the HTTP web server, it prints a failed message.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>ESP_LOGE(TAG, \"Failed to start HTTP server\");<\/code><\/pre>\n\n\n\n<p><strong>Wi-Fi and IP event handler<\/strong><\/p>\n\n\n\n<p>This callback function runs when an event related to Wi-Fi happens.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>static void wifi_event_handler(void* arg, esp_event_base_t event_base,\n                               int32_t event_id, void* event_data)\n{\n    if (event_base == WIFI_EVENT &amp;&amp; event_id == WIFI_EVENT_STA_START) {\n        ESP_LOGI(TAG, \"Wi-Fi STA started. Connecting to %s...\", MY_ESP_WIFI_SSID);\n        esp_wifi_connect();\n    } else if (event_base == WIFI_EVENT &amp;&amp; event_id == WIFI_EVENT_STA_DISCONNECTED) {\n        ESP_LOGW(TAG, \"Wi-Fi disconnected. Retrying connection...\");\n        esp_wifi_connect();\n    } else if (event_base == IP_EVENT &amp;&amp; event_id == IP_EVENT_STA_GOT_IP) {\n        ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;\n        ESP_LOGI(TAG, \"Got IP Address: \" IPSTR, IP2STR(&amp;event-&gt;ip_info.ip));\n        ESP_LOGI(TAG, \"Web Server ready! Access at http:\/\/\" IPSTR \"\/\", IP2STR(&amp;event-&gt;ip_info.ip));\n    }\n}<\/code><\/pre>\n\n\n\n<p>For example, when the ESP32 gets assigned an IP address, it triggers the <span class=\"rnthl rntliteral\">IP_EVENT<\/span> that prints this message in the Serial Monitor:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>ESP_LOGI(TAG, \"Got IP Address: \" IPSTR, IP2STR(&amp;event-&gt;ip_info.ip));\nESP_LOGI(TAG, \"Web Server ready! Access at http:\/\/\" IPSTR \"\/\", IP2STR(&amp;event-&gt;ip_info.ip));<\/code><\/pre>\n\n\n\n<p><strong>app_main(void)<\/strong><\/p>\n\n\n\n<p>When creating an ESP-IDF project, the <span class=\"rnthl rntliteral\">app_main<\/span> function will always be called to run. This function is where you need to write your code for any ESP-IDF applications; it is the equivalent of the <span class=\"rnthl rntliteral\">setup()<\/span> in Arduino programming. When the ESP32 boots, the ESP-IDF framework calls <span class=\"rnthl rntliteral\">app_main<\/span>.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>void app_main(void)\n{\n    \/\/ your code goes here\n}<\/code><\/pre>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">app_main(void)<\/span> function, you start by initializing the NVS (storage)\u2014the ESP32 stores the Wi-Fi settings in flash.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>esp_err_t ret = nvs_flash_init();\nif (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {\n    ESP_ERROR_CHECK(nvs_flash_erase());\n    ret = nvs_flash_init();\n}\nESP_ERROR_CHECK(ret);<\/code><\/pre>\n\n\n\n<p>Then, initialize the TCP\/IP stack required for network functions usage.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>ESP_ERROR_CHECK(esp_netif_init());\nESP_ERROR_CHECK(esp_event_loop_create_default());<\/code><\/pre>\n\n\n\n<p>Start the Wi-Fi interface in station mode, so the ESP32 can connect to the router. It also initializes the Wi-Fi functionalities.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>esp_netif_create_default_wifi_sta();\n\nwifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();\nESP_ERROR_CHECK(esp_wifi_init(&amp;cfg));<\/code><\/pre>\n\n\n\n<p>Assign the Wi-Fi events, so that when the ESP32 establishes a Wi-Fi connection or gets an IP address, it runs the corresponding Wi-Fi event.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,\n                                                    ESP_EVENT_ANY_ID,\n                                                    &amp;wifi_event_handler,\n                                                    NULL, NULL));\nESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,\n                                                    IP_EVENT_STA_GOT_IP,\n                                                    &amp;wifi_event_handler,\n                                                    NULL, NULL));<\/code><\/pre>\n\n\n\n<p>These next few lines set the SSID and password so the ESP32 can connect to your network, set the ESP in station mode, and start Wi-Fi.<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>wifi_config_t wifi_config = {\n    .sta = {\n        .ssid = MY_ESP_WIFI_SSID,\n        .password = MY_ESP_WIFI_PASS,\n    },\n};\nESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));\nESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &amp;wifi_config));\nESP_ERROR_CHECK(esp_wifi_start());<\/code><\/pre>\n\n\n\n<p>Finally, start the web server:<\/p>\n\n\n\n<pre class=\"wp-block-code language-c\"><code>httpd_handle_t server = start_web_server();\nif (server) {\n    ESP_LOGI(TAG, \"Web Server initialized. Waiting for Wi-Fi connection...\");\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Build and Flash Code to the ESP32 Board<\/h2>\n\n\n\n<p>To build and flash ESP-IDF code to the ESP32, you always need to follow this procedure. You need to select the flash method (UART), the COM port number, the target device (ESP32), build the code, and finally, flash it to the board. All these commands are available in the bottom menu bar of VS Code.<\/p>\n\n\n\n<p>Make sure all your options are correct (they may already be properly configured if you used the project wizard).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"498\" height=\"28\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Check-All-the-Configured-Settings-UART-COM-Port-Target-Board.png?resize=498%2C28&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code ESP-IDF Check All the Configured Settings UART COM Port Target Board\" class=\"wp-image-170147\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Check-All-the-Configured-Settings-UART-COM-Port-Target-Board.png?w=498&amp;quality=100&amp;strip=all&amp;ssl=1 498w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Check-All-the-Configured-Settings-UART-COM-Port-Target-Board.png?resize=300%2C17&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 498px) 100vw, 498px\" \/><\/figure><\/div>\n\n\n<p>However, if your setup is not correct, follow the next instructions to ensure everything is set up correctly. First, click the &#8220;<strong>Star<\/strong>&#8221; icon and select the flash method as <strong>UART<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"584\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-Flash-UART-Option-to-Program-Flash-ESP32-1024x584.png?resize=1024%2C584&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code ESP-IDF Select Flash UART Option to Program Flash ESP32\" class=\"wp-image-170161\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-Flash-UART-Option-to-Program-Flash-ESP32.png?resize=1024%2C584&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-Flash-UART-Option-to-Program-Flash-ESP32.png?resize=300%2C171&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-Flash-UART-Option-to-Program-Flash-ESP32.png?resize=768%2C438&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-Flash-UART-Option-to-Program-Flash-ESP32.png?w=1030&amp;quality=100&amp;strip=all&amp;ssl=1 1030w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p>While the ESP32 board is connected to your computer, click the COM Port (plug icon) and select the correct port number that refers to your ESP32.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"582\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Programming-ESP32-Board-Select-Correct-COM-Port-Number.png?resize=1024%2C582&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code ESP-IDF Programming ESP32 Board Select Correct COM Port Number\" class=\"wp-image-170160\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Programming-ESP32-Board-Select-Correct-COM-Port-Number.png?resize=1024%2C582&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Programming-ESP32-Board-Select-Correct-COM-Port-Number.png?resize=300%2C171&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Programming-ESP32-Board-Select-Correct-COM-Port-Number.png?resize=768%2C437&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Programming-ESP32-Board-Select-Correct-COM-Port-Number.png?w=1032&amp;quality=100&amp;strip=all&amp;ssl=1 1032w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p>You also need to select the target device. Click on the chip icon at the bottom bar. In my case, I have an ESP32 with the <strong>esp32s3<\/strong> chip.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"579\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-the-ESP32-S3-or-Correct-Target-Device.png?resize=1024%2C579&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code Select the ESP32 S3 or Correct Target Device ESP-IDF\" class=\"wp-image-170163\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-the-ESP32-S3-or-Correct-Target-Device.png?resize=1024%2C579&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-the-ESP32-S3-or-Correct-Target-Device.png?resize=300%2C170&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-the-ESP32-S3-or-Correct-Target-Device.png?resize=768%2C434&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-the-ESP32-S3-or-Correct-Target-Device.png?w=1031&amp;quality=100&amp;strip=all&amp;ssl=1 1031w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<p>For this board, I also need to select the configuration: <strong>ESP32-S chip (via builtin USB-JTAG)<\/strong>.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"757\" height=\"579\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-the-ESP32-S3-chip-via-built-in-USB-JTAG-Target-Device.png?resize=757%2C579&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code ESP-IDF Select the ESP32 S3 chip via built in USB JTAG Target Device\" class=\"wp-image-170162\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-the-ESP32-S3-chip-via-built-in-USB-JTAG-Target-Device.png?w=757&amp;quality=100&amp;strip=all&amp;ssl=1 757w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Select-the-ESP32-S3-chip-via-built-in-USB-JTAG-Target-Device.png?resize=300%2C229&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 757px) 100vw, 757px\" \/><\/figure><\/div>\n\n\n<p>Finally, your command bar at the bottom of VS Code should have similar options selected.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"498\" height=\"28\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Check-All-the-Configured-Settings-UART-COM-Port-Target-Board.png?resize=498%2C28&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code ESP-IDF Check All the Configured Settings UART COM Port Target Board\" class=\"wp-image-170147\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Check-All-the-Configured-Settings-UART-COM-Port-Target-Board.png?w=498&amp;quality=100&amp;strip=all&amp;ssl=1 498w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Check-All-the-Configured-Settings-UART-COM-Port-Target-Board.png?resize=300%2C17&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 498px) 100vw, 498px\" \/><\/figure><\/div>\n\n\n<p>Now, you can build the project by clicking the wrench icon (<strong>Build Project<\/strong>) as shown in the image below.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"581\" height=\"359\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/VS-Code-Build-Project-Example-Code-ESP32-ESP-IDF.png?resize=581%2C359&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code Build Project Example Code ESP32 ESP-IDF\" class=\"wp-image-170743\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/VS-Code-Build-Project-Example-Code-ESP32-ESP-IDF.png?w=581&amp;quality=100&amp;strip=all&amp;ssl=1 581w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/VS-Code-Build-Project-Example-Code-ESP32-ESP-IDF.png?resize=300%2C185&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 581px) 100vw, 581px\" \/><\/figure><\/div>\n\n\n<p>The first time you build a project, it usually takes a bit more time. Once completed, it should print a similar message in the <strong>Terminal<\/strong> menu and show a &#8220;<strong>Build Successfully<\/strong>&#8221; message.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"648\" height=\"468\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/VS-Code-Build-Example-Project-ESP32-ESP-IDF-Success-Message.jpg?resize=648%2C468&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code Build Example Project ESP32 ESP-IDF Success Message\" class=\"wp-image-170742\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/VS-Code-Build-Example-Project-ESP32-ESP-IDF-Success-Message.jpg?w=648&amp;quality=100&amp;strip=all&amp;ssl=1 648w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/06\/VS-Code-Build-Example-Project-ESP32-ESP-IDF-Success-Message.jpg?resize=300%2C217&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 648px) 100vw, 648px\" \/><\/figure><\/div>\n\n\n<p>This is the final step. You can now flash the ESP-IDF project to the ESP32 by clicking the &#8220;<strong>Flash Device<\/strong>&#8221; button (thunder icon).<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"848\" height=\"170\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-World-Code-Project-to-ESP32-ESP-IDF.png?resize=848%2C170&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code Flash Hello World Code Project to ESP32 ESP-IDF\" class=\"wp-image-170294\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-World-Code-Project-to-ESP32-ESP-IDF.png?w=848&amp;quality=100&amp;strip=all&amp;ssl=1 848w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-World-Code-Project-to-ESP32-ESP-IDF.png?resize=300%2C60&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-World-Code-Project-to-ESP32-ESP-IDF.png?resize=768%2C154&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 848px) 100vw, 848px\" \/><\/figure><\/div>\n\n\n<p>Depending on your board, you might need to hold down the on-board BOOT button on your ESP32 to put it into flashing mode. Once the process is completed, it will pop-up a info message saying &#8220;<strong>Flash Done<\/strong>&#8220;.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"575\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-Wolrd-Project-to-ESP32-ESP-IDF-Done-Success-Message.png?resize=1024%2C575&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code Flash Hello World Project to ESP32 ESP-IDF Done Success Message\" class=\"wp-image-170155\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-Wolrd-Project-to-ESP32-ESP-IDF-Done-Success-Message.png?resize=1024%2C575&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-Wolrd-Project-to-ESP32-ESP-IDF-Done-Success-Message.png?resize=300%2C168&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-Wolrd-Project-to-ESP32-ESP-IDF-Done-Success-Message.png?resize=768%2C431&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Flash-Hello-Wolrd-Project-to-ESP32-ESP-IDF-Done-Success-Message.png?w=1039&amp;quality=100&amp;strip=all&amp;ssl=1 1039w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>If you followed all the steps, the example should be running successfully on your board. Open your Terminal window \u2014 click the &#8220;<strong>Monitor Device<\/strong>&#8221; tool that is illustrated with a screen icon.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"780\" height=\"77\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Open-Terminal-Window-Monitor-Device-ESP32-ESP-IDF.png?resize=780%2C77&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"VS Code Open Terminal Window Monitor Device ESP32 ESP-IDF\" class=\"wp-image-170157\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Open-Terminal-Window-Monitor-Device-ESP32-ESP-IDF.png?w=780&amp;quality=100&amp;strip=all&amp;ssl=1 780w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Open-Terminal-Window-Monitor-Device-ESP32-ESP-IDF.png?resize=300%2C30&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2025\/05\/VS-Code-Open-Terminal-Window-Monitor-Device-ESP32-ESP-IDF.png?resize=768%2C76&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 780px) 100vw, 780px\" \/><\/figure><\/div>\n\n\n<p>The ESP32 connects to Wi-Fi and prints its IP address on the Serial Monitor. Copy that IP address because you need it to access the ESP32 web server.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"862\" height=\"231\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Terminal-Demonstration.png?resize=862%2C231&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Simple Web Server Terminal Demonstration\" class=\"wp-image-190757\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Terminal-Demonstration.png?w=862&amp;quality=100&amp;strip=all&amp;ssl=1 862w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Terminal-Demonstration.png?resize=300%2C80&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Terminal-Demonstration.png?resize=768%2C206&amp;quality=100&amp;strip=all&amp;ssl=1 768w\" sizes=\"(max-width: 862px) 100vw, 862px\" \/><\/figure><\/div>\n\n\n<p><strong>Note:<\/strong> if nothing shows up on the Serial Monitor, press the ESP32 \u201cEN\u201d button (ENABLE\/RESET button next to the microUSB port).<\/p>\n\n\n\n<p>To access your web server in your local netowrk, open your browser and type the ESP32 IP address. You should see a similar web page being served by your ESP32.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"628\" height=\"385\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Web-Page-Demonstration.png?resize=628%2C385&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"ESP-IDF ESP32 Simple Web Server Demonstration Serve HTML Web Page\" class=\"wp-image-190761\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Web-Page-Demonstration.png?w=628&amp;quality=100&amp;strip=all&amp;ssl=1 628w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Web-Page-Demonstration.png?resize=300%2C184&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 628px) 100vw, 628px\" \/><\/figure><\/div>\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>In this tutorial, you learned how to program the ESP32 with the ESP-IDF framework using VS Code to run a simple web server that serves HTML pages to a client connected to your local network.<\/p>\n\n\n\n<p>In future tutorials, we&#8217;ll expand this project to created buttons to control the ESP32 GPIOs, and add fields to show the state of GPIOs or readings from sensors connected to the ESP32.<\/p>\n\n\n\n<p>You might find it helpful to read other ESP-IDF guides:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-idf-esp32-blink-led\/\">ESP-IDF: ESP32 Blink LED Example (VS Code)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-idf-esp32-gpio-pwm-ledc\/\">ESP-IDF: ESP32 GPIO PWM with LEDC (Control LED Brightness)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp-idf-esp32-gpio-analog-adc\/\">ESP-IDF: ESP32 GPIO \u2013 Read Analog Input (ADC \u2013 Analog to Digital Converter)<\/a><\/li>\n<\/ul>\n\n\n\n<p>Meanwhile, you can check our ESP32 resources (with Arduino IDE) to learn more about the ESP32 board:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-cam-projects-ebook\/\">Learn ESP32 with Arduino IDE (eBook)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/projects-esp-idf-esp32\/\">ESP-IDF: ESP32 Projects, Tutorials and Guides<\/a><\/li>\n<\/ul>\n\n\n\n<p>Thanks for reading.<\/p>\n\n\n\n<p>To learn more about creating ESP32 web servers (but using Arduino Core), we recommend exploring our eBook: <a href=\"https:\/\/randomnerdtutorials.com\/build-web-servers-esp32-esp8266-ebook\/\" title=\"\">Build Web Servers with ESP32 and ESP8266 (3rd Edition)<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This guide shows how to build a simple local web server with the ESP32 programmed with ESP-IDF that serves a simple HTML web page. This web page can then be &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP-IDF: ESP32 Simple Web Server (Serve HTML Page)\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp-idf-esp32-web-server\/#more-190643\" aria-label=\"Read more about ESP-IDF: ESP32 Simple Web Server (Serve HTML Page)\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":190971,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[327,328,264],"tags":[],"class_list":["post-190643","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp-idf","category-esp32-esp-idf","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2026\/03\/ESP-IDF-ESP32-Simple-Web-Server-Serve-HTML-Page.jpg?fit=1920%2C1080&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/190643","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=190643"}],"version-history":[{"count":20,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/190643\/revisions"}],"predecessor-version":[{"id":194049,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/190643\/revisions\/194049"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/190971"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=190643"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=190643"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=190643"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}