RSS듀오랩스

Next.js와 Electron 비교: 같은 React, 다른 실행 구조

Electron글: , Duolabs12분 읽기blogelectronnextjsreacttechnical-note

Next.js와 Electron은 둘 다 JavaScript와 TypeScript, React 생태계를 활용합니다. 화면만 만들 때는 꽤 비슷해 보입니다. 컴포넌트를 나누고 상태를 관리하며, npm 패키지를 설치하고 개발자 도구로 화면을 확인하는 흐름도 익숙합니다.

저도 처음 두 기술을 나란히 놓았을 때는 React 코드를 얼마나 공유할 수 있는지가 가장 중요한 차이라고 생각했습니다. 그런데 실행 구조와 보안, 배포까지 범위를 넓혀 정리해 보니 더 중요한 경계가 보였습니다. Next.js는 서버와 브라우저를 전제로 하지만, Electron은 사용자 컴퓨터에 설치되어 운영체제 권한을 다룹니다.

이 차이를 모르고 화면 개발 방식만 옮기면 Electron의 Main 프로세스에 코드가 몰리거나, 반대로 Renderer에 필요 이상의 권한을 열어 주기 쉽습니다.

한 문장으로 구분해 보았습니다

Next.js는 React 기반의 풀스택 웹 애플리케이션 프레임워크입니다. 일반적으로 서버나 CDN에서 콘텐츠를 전달하고, 사용자는 브라우저에서 URL로 접근합니다. 정적 내보내기처럼 서버가 필요 없는 배포 방식도 있지만 제품의 기본 단위는 웹 애플리케이션입니다.

Electron은 Chromium과 Node.js를 함께 사용해 Windows, macOS, Linux용 데스크톱 애플리케이션을 만드는 런타임입니다. 사용자는 앱을 내려받아 설치하고, 앱은 로컬 파일과 창, 메뉴, 알림 같은 운영체제 기능을 사용할 수 있습니다.

구분 Next.js Electron
주요 실행 위치 서버와 웹 브라우저 사용자 컴퓨터
배포 단위 웹 서버 또는 정적 파일 운영체제별 앱과 설치 파일
사용자 업데이트 서버 배포 후 새로 접속하면 반영됩니다 설치된 앱을 업데이트해야 합니다
권한 범위 브라우저가 허용한 기능을 사용합니다 Main 프로세스에서 OS 기능을 사용할 수 있습니다
주요 통신 HTTP, Route Handler, Server Action IPC, 로컬 파일, 원격 API
운영 관심사 응답 속도, 캐시, SEO, 서버 부하 시작 속도, 메모리, 서명, 설치, 자동 업데이트

화면 개발이 비슷한 이유

React를 사용하는 Electron 프로젝트라면 Next.js에서 익힌 상당 부분을 그대로 활용할 수 있습니다.

  • React 컴포넌트와 Custom Hook을 사용할 수 있습니다.
  • TypeScript로 도메인 타입과 입력값 검증 규칙을 공유할 수 있습니다.
  • CSS와 디자인 토큰, 아이콘, UI 컴포넌트를 재사용할 수 있습니다.
  • ESLint, Prettier, Vitest 같은 개발 도구를 함께 사용할 수 있습니다.
  • npm workspace나 모노레포로 웹과 데스크톱 앱을 관리할 수 있습니다.

버튼, 입력 폼, 모달, 테이블을 만드는 일만 보면 두 환경의 차이는 크지 않습니다. 그래서 Next.js 개발자가 Electron Renderer 화면을 만드는 데 적응하는 시간은 비교적 짧습니다.

문제는 화면 뒤에서 시작됩니다.

Server와 Main은 비슷해 보여도 같은 역할이 아닙니다

Electron은 Chromium과 비슷한 다중 프로세스 모델을 사용합니다. 보통 앱의 생명주기와 운영체제 기능을 담당하는 Main 프로세스가 하나 있고, BrowserWindow마다 화면을 담당하는 Renderer 프로세스가 생깁니다. Renderer가 제한된 데스크톱 기능을 사용하도록 연결하는 Preload 스크립트도 있습니다.

개념을 익히는 용도로는 다음처럼 대응해 볼 수 있습니다.

Next.js Electron 설명
Client Component Renderer 사용자가 보는 화면을 담당합니다
서버 코드 또는 Route Handler Main 프로세스 권한이 필요한 작업을 처리합니다
브라우저와 서버 사이의 요청 IPC 서로 다른 실행 영역을 연결합니다
브라우저에 공개된 API Preload가 공개한 API 화면에서 허용된 기능만 사용하게 합니다

다만 이것은 이해를 돕기 위한 비유일 뿐입니다. Next.js 서버는 여러 사용자의 요청을 처리하지만 Electron의 Main 프로세스는 한 사용자의 컴퓨터에서 실행됩니다. Main 프로세스는 데이터 요청뿐 아니라 앱 종료, 창 생성, 메뉴, 트레이, 단축키 같은 데스크톱 생명주기까지 책임집니다.

HTTP 대신 IPC 경계를 설계해야 합니다

Next.js에서는 브라우저가 서버에 요청하고 서버가 인증과 권한을 검사합니다. Electron에서는 Renderer가 Main 프로세스에 IPC 요청을 보내는 경우가 많습니다.

처음에는 Renderer에서 Node.js와 파일 시스템을 바로 사용하면 편해 보입니다. 하지만 화면에 운영체제 권한을 그대로 주면 작은 스크립트 취약점도 로컬 파일 접근이나 프로세스 실행 문제로 커질 수 있습니다.

그래서 저는 Electron의 Preload를 API 관문으로 이해하는 편이 좋다고 봅니다. 파일 시스템 전체를 공개하지 않고 사용자가 실제로 수행해야 하는 동작만 좁게 노출합니다.

contextBridge.exposeInMainWorld("desktop", {
  chooseFile: () => ipcRenderer.invoke("dialog:choose-file"),
});

Renderer는 공개된 기능만 호출합니다.

const file = await window.desktop.chooseFile();

Main 프로세스에서는 IPC 발신자와 입력값을 다시 검증해야 합니다. Renderer에서 이미 검증했더라도 권한 경계의 반대편에서 한 번 더 확인하는 것이 안전합니다.

Electron 공식 보안 가이드는 원격 콘텐츠에 Node.js 통합을 활성화하지 않고, Context Isolation과 샌드박스를 사용하며, IPC 발신자를 검증할 것을 권장합니다. Renderer에 ipcRenderer 자체를 공개하기보다 목적이 분명한 기능만 contextBridge로 전달해야 합니다.

데이터가 저장되는 위치도 달라집니다

Next.js에서는 보통 서버 데이터베이스가 데이터의 기준이 됩니다. 로그인 상태와 권한, 여러 사용자의 동시 수정도 서버에서 관리합니다.

Electron은 사용자 컴퓨터에 설정과 데이터를 저장할 수 있습니다. 간단한 설정은 앱 데이터 디렉터리에 저장하고, 구조화된 데이터는 SQLite 같은 로컬 데이터베이스로 관리할 수 있습니다. 인증 토큰처럼 민감한 정보는 일반 파일보다 macOS Keychain이나 Windows Credential Manager처럼 운영체제가 제공하는 보안 저장소를 검토하는 편이 좋습니다.

로컬 저장은 오프라인 동작에 유리하지만 다른 숙제가 생깁니다.

  • 사용자가 컴퓨터를 교체할 때 데이터를 어떻게 옮길지 정해야 합니다.
  • 여러 기기에서 수정한 내용을 어떻게 동기화할지 설계해야 합니다.
  • 앱 버전에 따른 로컬 데이터 마이그레이션이 필요합니다.
  • 새 버전을 되돌렸을 때 데이터 형식이 호환되는지 확인해야 합니다.

웹에서는 서버가 맡던 문제의 일부가 Electron에서는 각 사용자 컴퓨터로 이동합니다.

URL 라우팅에 창의 생명주기가 더해집니다

Next.js는 URL이 화면 구조의 중심입니다. 페이지와 레이아웃을 URL에 맞춰 구성하고, 사용자는 브라우저의 뒤로 가기와 앞으로 가기를 사용합니다.

Electron에서도 React Router 같은 도구로 화면을 나눌 수 있습니다. 여기에 데스크톱 앱 특유의 상태가 추가됩니다.

  • 여러 BrowserWindow를 열 수 있습니다.
  • 메인 창을 닫아도 트레이에서 앱을 계속 실행할 수 있습니다.
  • 메뉴나 전역 단축키로 창을 열 수 있습니다.
  • 파일 연결이나 커스텀 프로토콜로 앱을 실행할 수 있습니다.
  • 운영체제별로 창을 닫는 동작과 앱을 종료하는 동작이 다를 수 있습니다.

웹 라우팅만 생각하면 창은 닫혔는데 프로세스가 남거나, 반대로 보조 창을 닫았을 때 앱 전체가 종료되는 문제가 생길 수 있습니다. Electron에서는 화면 경로와 별도로 앱과 창의 생명주기를 설계해야 합니다.

성능을 판단하는 기준도 달라집니다

Next.js에서는 서버 응답 시간, LCP와 CLS, JavaScript 번들 크기, 검색 노출, 캐시 효율을 주로 확인합니다.

Electron에서는 다음 항목도 중요해집니다.

  • 앱을 실행하고 첫 화면이 나타나는 시간
  • 앱을 켜 둔 상태의 기본 메모리 사용량
  • 설치 파일과 업데이트 파일의 크기
  • 새 창이 열리는 시간
  • Main과 Renderer 사이의 IPC 호출량
  • 네이티브 모듈의 플랫폼별 호환성

Electron은 Chromium과 Node.js를 포함하므로 단순한 화면만 있는 앱도 일반 웹페이지보다 설치 크기와 메모리 사용량이 커질 수 있습니다. 시작할 때 모든 창과 데이터를 미리 준비하기보다는 필요한 시점에 로드하는 구조가 나을 때가 많습니다.

배포에서 차이가 가장 크게 드러납니다

Next.js는 서버를 새 버전으로 배포하면 사용자가 다음 접속부터 변경된 버전을 받습니다. 문제가 있으면 서버 배포를 되돌릴 수 있습니다.

Electron은 사용자 컴퓨터마다 앱이 설치됩니다. 따라서 Windows와 macOS 설치 파일, CPU 아키텍처, 코드 서명, macOS 공증, 자동 업데이트를 직접 관리해야 합니다. 새 서버 API와 몇 달 전 앱이 함께 동작하는 상황도 고려해야 합니다.

화면 개발은 웹과 닮았지만 배포 이후의 운영은 모바일 앱에 더 가까운 부분이 있습니다.

공유할 코드와 분리할 코드를 나누었습니다

Next.js 웹과 Electron 앱을 함께 만든다면 다음과 같은 모노레포 구조를 생각할 수 있습니다.

apps/
  web/
  desktop/

packages/
  ui/
  domain/
  validation/
  api-client/
  design-tokens/

UI 컴포넌트와 도메인 타입, 검증 스키마, API 클라이언트는 비교적 공유하기 좋습니다. 반면 Next.js 서버에 종속된 코드와 Electron Main 또는 Preload 코드는 명확하게 분리하는 편이 좋습니다.

공유율을 높이는 것 자체를 목표로 삼으면 실행 환경의 차이를 숨기게 됩니다. 저는 공유 가능한 순수 로직은 모으고, 권한과 생명주기를 다루는 코드는 각 앱에 남기는 구조가 더 읽기 쉽다고 봅니다.

무엇을 선택할지 판단하는 기준

설치 없이 URL로 접근해야 하고 검색 노출과 여러 기기에서의 접근이 중요하다면 Next.js가 자연스럽습니다.

다음 요구가 제품의 중심이라면 Electron을 검토할 만합니다.

  • 인터넷 연결 없이도 주요 기능이 동작해야 합니다.
  • 로컬 파일을 많이 읽거나 변환해야 합니다.
  • 트레이와 운영체제 메뉴, 단축키가 필요합니다.
  • 장시간 백그라운드에서 작업해야 합니다.
  • 하드웨어나 다른 데스크톱 프로그램과 연동해야 합니다.
  • 여러 창을 사용하는 데스크톱 작업 흐름이 중요합니다.

두 기술을 함께 사용할 수도 있습니다. Next.js로 웹 서비스와 API를 운영하고 Electron을 데스크톱 클라이언트로 제공하는 방식입니다. 이때 React와 도메인 로직은 공유하되, 웹과 데스크톱의 권한 경계와 배포 주기는 별도로 설계해야 합니다.

이 글을 정리하고 나니 Next.js 개발자가 Electron을 시작할 때 새로 배워야 할 핵심은 React가 아니었습니다. Main, Preload, Renderer의 경계와 설치 이후의 업데이트 과정이었습니다. 다음 글에서는 이 가운데 배포 과정을 Windows와 macOS로 나누어 정리하겠습니다.

마지막 수정:

공유하실 때는 출처(Duolabs)와 원문 주소를 표시해 주세요.