DEV Community

Cover image for Running LangChain ReactAgent in browser
Chris Wan
Chris Wan

Posted on

Running LangChain ReactAgent in browser

LangChain is the easiest way to start building agents and applications powered by LLMs. It provides a pre-built agent architecture and model integrations to help you get started quickly and seamlessly incorporate LLMs into your agents and applications.

———— LangChain v1.0 is now available!

Getting Started

The createAgent() function provides a production-ready agent implementation that’s remarkably simple to use:

import { createAgent } from "langchain";

const agent = createAgent({
  model: "gpt-5",
  tools: []
});
Enter fullscreen mode Exit fullscreen mode

However, when attempting to use this function within a useEffect() hook in a Next.js project, I encounter a frustrating error:

does not support external modules (request: node:async_hooks)

Upon investigation, the root cause becomes clear. The context.js file contains the line:

import { AsyncLocalStorage } from "node:async_hooks";
Enter fullscreen mode Exit fullscreen mode

Unfortunately, node:async_hooks is not supported in browser environments.

Understanding the Import Traces

Import traces:
  Client Component Browser:
    ./node_modules/@langchain/core/dist/context.js [Client Component Browser]
    ./node_modules/langchain/dist/index.js [Client Component Browser]
    ./apps/web/app/page.tsx [Client Component Browser]
Enter fullscreen mode Exit fullscreen mode

The langchain/dist/index.js exports context.js. For now createAgent() function is what we need only. Can we simply import the agent directly using import { createAgent } from 'langchain/agents'?

Unfortunately, this approach doesn’t work because LangChain’s package.json defines specific exports, preventing other sub-path imports.

Does LangChain must be used in Node.js runtime environment?

The answer is no — with the right configuration, LangChain can indeed run in browser environments. I found two ways to do it.

Solution I: Resolve Alias Configuration

The first and most elegant solution involves creating a mock for async_hooks and configuring build system to use it instead of the Node.js module.

Step 1: Mock async_hooks

import { MockAsyncLocalStorage } from '@langchain/core/singletons';
const AsyncLocalStorage = MockAsyncLocalStorage;
export { AsyncLocalStorage };
Enter fullscreen mode Exit fullscreen mode

You can also implement a custom AsyncLocalStorage class, as long as it adheres to the AsyncLocalStorageInterface.

For CommonJS, using require and module.exports instead of ES6 imports.

Step 2: Configure next.config.js

Update Next.js configuration to work with either Webpack or Turbopack:

import path from 'node:path';
import { fileURLToPath } from 'node:url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

/** @type {import('next').NextConfig} */
const nextConfig = {
    webpack: (config, { webpack, isServer }) => {
        if (!isServer)  {
            config.plugins.push(
                new webpack.NormalModuleReplacementPlugin(/^node:async_hooks$/, path.resolve(__dirname, 'async_hooks'))
            );
        }
        return config;
    },
    turbopack: {
        resolveAlias: {
            'node:async_hooks': {
                browser: './async_hooks.js'
            },
        }
    }
};

export default nextConfig;
Enter fullscreen mode Exit fullscreen mode

Important Note: If package.json includes "type": "module", the built-in __dirname variable won't be available. We need to create our own implementation. For CommonJS, stick with require and module.exports, and remove any __dirname-related logic.

This configuration is pretty straightforward, it substitutes node:async_hooks with mocked async_hooks during transpiling.

To achieve more precise control, we can enhance the configuration using isServer and browser conditional aliasing when Webpack and Turbopack target browser environments.

Solution II: Source Code Modification

When configuration changes aren’t feasible, we can take a more direct approach by modifying the LangChain source code locally.

  1. Remove export @langchain/core/context from index.ts
  2. Change import @langchain/langgraph to @langchain/langgraph/web in every file

While this method is less elegant than the alias configuration approach, it’s particularly suitable for environments where modifying Webpack or Turbopack configurations isn’t possible or practical.

Conclusion

Running langchain agent in browser is cool. However, there’s one crucial security consideration that developers must address: LLM API key management.

When running LLM-powered applications in the browser, your API keys are exposed to client-side code, creating a significant security vulnerability. Direct API key usage puts your credentials at high risk of being compromised.

Before deploying any browser-based LangChain implementation, it’s essential to build a token exchange service. It will provide frontend application with temporary, scoped tokens.

By this, we can safely harness the power of LangChain agents in browser environments while maintaining the security of your LLM service credentials.

Top comments (0)