Click Below to Get the Code

Browse, clone, and build from real-world templates powered by Harper.
Tutorial
GitHub Logo

Trials and Tribulations of Self‑Hosting Next.js

Discover what it really takes to self-host Next.js beyond just running next start. Learn how Harper reimagined the entire Next.js lifecycle. Develop, Build, Deploy, and Run, to support clustered, bare-metal environments with hot reload, rolling deploys, multi-zone support, and more.
Tutorial

Trials and Tribulations of Self‑Hosting Next.js

Ethan Arrowood
Head of Open Source
at Harper
June 24, 2025
Ethan Arrowood
Head of Open Source
at Harper
June 24, 2025
Ethan Arrowood
Head of Open Source
at Harper
June 24, 2025
June 24, 2025
Discover what it really takes to self-host Next.js beyond just running next start. Learn how Harper reimagined the entire Next.js lifecycle. Develop, Build, Deploy, and Run, to support clustered, bare-metal environments with hot reload, rolling deploys, multi-zone support, and more.
Ethan Arrowood
Head of Open Source
Co-authored by Austin Akers


next start” Isn’t Enough

We love Next.js. It’s an incredible framework for building modern web apps with React. But the moment you try to self‑host it—especially on bare metal or in clustered environments—you quickly learn that serverless hosts are doing a lot of heavy lifting.

We faced this firsthand at Harper, a platform that fuses a database, networking stack, and application runtime into one high‑performance Node.js engine. So, we asked: What does it really take to self‑host Next.js inside Harper? Spoiler: it’s way more than running next start.

This is the story of how we reimagined the Next.js lifecycle—Develop, Build, Deploy, and Run— within our platform.

Develop: Rebuilding next dev Internally

The Next.js dev server is magic. Hot Module Reloading (HMR), Fast Refresh, error overlays—everything just works. To replicate that inside Harper, we built:

  • A WebSocket-aware upgrade handler to inject hot-reload support into the Harper middleware.
  • A CLI wrapper, harperdb-nextjs dev, which boots Harper and then spins up a Next.js dev server with all the right wiring.
  • Seamless Hot Module Reloading via shared WebSocket channels between client and server.
Sequence diagram showing how HMR updates modules in the browser via WebSocket after file changes are detected by the dev server.

We dove deep into how WebSocket upgrades work in Node and exposed just enough of Harper’s networking stack to give Next.js what it needed.

Build: One Thread to Rule Them All

Harper is multi-threaded. So if we weren’t careful, every thread would build the app independently. Our fix:

  • Thread-locking to ensure only one thread triggers a build.
  • Shared artifact storage so other threads can reuse the output.
  • A harperdb-nextjs build command to kick off clean, single-threaded builds.
Flowchart detailing how threads manage file locks, handle stale states, and coordinate build execution to prevent concurrent access.

This let us avoid the explosion of duplicate builds while preserving concurrency where it matters.

Deploy: Rolling Your Own (Literally)

Production Harper instances often run as clustered nodes, replicated across regions. Replacing all of them at once? A disaster waiting to happen.

Instead, we built rolling deployment support, one node at a time:

  • Nodes take turns building and restarting.
  • Traffic shifts around them.
  • Zero downtime. Full data consistency.
Illustrates a rolling deployment strategy where updates are gradually applied across server groups while maintaining service availability and performance monitoring.

And the best part? This isn't just for Next.js—it's the same deploy system Harper uses for all components.

Run: Programmatic Next.js + Middleware Wizardry

We don’t use next start. Instead, we load Next.js programmatically:

const app = next({ dir: componentPath, dev: false });
await app.prepare();

Then we inject the request and WebSocket handlers directly into Harper’s middleware. This unlocks some wild capabilities:

  • Dynamic version loading: We require.resolve() the right Next.js version from the app’s package.json.
  • Multi-zone hosting: Several Next.js apps, each at different paths, running in one Harper process.
Shows how Harper routes client requests to zone-specific handlers and components using HTTP middleware across blog, store, and root apps.

This allows enterprise users to collapse complex micro-frontend setups into a single runtime—no hops, no hard navigation.

The Tricky Bits: Working Directory Problem

Next.js handles dynamic paths well. But some React tools assume process.cwd() reflects their app’s root. When you’re running multiple apps in one process, that assumption breaks.

We didn’t find a silver bullet here. Instead, we emphasize:

  • Explicit paths over relative ones.
  • Avoiding tools that depend on working directory voodoo.

It’s manageable—but worth flagging if you try this approach.

What’s Next? (Yes, Pun Intended)

We’re not done. Here’s what we’re working on now:

  • Smarter HTTP middleware to remove unnecessary redirects in multi-zone setups.
  • Next.js page cache ↔ Harper database integration to persist pre-rendered HTML and speed up cold starts.
  • Framework parity: bringing the same experience to Vue, Nuxt, Svelte, Astro, and more.

Conclusion

Self-hosting Next.js is far more involved than running a single command—but with the right approach, it can be both powerful and seamless. By rethinking each stage of the app lifecycle—develop, build, deploy, and run—we integrated Next.js deeply into Harper’s platform, unlocking support for features like multi-zone apps, rolling deployments, and dynamic versioning.

The result is a flexible, production-grade setup that gives teams full control without sacrificing the developer experience Next.js is known for.

Co-authored by Austin Akers


next start” Isn’t Enough

We love Next.js. It’s an incredible framework for building modern web apps with React. But the moment you try to self‑host it—especially on bare metal or in clustered environments—you quickly learn that serverless hosts are doing a lot of heavy lifting.

We faced this firsthand at Harper, a platform that fuses a database, networking stack, and application runtime into one high‑performance Node.js engine. So, we asked: What does it really take to self‑host Next.js inside Harper? Spoiler: it’s way more than running next start.

This is the story of how we reimagined the Next.js lifecycle—Develop, Build, Deploy, and Run— within our platform.

Develop: Rebuilding next dev Internally

The Next.js dev server is magic. Hot Module Reloading (HMR), Fast Refresh, error overlays—everything just works. To replicate that inside Harper, we built:

  • A WebSocket-aware upgrade handler to inject hot-reload support into the Harper middleware.
  • A CLI wrapper, harperdb-nextjs dev, which boots Harper and then spins up a Next.js dev server with all the right wiring.
  • Seamless Hot Module Reloading via shared WebSocket channels between client and server.
Sequence diagram showing how HMR updates modules in the browser via WebSocket after file changes are detected by the dev server.

We dove deep into how WebSocket upgrades work in Node and exposed just enough of Harper’s networking stack to give Next.js what it needed.

Build: One Thread to Rule Them All

Harper is multi-threaded. So if we weren’t careful, every thread would build the app independently. Our fix:

  • Thread-locking to ensure only one thread triggers a build.
  • Shared artifact storage so other threads can reuse the output.
  • A harperdb-nextjs build command to kick off clean, single-threaded builds.
Flowchart detailing how threads manage file locks, handle stale states, and coordinate build execution to prevent concurrent access.

This let us avoid the explosion of duplicate builds while preserving concurrency where it matters.

Deploy: Rolling Your Own (Literally)

Production Harper instances often run as clustered nodes, replicated across regions. Replacing all of them at once? A disaster waiting to happen.

Instead, we built rolling deployment support, one node at a time:

  • Nodes take turns building and restarting.
  • Traffic shifts around them.
  • Zero downtime. Full data consistency.
Illustrates a rolling deployment strategy where updates are gradually applied across server groups while maintaining service availability and performance monitoring.

And the best part? This isn't just for Next.js—it's the same deploy system Harper uses for all components.

Run: Programmatic Next.js + Middleware Wizardry

We don’t use next start. Instead, we load Next.js programmatically:

const app = next({ dir: componentPath, dev: false });
await app.prepare();

Then we inject the request and WebSocket handlers directly into Harper’s middleware. This unlocks some wild capabilities:

  • Dynamic version loading: We require.resolve() the right Next.js version from the app’s package.json.
  • Multi-zone hosting: Several Next.js apps, each at different paths, running in one Harper process.
Shows how Harper routes client requests to zone-specific handlers and components using HTTP middleware across blog, store, and root apps.

This allows enterprise users to collapse complex micro-frontend setups into a single runtime—no hops, no hard navigation.

The Tricky Bits: Working Directory Problem

Next.js handles dynamic paths well. But some React tools assume process.cwd() reflects their app’s root. When you’re running multiple apps in one process, that assumption breaks.

We didn’t find a silver bullet here. Instead, we emphasize:

  • Explicit paths over relative ones.
  • Avoiding tools that depend on working directory voodoo.

It’s manageable—but worth flagging if you try this approach.

What’s Next? (Yes, Pun Intended)

We’re not done. Here’s what we’re working on now:

  • Smarter HTTP middleware to remove unnecessary redirects in multi-zone setups.
  • Next.js page cache ↔ Harper database integration to persist pre-rendered HTML and speed up cold starts.
  • Framework parity: bringing the same experience to Vue, Nuxt, Svelte, Astro, and more.

Conclusion

Self-hosting Next.js is far more involved than running a single command—but with the right approach, it can be both powerful and seamless. By rethinking each stage of the app lifecycle—develop, build, deploy, and run—we integrated Next.js deeply into Harper’s platform, unlocking support for features like multi-zone apps, rolling deployments, and dynamic versioning.

The result is a flexible, production-grade setup that gives teams full control without sacrificing the developer experience Next.js is known for.

Discover what it really takes to self-host Next.js beyond just running next start. Learn how Harper reimagined the entire Next.js lifecycle. Develop, Build, Deploy, and Run, to support clustered, bare-metal environments with hot reload, rolling deploys, multi-zone support, and more.

Download

White arrow pointing right
Discover what it really takes to self-host Next.js beyond just running next start. Learn how Harper reimagined the entire Next.js lifecycle. Develop, Build, Deploy, and Run, to support clustered, bare-metal environments with hot reload, rolling deploys, multi-zone support, and more.

Download

White arrow pointing right
Discover what it really takes to self-host Next.js beyond just running next start. Learn how Harper reimagined the entire Next.js lifecycle. Develop, Build, Deploy, and Run, to support clustered, bare-metal environments with hot reload, rolling deploys, multi-zone support, and more.

Download

White arrow pointing right

Explore Recent Resources

Blog
GitHub Logo

5 Architectures for Web Personalization

Personalization is a data-delivery problem. Every architectural choice reduces to two distances: compute to user, and compute to fresh data. This piece maps five real architectures against both axes, scored on a concrete retailer workload where stale or slow data breaks the business.
Blog
Personalization is a data-delivery problem. Every architectural choice reduces to two distances: compute to user, and compute to fresh data. This piece maps five real architectures against both axes, scored on a concrete retailer workload where stale or slow data breaks the business.
Person with short dark hair and moustache, wearing a colorful plaid shirt, smiling outdoors in a forested mountain landscape.
Aleks Haugom
Senior Manager of GTM
Blog

5 Architectures for Web Personalization

Personalization is a data-delivery problem. Every architectural choice reduces to two distances: compute to user, and compute to fresh data. This piece maps five real architectures against both axes, scored on a concrete retailer workload where stale or slow data breaks the business.
Aleks Haugom
Jul 2026
Blog

5 Architectures for Web Personalization

Personalization is a data-delivery problem. Every architectural choice reduces to two distances: compute to user, and compute to fresh data. This piece maps five real architectures against both axes, scored on a concrete retailer workload where stale or slow data breaks the business.
Aleks Haugom
Blog

5 Architectures for Web Personalization

Personalization is a data-delivery problem. Every architectural choice reduces to two distances: compute to user, and compute to fresh data. This piece maps five real architectures against both axes, scored on a concrete retailer workload where stale or slow data breaks the business.
Aleks Haugom
Blog
GitHub Logo

Agentic Engineering Needs an Opinion: Why Scale Starts with Architecture

AI coding works in a sandbox because the environment is trivially narrow. Real systems have history, constraints, and blast radius. Coding agents make sound decisions only when the architecture is explicit and shared. Opinion isn't a constraint on agentic engineering, it's what makes it possible at scale.
Select*
Blog
AI coding works in a sandbox because the environment is trivially narrow. Real systems have history, constraints, and blast radius. Coding agents make sound decisions only when the architecture is explicit and shared. Opinion isn't a constraint on agentic engineering, it's what makes it possible at scale.
A smiling man with a beard and salt-and-pepper hair stands outdoors with arms crossed, wearing a white button-down shirt.
Stephen Goldberg
CEO & Co-Founder
Blog

Agentic Engineering Needs an Opinion: Why Scale Starts with Architecture

AI coding works in a sandbox because the environment is trivially narrow. Real systems have history, constraints, and blast radius. Coding agents make sound decisions only when the architecture is explicit and shared. Opinion isn't a constraint on agentic engineering, it's what makes it possible at scale.
Stephen Goldberg
Jun 2026
Blog

Agentic Engineering Needs an Opinion: Why Scale Starts with Architecture

AI coding works in a sandbox because the environment is trivially narrow. Real systems have history, constraints, and blast radius. Coding agents make sound decisions only when the architecture is explicit and shared. Opinion isn't a constraint on agentic engineering, it's what makes it possible at scale.
Stephen Goldberg
Blog

Agentic Engineering Needs an Opinion: Why Scale Starts with Architecture

AI coding works in a sandbox because the environment is trivially narrow. Real systems have history, constraints, and blast radius. Coding agents make sound decisions only when the architecture is explicit and shared. Opinion isn't a constraint on agentic engineering, it's what makes it possible at scale.
Stephen Goldberg
Blog
GitHub Logo

Building a Cozy Sandbox Game on Harper

A nature-restoration game with six biomes, 150 animals, and a real food web — built with a single Harper component as the entire backend. One YAML file wires the database, API, content seeder, and static host. The same binary ships offline on itch.io.
Shell
Blog
A nature-restoration game with six biomes, 150 animals, and a real food web — built with a single Harper component as the entire backend. One YAML file wires the database, API, content seeder, and static host. The same binary ships offline on itch.io.
Person with long wavy brown hair wearing a bright pink shirt with a teal trim, smiling outdoors in soft sunlight with blurred trees in the background.
Bailey Dunning
Forward Deployed Engineer
Blog

Building a Cozy Sandbox Game on Harper

A nature-restoration game with six biomes, 150 animals, and a real food web — built with a single Harper component as the entire backend. One YAML file wires the database, API, content seeder, and static host. The same binary ships offline on itch.io.
Bailey Dunning
Jun 2026
Blog

Building a Cozy Sandbox Game on Harper

A nature-restoration game with six biomes, 150 animals, and a real food web — built with a single Harper component as the entire backend. One YAML file wires the database, API, content seeder, and static host. The same binary ships offline on itch.io.
Bailey Dunning
Blog

Building a Cozy Sandbox Game on Harper

A nature-restoration game with six biomes, 150 animals, and a real food web — built with a single Harper component as the entire backend. One YAML file wires the database, API, content seeder, and static host. The same binary ships offline on itch.io.
Bailey Dunning
Blog
GitHub Logo

Your Website was Built for Humans. AI Needs Something Cleaner.

The web spent a decade optimizing for browsers. JavaScript-heavy rendering, dynamic CMS templates, and client-side hydration made pages beautiful and machines blind. AI answer engines retrieve, parse, and cite content directly. If your best content is trapped behind a render cycle, a cleaner source wins.
A.I.
Blog
The web spent a decade optimizing for browsers. JavaScript-heavy rendering, dynamic CMS templates, and client-side hydration made pages beautiful and machines blind. AI answer engines retrieve, parse, and cite content directly. If your best content is trapped behind a render cycle, a cleaner source wins.
Person with short dark hair and moustache, wearing a colorful plaid shirt, smiling outdoors in a forested mountain landscape.
Aleks Haugom
Senior Manager of GTM
Blog

Your Website was Built for Humans. AI Needs Something Cleaner.

The web spent a decade optimizing for browsers. JavaScript-heavy rendering, dynamic CMS templates, and client-side hydration made pages beautiful and machines blind. AI answer engines retrieve, parse, and cite content directly. If your best content is trapped behind a render cycle, a cleaner source wins.
Aleks Haugom
Jun 2026
Blog

Your Website was Built for Humans. AI Needs Something Cleaner.

The web spent a decade optimizing for browsers. JavaScript-heavy rendering, dynamic CMS templates, and client-side hydration made pages beautiful and machines blind. AI answer engines retrieve, parse, and cite content directly. If your best content is trapped behind a render cycle, a cleaner source wins.
Aleks Haugom
Blog

Your Website was Built for Humans. AI Needs Something Cleaner.

The web spent a decade optimizing for browsers. JavaScript-heavy rendering, dynamic CMS templates, and client-side hydration made pages beautiful and machines blind. AI answer engines retrieve, parse, and cite content directly. If your best content is trapped behind a render cycle, a cleaner source wins.
Aleks Haugom