Nnextop / app

What is NextOP?

NextOP bundles Next.js + Electron to build desktop applications for the React ecosystem. The goal is to combine the Next.js developer experience (App Router, SSR, Server Components, API routes, next/image) with Electron's native capabilities (filesystem, shell, notifications, clipboard, secure storage, native menus, multi-window).

The fullstack React framework for the desktop. Real Next.js on the inside, a native Electron shell on the outside.

  • Repository: github.com/FlyingTurkman/nextop-app
  • Packages: create-nextop-app (scaffolder), nextop-app (runtime library + nextop CLI)
  • Status: early / experimental — 1.0.0 line, API may still change.
  • Platform focus: Windows (PowerShell). macOS/Linux work but are less validated.

The key idea: a live Next.js server, not a static export

NextOP does not statically export Next.js. Instead it runs a live Next.js HTTP server inside the Electron main process:

Electron app.whenReady()
→ startNextServer(): next({ dir, dev }) + http.createServer → 127.0.0.1:<port>
→ BrowserWindow.loadURL("http://127.0.0.1:<port>")

Consequence: every Next.js feature works — App Router, SSR, Server Components, Route Handlers, Server Actions, middleware, next/image. This is the differentiator versus static-export-based desktop wrappers.

Cost: Chromium + Node + a live Next server is the heaviest runtime profile among comparable frameworks. This weight is inherent to the design, not a bug.

Same runtime model for dev and production

main.ts runs the Next server in-process for both modes:

  • devnext({ dir: process.cwd(), dev: true })
  • productionnext({ dir: app.getAppPath(), dev: false }) against the prebuilt .next output.

The server binds to 127.0.0.1 only (never the LAN), and loadURL uses 127.0.0.1 to match (avoiding IPv4/IPv6 mismatch). Port preference is 3000, falling back to an OS-assigned free port on EADDRINUSE (race-free — the server binds the port itself and reports the actual one).