Node.js는 다음과 같은 구조를 가지고 있다.

libuv는 논블로킹 I/O와 이벤트 모델이 구현된 라이브러리이다. V8엔진은 크롬에 사용된 엔진이며, 동시에 뛰어난 자바스크립트 엔진이다. 이것이 Node.js를 매우 빠르고 효율적이게 만들어 준다. 그리고 Node.js의 Core 라이브러리가 존재하는데 이를 노드 코어라고 부른다. 노드 코어와 V8, libuv 라이브러리 사이에서 서로를 연결하고 사용 가능해주도록 바인딩하는 바인딩 세트가 존재하여 C/C++로 이뤄진 라이브러이와 엔진들과 자바스크립트가 서로 랩핑하고 사용할 수 있게 해주는 것이다. libuv을 살펴 보기 전 블로킹을 먼저 살펴본다.
*바인딩이란? 서로 묶어서 연결해준다는 의미. Core 라이브러리를 C++로 변환하여 V8과 libuv와 바인딩 시켜준다.
I/O는 입력과 출력을 의미하는데 이는 컴퓨터의 기본 동작 중 가장 느리다. RAM에 엑세스 하는데 걸리는 시간은 10E-9초(나노)이며, 디스크 또는 네트워크에 데이터에 엑세스 하는데 걸리는 시간은 10E-3초(밀리)이다. I/O는 일반적으로 CPU측면에서 비용이 많이 들지는 않으나 요청을 보낸 순간부터 작업이 완료되는 순간까지 지연을 동반한다. 전통적으로 블로킹 I/O 프로그래밍에서는 I/O 요청이 있을 때에 해당하는 함수 호출하여 작업이 완료될 때까지 스레드의 실행을 차단한다. 이러한 방식으로 구현된 웹 서버가 하나의 스레드에서 여러 요청을 처리 할 수 없게 되는데 이는 각 소켓에서의 모든 I/O작업이 다른 요청 처리를 차단 하기 때문이다. 이러한 이유로 웹 서버에서 동시성을 처리하기 위한 전통적인 처리 방식은 각 각의 동시성 요청에 대해 새로운 스레드 또는 프로세스를 시작하거나 풀에서 가져온 스레드를 재사용 하는 것이였다. 이렇게 하면 하나의 요청을 수행하는 스레드가 차단 되어도 다른 스레드에서 다른 요청을 처리하면 된다. 언듯 보면 좋은 방식으로 보이지만 이는 다름과 같은 문제점이 야기되는데, 첫번째로 동시적으로 들어올 최대 요청을 미리 생각해서 하드웨어를 구축해놔야 한다는 것이다. 만약 이 예상한 최대 요청을 초과할 경우에는 결국 서버는 감당하지 못하게 된다. 또한 금액도 매우 많이 필요하다. 두번째로는 최대 요청의 예상보다 낮은 요청들만 이뤄질 경우 리소드들은 계속 대기만 하며 자원을 낭비하는 형태가 된다. 한마디로 놀고 있다는 것이다. 이러한 문제점들을 해결하기 위하여 Node.js는 논블로킹 I/O방식으로 이뤄져 있다.
현대의 최신의 운영체제는 논 블로킹 I/O로 이뤄져 있다. 리소스를 엑세스하는 또 다른 메커니즘을 지원하는 것인데, 이 운영 모드에서 시스템 호출은 데이터가 읽히거나 쓰여질 때까지 기다리지 않고 항상 즉시 반환된다. 호출하는 순간에 결과를 사용할 수 없는 경우, 이 함수는 단순히 미리 정의된 상수를 반환하고, 그 순간 반환할 수 있는 데이터가 없음을 나타낸다.
가령 유닉스 운영체제에서 읽어낼 준비가 된 데이터가 없을 경우에 실패를 알려 대기 상태에 머물지 않도록 한다. 이러한 종류의 논 블로킹 I/O에 엑세스 하는 가장 기본적인 패턴은 실제 데이터가 반환횔 때까지 루프 내에서 리소를 적극적으로 폴링하는 것인데, 이것은 busy-waiting이라고 한다.
이 기술로 동일한 스레드에서 서로 다른 리소스를 처리할 수 있지만 이 상태로는 효율적이지 않다. 왜냐하면 이럴 경우 대부분 사용할 수 없는 리소스를 계속 반복하는데 CPU를 사용하게 되기 때문이다.
하지만 다행스럽게도 Busy-wating이 이상적인 논블로킹 알고리즘은 아니나 대부분 최신 운영체제는 효율적인 논 블로킹 리소스 처리를 위한 기본적인 매커니즘을 제공 하고 있는데 동기 이벤트 디멀티플렉서 와 이벤트 통지 인터페이스가 그것이다.
이 구성 요소는 감시된 일련의 리소스들로부터 I/O 이벤트들을 수집하여 큐에 넣고 처리할 수 있는 새 이벤트가 있을 때까지 차단한다. 이것을 이벤트 루프라고 하는데 다음의 과정을 거친다.
