Click Below to Get the Code

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

Harper v5.0's Upgraded JavaScript Environment

Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.
Tutorial

Harper v5.0's Upgraded JavaScript Environment

Kris Zyp
SVP of Engineering
at Harper
April 28, 2026
Kris Zyp
SVP of Engineering
at Harper
April 28, 2026
Kris Zyp
SVP of Engineering
at Harper
April 28, 2026
April 28, 2026
Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.
Kris Zyp
SVP of Engineering

Harper v5.0 introduces a significantly upgraded JavaScript execution environment for applications. The new environment provides application-specific context and stronger security controls, and represents a meaningful step forward in both developer experience and platform security.


The Old Approach

In prior versions of Harper, application code was loaded with a straightforward native import(). There was no execution boundary: every application ran in the same global context as Harper itself, meaning modifications to built-in prototypes could affect the entire runtime. There was also no way to give each application its own context—a logger tagged to that application's name, access only to that application's configuration—without threading those values through manually.

What's New in v5.0

A VM-Based Module Loader

Harper now loads application modules through Node.js's vm.SourceTextModule API, giving each application its own module cache and execution context. This is what enables application-specific JavaScript context: each app gets its own module graph, isolated from other apps and from Harper's own internals.

The loader is configurable. The default is vm mode. If legacy code is having trouble with the new loader, you can set applications.moduleLoader: native to fall back to the old behavior while working through the migration. There's also a compartment mode using SES Compartments for applications that want the strictest possible isolation.

Application-Specific Context

When application code runs, it now has access to a set of globals and module exports scoped specifically to that application:

  • logger — Logs are automatically tagged with your application's name, making output from multi-application servers dramatically easier to follow and filter.
  • config — The configuration object for your specific application, sourced from your component's config.yaml. No more passing config around manually.

These are available via the harper package, which is the preferred way to access them:

import { logger, config, tables, Resource } from 'harper';

The logger you get this way is automatically tagged to your application. The config is your application's config. We strongly recommend migrating to explicit imports from harper rather than depending on globals. The globals still work for backward compatibility, but they may not always give you the fully contextualized version.

Security Controls

Harper's VM context is not a hardened security sandbox—it provides access to the full breadth of Node.js APIs, which is what makes it a powerful environment for building real server-side applications. A determined attacker with code execution could potentially find ways around the VM isolation. What we've built is a meaningful security improvement that blocks a broad class of common exploitation patterns while maintaining the full capability of Node.js. Here's what the new environment actively protects against:

Prototype pollution. The default lockdown mode (freeze-after-load) freezes JavaScript intrinsics—Object, Array, Promise, Map, Set, and others—after application code is loaded. Prototype pollution is one of the most common JavaScript exploitation techniques, and freezing the prototypes of these core types stops it cold. For even stricter protection, you can enable applications.lockdown: ses to apply full SES lockdown from the ses package. This is the gold standard for Hardened JavaScript, though it's more likely to be incompatible with packages that make assumptions about mutability of built-ins.

Malicious process spawning. One of the most dangerous things a compromised Node.js application can do is spawn arbitrary subprocesses. In v5.0, child_process's spawn(), exec(), and execFile() are intercepted and checked against an explicit allowlist in applications.allowedSpawnCommands. If a process command isn't on the list, the call throws an error. Only the commands you explicitly authorize can be launched.

There's a related improvement for legitimate subprocess use as well: Harper now requires a name option when spawning processes. Harper's multi-threaded architecture means that naive subprocess code spawns duplicate processes on each worker thread restart. Named processes are now tracked via PID files and deduplicated automatically.

Unauthorized file access. By default, applications can only load modules from within their own directory tree (allowedDirectory: app). The VM loader enforces this at module load time via path validation. This prevents an application from loading modules—or reading files—from outside its own scope.

Node.js built-in module allowlist. The applications.allowedBuiltinModules option lets you explicitly enumerate which Node.js built-in modules applications are permitted to import. This closes off access to sensitive Node APIs that most applications don't need.

Supply chain attack mitigation. Harper now uses --ignore-scripts by default when installing application packages. Install scripts are a common vector for supply chain attacks—malicious packages often hide payloads in postinstall scripts. Disabling these by default means that unless you've explicitly opted in with allowInstallScripts, package installation can't silently execute arbitrary code.

Migrating Existing Applications

For most well-behaved applications, upgrading to v5.0 should be seamless. But there are a few patterns that will run into the new environment:

If your application accesses files outside its own directory, you'll need to configure applications.allowedDirectory. Note that dev mode installs (the default when you choose the "dev" configuration during installation) set allowedDirectory: any, which allows access to any path on the filesystem, so local development shouldn't be affected. Production installs default to restricting access to the app directory.

If your application modifies intrinsic prototypes (e.g., extending Array.prototype or Object.prototype), this will break under the default freeze-after-load lockdown because those prototypes are frozen after startup. The intent with this change is to prevent the dangerous and verboten pattern of prototype mutation; thus you may need to refactor. If you're using a library that does this, you can set lockdown: none to disable it entirely while you work through the issue.

If your application spawns child processes, you'll need to add those commands to applications.allowedSpawnCommands in your configuration, and update your spawn calls to include a name in the options:

import { exec } from 'node:child_process';

exec('my-tool', ['--flag'], { name: 'my-named-process' }, callback);

If you have packages that need to spawn, and you are unable to modify them, you can disable the VM loader for dependencies with applications.dependencyLoader: native (see next section).

If the VM module loader is causing compatibility issues with specific packages, you can configure applications.dependencyLoader: native to load npm dependencies with the native module loader while still getting application context for your own code. The default auto mode already uses native loading for npm packages that don't declare harper as a dependency.

If all else fails, setting applications.moduleLoader: native disables the VM loader entirely, restoring the pre-v5 behavior for your application. This disables all the dependency loader options, directory containment, and spawn command protections (lockdown can still be used though). This is a temporary escape hatch—if you hit something that requires it, please file an issue so we can address the compatibility gap.

Our Commitment to Platform Security

The context for these changes matters. Supply chain attacks on npm packages are increasing. The npm ecosystem's size is also its vulnerability surface—malicious packages, dependency confusion attacks, and compromised dependencies are real and growing threats. When you run a Harper application, you're potentially running dozens of third-party packages, any of which could be a vector.

Our goal with v5.0's JavaScript environment is to make Harper a platform where a compromised dependency has a much harder time doing real damage. Blocked prototype pollution, constrained subprocess spawning, restricted file access, and explicit module allowlists all work together to reduce what malicious code can accomplish.

For customers running on our Fabric hosting service, there are additional layers of isolation at the infrastructure level: each tenant runs in a separate Docker container on a dedicated user account. These infrastructure controls complement the application environment hardening—defense in depth rather than a single layer.

Full SES compartmentalization is available today for applications that opt into it, and we're continuing to improve the compatibility of the VM-based loader with the broader npm ecosystem. As Node.js's module isolation primitives mature, we'll keep building on them.

Questions or issues with the v5.0 migration? Open an issue on the Harper GitHub repo or reach out on Discord.

Harper v5.0 introduces a significantly upgraded JavaScript execution environment for applications. The new environment provides application-specific context and stronger security controls, and represents a meaningful step forward in both developer experience and platform security.


The Old Approach

In prior versions of Harper, application code was loaded with a straightforward native import(). There was no execution boundary: every application ran in the same global context as Harper itself, meaning modifications to built-in prototypes could affect the entire runtime. There was also no way to give each application its own context—a logger tagged to that application's name, access only to that application's configuration—without threading those values through manually.

What's New in v5.0

A VM-Based Module Loader

Harper now loads application modules through Node.js's vm.SourceTextModule API, giving each application its own module cache and execution context. This is what enables application-specific JavaScript context: each app gets its own module graph, isolated from other apps and from Harper's own internals.

The loader is configurable. The default is vm mode. If legacy code is having trouble with the new loader, you can set applications.moduleLoader: native to fall back to the old behavior while working through the migration. There's also a compartment mode using SES Compartments for applications that want the strictest possible isolation.

Application-Specific Context

When application code runs, it now has access to a set of globals and module exports scoped specifically to that application:

  • logger — Logs are automatically tagged with your application's name, making output from multi-application servers dramatically easier to follow and filter.
  • config — The configuration object for your specific application, sourced from your component's config.yaml. No more passing config around manually.

These are available via the harper package, which is the preferred way to access them:

import { logger, config, tables, Resource } from 'harper';

The logger you get this way is automatically tagged to your application. The config is your application's config. We strongly recommend migrating to explicit imports from harper rather than depending on globals. The globals still work for backward compatibility, but they may not always give you the fully contextualized version.

Security Controls

Harper's VM context is not a hardened security sandbox—it provides access to the full breadth of Node.js APIs, which is what makes it a powerful environment for building real server-side applications. A determined attacker with code execution could potentially find ways around the VM isolation. What we've built is a meaningful security improvement that blocks a broad class of common exploitation patterns while maintaining the full capability of Node.js. Here's what the new environment actively protects against:

Prototype pollution. The default lockdown mode (freeze-after-load) freezes JavaScript intrinsics—Object, Array, Promise, Map, Set, and others—after application code is loaded. Prototype pollution is one of the most common JavaScript exploitation techniques, and freezing the prototypes of these core types stops it cold. For even stricter protection, you can enable applications.lockdown: ses to apply full SES lockdown from the ses package. This is the gold standard for Hardened JavaScript, though it's more likely to be incompatible with packages that make assumptions about mutability of built-ins.

Malicious process spawning. One of the most dangerous things a compromised Node.js application can do is spawn arbitrary subprocesses. In v5.0, child_process's spawn(), exec(), and execFile() are intercepted and checked against an explicit allowlist in applications.allowedSpawnCommands. If a process command isn't on the list, the call throws an error. Only the commands you explicitly authorize can be launched.

There's a related improvement for legitimate subprocess use as well: Harper now requires a name option when spawning processes. Harper's multi-threaded architecture means that naive subprocess code spawns duplicate processes on each worker thread restart. Named processes are now tracked via PID files and deduplicated automatically.

Unauthorized file access. By default, applications can only load modules from within their own directory tree (allowedDirectory: app). The VM loader enforces this at module load time via path validation. This prevents an application from loading modules—or reading files—from outside its own scope.

Node.js built-in module allowlist. The applications.allowedBuiltinModules option lets you explicitly enumerate which Node.js built-in modules applications are permitted to import. This closes off access to sensitive Node APIs that most applications don't need.

Supply chain attack mitigation. Harper now uses --ignore-scripts by default when installing application packages. Install scripts are a common vector for supply chain attacks—malicious packages often hide payloads in postinstall scripts. Disabling these by default means that unless you've explicitly opted in with allowInstallScripts, package installation can't silently execute arbitrary code.

Migrating Existing Applications

For most well-behaved applications, upgrading to v5.0 should be seamless. But there are a few patterns that will run into the new environment:

If your application accesses files outside its own directory, you'll need to configure applications.allowedDirectory. Note that dev mode installs (the default when you choose the "dev" configuration during installation) set allowedDirectory: any, which allows access to any path on the filesystem, so local development shouldn't be affected. Production installs default to restricting access to the app directory.

If your application modifies intrinsic prototypes (e.g., extending Array.prototype or Object.prototype), this will break under the default freeze-after-load lockdown because those prototypes are frozen after startup. The intent with this change is to prevent the dangerous and verboten pattern of prototype mutation; thus you may need to refactor. If you're using a library that does this, you can set lockdown: none to disable it entirely while you work through the issue.

If your application spawns child processes, you'll need to add those commands to applications.allowedSpawnCommands in your configuration, and update your spawn calls to include a name in the options:

import { exec } from 'node:child_process';

exec('my-tool', ['--flag'], { name: 'my-named-process' }, callback);

If you have packages that need to spawn, and you are unable to modify them, you can disable the VM loader for dependencies with applications.dependencyLoader: native (see next section).

If the VM module loader is causing compatibility issues with specific packages, you can configure applications.dependencyLoader: native to load npm dependencies with the native module loader while still getting application context for your own code. The default auto mode already uses native loading for npm packages that don't declare harper as a dependency.

If all else fails, setting applications.moduleLoader: native disables the VM loader entirely, restoring the pre-v5 behavior for your application. This disables all the dependency loader options, directory containment, and spawn command protections (lockdown can still be used though). This is a temporary escape hatch—if you hit something that requires it, please file an issue so we can address the compatibility gap.

Our Commitment to Platform Security

The context for these changes matters. Supply chain attacks on npm packages are increasing. The npm ecosystem's size is also its vulnerability surface—malicious packages, dependency confusion attacks, and compromised dependencies are real and growing threats. When you run a Harper application, you're potentially running dozens of third-party packages, any of which could be a vector.

Our goal with v5.0's JavaScript environment is to make Harper a platform where a compromised dependency has a much harder time doing real damage. Blocked prototype pollution, constrained subprocess spawning, restricted file access, and explicit module allowlists all work together to reduce what malicious code can accomplish.

For customers running on our Fabric hosting service, there are additional layers of isolation at the infrastructure level: each tenant runs in a separate Docker container on a dedicated user account. These infrastructure controls complement the application environment hardening—defense in depth rather than a single layer.

Full SES compartmentalization is available today for applications that opt into it, and we're continuing to improve the compatibility of the VM-based loader with the broader npm ecosystem. As Node.js's module isolation primitives mature, we'll keep building on them.

Questions or issues with the v5.0 migration? Open an issue on the Harper GitHub repo or reach out on Discord.

Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.

Download

White arrow pointing right
Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.

Download

White arrow pointing right
Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.

Download

White arrow pointing right

Explore Recent Resources

Tutorial
GitHub Logo

Harper v5.0's Upgraded JavaScript Environment

Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.
Tutorial
Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.
Person with very short blonde hair wearing a light gray button‑up shirt, standing with arms crossed and smiling outdoors with foliage behind.
Kris Zyp
SVP of Engineering
Tutorial

Harper v5.0's Upgraded JavaScript Environment

Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.
Kris Zyp
Apr 2026
Tutorial

Harper v5.0's Upgraded JavaScript Environment

Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.
Kris Zyp
Tutorial

Harper v5.0's Upgraded JavaScript Environment

Harper v5.0 introduces a VM-based JavaScript environment that enhances application isolation, security, and developer experience. With application-specific context, module-level separation, and protections against prototype pollution, unauthorized access, and supply chain attacks, it delivers a more secure, scalable foundation for modern distributed applications.
Kris Zyp
Blog
GitHub Logo

5 Patterns to Cut Your Agent's Token Bill

AI agent costs are driven up by inefficient architecture. This guide breaks down five proven patterns, including deterministic workflows, parallel tool calls, and semantic caching, to reduce token usage, improve performance, and scale AI systems more efficiently.
Blog
AI agent costs are driven up by inefficient architecture. This guide breaks down five proven patterns, including deterministic workflows, parallel tool calls, and semantic caching, to reduce token usage, improve performance, and scale AI systems more efficiently.
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 Patterns to Cut Your Agent's Token Bill

AI agent costs are driven up by inefficient architecture. This guide breaks down five proven patterns, including deterministic workflows, parallel tool calls, and semantic caching, to reduce token usage, improve performance, and scale AI systems more efficiently.
Aleks Haugom
Apr 2026
Blog

5 Patterns to Cut Your Agent's Token Bill

AI agent costs are driven up by inefficient architecture. This guide breaks down five proven patterns, including deterministic workflows, parallel tool calls, and semantic caching, to reduce token usage, improve performance, and scale AI systems more efficiently.
Aleks Haugom
Blog

5 Patterns to Cut Your Agent's Token Bill

AI agent costs are driven up by inefficient architecture. This guide breaks down five proven patterns, including deterministic workflows, parallel tool calls, and semantic caching, to reduce token usage, improve performance, and scale AI systems more efficiently.
Aleks Haugom
Repo
GitHub Logo

Product Recommendations Engine

An open-source real-time product recommendation engine built as a Harper component. Combines co-occurrence learning, HNSW vector search, UCB exploration, and category diversity re-ranking on Harper's replicated tables. No vector database, training pipeline, or external ML infrastructure required.
TypeScript
Repo
An open-source real-time product recommendation engine built as a Harper component. Combines co-occurrence learning, HNSW vector search, UCB exploration, and category diversity re-ranking on Harper's replicated tables. No vector database, training pipeline, or external ML infrastructure required.
Repo

Product Recommendations Engine

An open-source real-time product recommendation engine built as a Harper component. Combines co-occurrence learning, HNSW vector search, UCB exploration, and category diversity re-ranking on Harper's replicated tables. No vector database, training pipeline, or external ML infrastructure required.
Apr 2026
Repo

Product Recommendations Engine

An open-source real-time product recommendation engine built as a Harper component. Combines co-occurrence learning, HNSW vector search, UCB exploration, and category diversity re-ranking on Harper's replicated tables. No vector database, training pipeline, or external ML infrastructure required.
Repo

Product Recommendations Engine

An open-source real-time product recommendation engine built as a Harper component. Combines co-occurrence learning, HNSW vector search, UCB exploration, and category diversity re-ranking on Harper's replicated tables. No vector database, training pipeline, or external ML infrastructure required.
Blog
GitHub Logo

The Nearstore Agent: a reference pattern for low-latency, geofenced, promotional decisions

Build a real-time, geofenced promo engine on Harper's agentic runtime. The Nearstore Agent collapses geofence lookup, customer data, campaigns, and AI decisions into a single process. Clone the reference repo and deploy in minutes.
Blog
Build a real-time, geofenced promo engine on Harper's agentic runtime. The Nearstore Agent collapses geofence lookup, customer data, campaigns, and AI decisions into a single process. Clone the reference repo and deploy in minutes.
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

The Nearstore Agent: a reference pattern for low-latency, geofenced, promotional decisions

Build a real-time, geofenced promo engine on Harper's agentic runtime. The Nearstore Agent collapses geofence lookup, customer data, campaigns, and AI decisions into a single process. Clone the reference repo and deploy in minutes.
Aleks Haugom
Apr 2026
Blog

The Nearstore Agent: a reference pattern for low-latency, geofenced, promotional decisions

Build a real-time, geofenced promo engine on Harper's agentic runtime. The Nearstore Agent collapses geofence lookup, customer data, campaigns, and AI decisions into a single process. Clone the reference repo and deploy in minutes.
Aleks Haugom
Blog

The Nearstore Agent: a reference pattern for low-latency, geofenced, promotional decisions

Build a real-time, geofenced promo engine on Harper's agentic runtime. The Nearstore Agent collapses geofence lookup, customer data, campaigns, and AI decisions into a single process. Clone the reference repo and deploy in minutes.
Aleks Haugom
Blog
GitHub Logo

How a Shopify Custom Tie Shop Exposes a Common Flaw in Agent Architecture

Explore how a Shopify-based custom tie shop reveals a critical flaw in one LLM agent design strategy, and why context-first architectures with unified runtimes deliver faster, more accurate, and scalable customer support automation.
Blog
Explore how a Shopify-based custom tie shop reveals a critical flaw in one LLM agent design strategy, and why context-first architectures with unified runtimes deliver faster, more accurate, and scalable customer support automation.
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

How a Shopify Custom Tie Shop Exposes a Common Flaw in Agent Architecture

Explore how a Shopify-based custom tie shop reveals a critical flaw in one LLM agent design strategy, and why context-first architectures with unified runtimes deliver faster, more accurate, and scalable customer support automation.
Aleks Haugom
Apr 2026
Blog

How a Shopify Custom Tie Shop Exposes a Common Flaw in Agent Architecture

Explore how a Shopify-based custom tie shop reveals a critical flaw in one LLM agent design strategy, and why context-first architectures with unified runtimes deliver faster, more accurate, and scalable customer support automation.
Aleks Haugom
Blog

How a Shopify Custom Tie Shop Exposes a Common Flaw in Agent Architecture

Explore how a Shopify-based custom tie shop reveals a critical flaw in one LLM agent design strategy, and why context-first architectures with unified runtimes deliver faster, more accurate, and scalable customer support automation.
Aleks Haugom