In this guide, you’ll learn how to set and control the ESP32 board’s GPIO pins as digital outputs with ESP-IDF (Espressif IoT Development Framework).
The ESP32 is a microcontroller that offers several General Purpose Input/Output (GPIO) pins that can be configured as either inputs or outputs. With the GPIOs set as outputs, you can control devices like LEDs, relays, motors, or other components by setting the pin’s voltage level to HIGH (3.3V) or LOW (0V).

Prerequisites
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’t already:
You will also need an ESP32 development board model of your choice.
ESP32 GPIO Digital Outputs
In ESP-IDF, to set the ESP32 GPIOs as digital outputs, you need to do the following.
First, you need to configure the GPIO pins: assign the pin number, set the mode, enable/disable pull-up or pull-down internal resistors, and enable/disable interrupts.
For example, to control an LED, define the gpio_config() function using the following structure:
#define LED_PIN 2
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LED_PIN), // Select GPIO 2
.mode = GPIO_MODE_OUTPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
gpio_config(&io_conf);
Then, you set the level of the GPIO you want to control (either 1 = HIGH or 0 = LOW). Use the gpio_set_level() function as follows:
gpio_set_level(LED_PIN, 1);
gpio_set_level(LED_PIN, 0);
gpio_config_t structure
Public Member | Value |
uint64_t pin_bit_mask | GPIO pin set with bit mask, for example: (1ULL << 2) |
gpio_mode_t mode | GPIO_MODE_DISABLE, GPIO_MODE_INPUT, GPIO_MODE_OUTPUT, GPIO_MODE_OUTPUT_OD, GPIO_MODE_INPUT_OUTPUT_OD, GPIO_MODE_INPUT_OUTPUT |
gpio_pullup_t pull_up_en | GPIO_PULLUP_DISABLE, GPIO_PULLUP_ENABLE |
gpio_pulldown_t pull_down_en | GPIO_PULLDOWN_DISABLE, GPIO_PULLDOWN_ENABLE |
gpio_int_type_t intr_type | GPIO_INTR_DISABLE, GPIO_INTR_POSEDGE, GPIO_INTR_NEGEDGE, GPIO_INTR_ANYEDGE, GPIO_INTR_LOW_LEVEL, GPIO_INTR_HIGH_LEVEL, GPIO_INTR_MAX |
All GPIOs can be used as outputs except GPIOs 6 to 11 (connected to the integrated SPI flash) and GPIOs 34, 35, 36, and 39 (input-only GPIOs).
Learn more about the ESP32 GPIOs: ESP32 GPIO Reference Guide.
Creating an ESP-IDF Template App Project for the ESP32
The ESP-IDF extension provides an easy way to create a project from scratch with all the required files and configurations generated automatically.
To create a new ESP-IDF project on VS Code, follow these steps:
- Open the ESP-IDF Espressif extension
- Expand the “Advanced” menu
- Click the “New Project Wizard” option
- Choose the “Use ESP-IDF v5.4.1” to select the framework version

A new window opens, you need to fill in these fields:
- Project Name: type the desired project name;
- Enter Project Directory: click the folder icon and select the target folder to save all your project files. You can use any directory. Note: do NOT use a Google Drive / One Drive / Dropbox folder, because it will write/create many files during the building process—if it’s on a cloud folder, this process might be extremely slow;
- ESP-IDF Target: select the target device chip, I’m using an ESP32 with the esp32s3 chip;
- ESP-IDF Board: for the esp32s3 chip, I also need to select the configuration: ESP32-S chip (via builtin USB-JTAG);
- Serial Port: while having your ESP32 board connected to your computer, select the correct COM port number that refers to your ESP32;
- Choose Template: click the blue button to create a new project using a template.

In the menu, select the “template-app” sample project and press the “Create project using template template-app” button.

Opening the ESP-IDF Project on VS Code
After a few seconds, a small notification will appear at the bottom right corner of VS Code. You can click “Yes” to open the newly created ESP-IDF project template.

IMPORTANT: if you didn’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:
Go to File > Open Folder…

Browse on your computer for the esp-idf-project folder (your project folder name that you’ve previously defined) and “Select Folder“.

That’s it! Your new ESP-IDF project template has been successfully created and opened.
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 main.c file.
The example codes will be written in the main.c file. To open it, follow these instructions:
- Open the project explorer by clicking the first icon on the left sidebar.
- Select your project folder name, in my case it’s “ESP-IDF-PROJECT“.
- Expand the “main” folder.
- Click the “main.c” file.
- The default main.c template file loads in the code window.

Example #1: Blink ESP32 LED with ESP-IDF gpio_config()
Here’s the full main.c code that blinks the ESP32 on-board LED using the gpio_config() function:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp-idf-esp32-gpio-outputs/
*/
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#include "sdkconfig.h"
// Define the GPIO pin for the LED (GPIO 2 is common for onboard LEDs)
#define LED_PIN 2
void app_main(void)
{
// Configure GPIO
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LED_PIN), // Select GPIO 2
.mode = GPIO_MODE_OUTPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
gpio_config(&io_conf);
// Blink loop
while (1) {
// Turn LED ON
printf("LED ON\n");
gpio_set_level(LED_PIN, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
// Turn LED OFF
printf("LED OFF\n");
gpio_set_level(LED_PIN, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
}
}
How the Code Works
In this section, we’ll take a look at the code to see how it works.
Libraries
We start by including the required libraries:
- stdio.h – the standard C library will be used for the printf function that prints the debugging information in the serial monitor;
- FreeRTOS.h – provides the core FreeRTOS types and functions;
- task.h – allows to use of the non-blocking delay function vTaskDelay;
- driver/gpio.h – includes the functions required to configure and control GPIOs;
- sdkconfig.h – includes the project’s configuration file.
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#include "sdkconfig.h"
Pin Assignment
This line assigns the on-board LED to GPIO 2; you can change it to a different number to match your board pinout or to control a different GPIO.
#define LED_PIN 2
app_main(void)
When creating an ESP-IDF project, this 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 setup() in Arduino programming. When the ESP32 boots, the ESP-IDF framework calls app_main.
void app_main(void)
{
// your code goes here
}
In the app_main(void) function, you start by creating the GPIO config variable:
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LED_PIN), // Select GPIO 2
.mode = GPIO_MODE_OUTPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
Then, call the gpio_config(&io_conf) function to configure the GPIO as an output, because we want to control its state with HIGH/LOW.
gpio_config(&io_conf);
The while(1) runs an infinite loop that ensures the LED will be blinking indefinitely. This is similar to the loop() function in Arduino programming.
while (1) {
// Turn LED ON
printf("LED ON\n");
gpio_set_level(LED_PIN, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
// Turn LED OFF
printf("LED OFF\n");
gpio_set_level(LED_PIN, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
};
Inside the infinite loop, you print a message saying “LED ON” in the Serial Monitor/Terminal tab.
printf("LED ON\n");
Set the LED_PIN level to 1 (it’s like setting to HIGH to turn the LED on).
gpio_set_level(LED_PIN, 1);
Then, add a delay of 1000 milliseconds (1 second), so the LED is ON for 1 second before you turn it off to create the blink effect.
vTaskDelay(1000 / portTICK_PERIOD_MS);
A similar process is repeated to turn the LED off.
// Turn LED OFF
printf("LED OFF\n");
gpio_set_level(LED_PIN, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
Build and Flash Code to the ESP32 Board
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.
Make sure all your options are correct (they may already be properly configured if you used the project wizard).

However, if your setup is not correct, follow the next instructions to ensure everything is set up correctly. First, click the “Star” icon and select the flash method as UART.

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.

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 esp32s3 chip.

For this board, I also need to select the configuration: ESP32-S chip (via builtin USB-JTAG).

Finally, your command bar on the bottom of VS Code should have similar options selected.

Now, you can build the project by clicking the wrench icon (Build Project) as shown in the image below.

The first time you build a project, it usually takes a bit more time. Once completed, it should print a similar message in the Terminal menu and show a “Build Successfully” message.

This is the final step. You can now flash the ESP-IDF project to the ESP32 by clicking the “Flash Device” button (thunder icon).

Depending on your board, you might need to hold down the on-board BOOT button on your ESP32 to put into flashing mode. Once the process is completed, it will pop-up a info message saying “Flash Done“.

Demonstration
If you followed all the steps, the Blinking Code example should be running successfully on your board. Open your Terminal window — click the “Monitor Device” tool that is illustrated with a screen icon.

The terminal should be printing a message saying “LED ON” and “LED OFF“. This process is repeated indefinitely.

Your board is now running a basic LED blinking example. It will turn on GPIO 2 (blue LED labelled as IO2 in this particular board) for 1 second.

Then, it will turn it off for 1 second.

Example #2: Simple Blink LED with ESP-IDF
Instead of using the gpio_config() function with a gpio_config_t structure, you can also control an output by simply resetting the pin and set the direction to output. Here’s the full main.c code that blinks the ESP32 on-board LED:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp-idf-esp32-blink-led/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
// Define the GPIO pin for the LED (GPIO 2 is common for onboard LEDs)
#define BLINK_GPIO 2
void app_main(void)
{
// Configure the GPIO pin
gpio_reset_pin(BLINK_GPIO);
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
// Blink loop
while (1) {
// Turn LED ON
printf("LED ON\n");
gpio_set_level(BLINK_GPIO, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
// Turn LED OFF
printf("LED OFF\n");
gpio_set_level(BLINK_GPIO, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
}
}
How the Code Works
Libraries
We start by including the required libraries as shown in the previous example:
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#include "sdkconfig.h"
Pin Assignment
This line assigns the on-board LED to GPIO 2; you can change it to a different number to match your board pinout or to control a different GPIO.
#define BLINK_GPIO 2
app_main(void)
Inside the app_main(void) function, you start by clearing the previous configurations for the BLINK_GPIO:
gpio_reset_pin(BLINK_GPIO);
You configure the BLINK_GPIO as an output, because we want to control its state with HIGH/LOW.
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
The while(1) runs an infinite loop that ensures the LED will be blinking indefinitely.
while (1) {
// Turn LED ON
printf("LED ON\n");
gpio_set_level(BLINK_GPIO, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
// Turn LED OFF
printf("LED OFF\n");
gpio_set_level(BLINK_GPIO, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS); // Delay 1 second
};
You can build and flash the code into your ESP32, and it should run exactly as illustrated in example #1.
Example #3: Control Multiple ESP32 GPIOs with ESP-IDF
If you want to declare and configure multiple GPIOs at once, I recommend using the gpio_config() function with a gpio_config_t structure as shown in example #1. Here’s the full main.c code that turns 3 GPIO pins of the ESP32 on and off:
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
https://RandomNerdTutorials.com/esp-idf-esp32-gpio-outputs/
*/
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#include "sdkconfig.h"
#define LED_PIN_1 2
#define LED_PIN_2 4
#define LED_PIN_3 5
void app_main(void)
{
// Configure multiple GPIOs
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LED_PIN_1) | (1ULL << LED_PIN_2) | (1ULL << LED_PIN_3),
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE
};
gpio_config(&io_conf);
while (1) {
// Turn all LEDs ON
gpio_set_level(LED_PIN_1, 1);
gpio_set_level(LED_PIN_2, 1);
gpio_set_level(LED_PIN_3, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Turn all LEDs OFF
gpio_set_level(LED_PIN_1, 0);
gpio_set_level(LED_PIN_2, 0);
gpio_set_level(LED_PIN_3, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
How the Code Works
Libraries
First, include the required libraries:
#include <stdio.h>
#include <freertos/FreeRTOS.h>
#include <freertos/task.h>
#include <driver/gpio.h>
#include "sdkconfig.h"
Pin Assignment
This line assigns the 3 pins to GPIO 2, GPIO 4, and GPIO 5.
#define LED_PIN_1 2
#define LED_PIN_2 4
#define LED_PIN_3 5
app_main(void)
In the app_main(void) function, you start by creating the GPIO config variable:
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << LED_PIN_1) | (1ULL << LED_PIN_2) | (1ULL << LED_PIN_3),
.mode = GPIO_MODE_OUTPUT, // Set as output
.pull_up_en = GPIO_PULLUP_DISABLE, // Disable pull-up
.pull_down_en = GPIO_PULLDOWN_DISABLE, // Disable pull-down
.intr_type = GPIO_INTR_DISABLE // Disable interrupts
};
Then, call the gpio_config(&io_conf) function to configure all 3 GPIOs as outputs.
gpio_config(&io_conf);
The while(1) runs an infinite loop that ensures the LEDs will be blinking indefinitely.
while (1) {
// Turn all LEDs ON
gpio_set_level(LED_PIN_1, 1);
gpio_set_level(LED_PIN_2, 1);
gpio_set_level(LED_PIN_3, 1);
vTaskDelay(1000 / portTICK_PERIOD_MS);
// Turn all LEDs OFF
gpio_set_level(LED_PIN_1, 0);
gpio_set_level(LED_PIN_2, 0);
gpio_set_level(LED_PIN_3, 0);
vTaskDelay(1000 / portTICK_PERIOD_MS);
};
Schematic Diagram
Here’s a list of the parts you need to build the circuit:
Connect 3 LEDs to GPIO 2, GPIO 4, and GPIO 5 as shown in the schematic diagram below.

You can build and flash the code into your ESP32. This code turns all 3 connected LEDs on and off continuously.

Wrapping Up
In this tutorial, you learned how to program the ESP32 with the ESP-IDF framework using VS Code to control the GPIOs as digital outputs. In the next guide, we’ll cover ESP-IDF GPIO Inputs.
Other ESP-IDF guides:
- Programming ESP32 with ESP-IDF using VS Code – Getting Started Guide
- ESP-IDF: ESP32 Blink LED Example (VS Code)
Meanwhile, you can check our ESP32 resources (with Arduino IDE) to learn more about the ESP32 board:
Thanks for reading.
I have been curious about IDF for some time. I understand that it gives you more granular control over the ESP32. It appears to be more verbose than Arduino ide thou. Have you used it enough to be comfortable with it? If so, which one do you prefer for common projects? Are you planing to expand this topic?
Thanks for sharing.
Wow, thanks Rui for this tutorial on ESP-IDF in VCS. I have to comment that, compared to PlatformIO in VCS, the code looks quite bulky and a bit obscure to just turn on/off an LED ! … something more complex (e.g. webserver) must be incomprehensible to all but software engineeers ! … I suppose that is the cost of getting access to the latest devices.