@grpc/grpc-js vs @improbable-eng/grpc-web vs grpc-web
gRPC Client Libraries for Node.js and Web Browsers
@grpc/grpc-js@improbable-eng/grpc-webgrpc-web

gRPC Client Libraries for Node.js and Web Browsers

@grpc/grpc-js is the official gRPC implementation for Node.js servers, enabling high-performance service-to-service communication. grpc-web is the official Google client for browsers, allowing web apps to talk to gRPC services via a proxy. @improbable-eng/grpc-web is a community-driven TypeScript client for gRPC-Web that historically offered easier integration for web developers. While all three handle gRPC protocols, they target different runtimes — server versus browser — and require distinct infrastructure setups.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
@grpc/grpc-js04,8192.5 MB2234 months agoApache-2.0
@improbable-eng/grpc-web04,475-1804 years agoApache-2.0
grpc-web09,19836.3 kB1877 months agoApache-2.0

gRPC Clients for Node.js and Web: Architecture and Implementation Compared

Choosing the right gRPC library depends entirely on where your code runs. @grpc/grpc-js is built for Node.js servers, while grpc-web and @improbable-eng/grpc-web are designed for browsers. Mixing them up leads to build failures or runtime errors. Let's break down how they handle environment support, setup, and API design.

🖥️ Runtime Environment: Server vs. Browser

@grpc/grpc-js runs exclusively on Node.js.

  • It relies on Node's native http2 module.
  • Bundling this for the browser will fail because browser environments lack Node core modules.
// @grpc/grpc-js: Server-side only
const { Client, credentials } = require('@grpc/grpc-js');
const client = new Client('localhost:50051', credentials.createInsecure());
// ❌ Will throw error if bundled for webpack/vite in browser

grpc-web runs in browsers.

  • It uses HTTP/1.1 or HTTP/2 over standard web requests.
  • Requires a proxy (like Envoy) to translate between browser and gRPC server.
// grpc-web: Browser client (generated code)
const { GreeterClient } = require('./proto/helloworld_grpc_web_pb');
const client = new GreeterClient('https://api.example.com', null, null);
// ✅ Works in browser via XHR or Fetch

@improbable-eng/grpc-web runs in browsers.

  • It implements the gRPC-Web protocol using standard Fetch or XHR.
  • Also requires a gRPC-Web compatible proxy on the server side.
// @improbable-eng/grpc-web: Browser client
import { createClientFactory } from '@improbable-eng/grpc-web';
const client = createClientFactory().create(MyService);
// ✅ Works in browser, handles transport internally

🛠️ Setup and Code Generation

@grpc/grpc-js uses standard protoc plugins.

  • You generate JS code using grpc_tools_node_protoc_plugin.
  • The generated code matches the Node.js runtime expectations.
// @grpc/grpc-js: Generation command
protoc --js_out=import_style=commonjs,binary:. \
  --grpc_out=grpc_js:. \
  --plugin=protoc-gen-grpc=./node_modules/.bin/grpc_tools_node_protoc_plugin \
  service.proto

grpc-web requires specific web plugins.

  • You must use protoc-gen-grpc-web to generate compatible code.
  • The output often relies on Closure Library or specific CommonJS wrappers.
// grpc-web: Generation command
protoc --js_out=import_style=commonjs:. \
  --grpc-web_out=import_style=commonjs,mode=grpcwebtext:. \
  service.proto

@improbable-eng/grpc-web uses its own plugin or compatible output.

  • It can often consume standard gRPC-Web generated files but wraps them for TS.
  • Historically offered better TypeScript type inference without extra steps.
// @improbable-eng/grpc-web: Generation command
protoc --js_out=import_style=commonjs:. \
  --grpc-web_out=import_style=commonjs,mode=grpcwebtext:. \
  service.proto
// Then wrap with @improbable-eng/grpc-web utilities

🔌 API Style: Callbacks vs. Promises

@grpc/grpc-js leans heavily on callbacks.

  • Methods accept a callback function for responses.
  • Streaming uses event emitters.
// @grpc/grpc-js: Callback style
client.sayHello(request, (err, response) => {
  if (err) console.error(err);
  else console.log(response.message);
});

grpc-web uses callbacks in generated code.

  • The official generated clients expect (err, response) signatures.
  • Promises require manual wrapping or helper libraries.
// grpc-web: Callback style
client.sayHello(request, { customHeader: 'value' }, (err, response) => {
  if (err) console.error(err);
  else console.log(response.getMessage());
});

@improbable-eng/grpc-web supports Promises natively.

  • Offers a cleaner async/await experience.
  • Reduces boilerplate for frontend developers used to Fetch API.
// @improbable-eng/grpc-web: Promise style
const response = await client.sayHello(request, {
  headers: new Headers({ customHeader: 'value' })
});
console.log(response.message);

🌐 Proxy and Infrastructure Requirements

@grpc/grpc-js connects directly to gRPC servers.

  • No proxy needed if both sides are Node.js.
  • Direct HTTP/2 connection over TCP.
// @grpc/grpc-js: Direct connection
// Client -> Node.js Server (Port 50051)

grpc-web requires an Envoy proxy.

  • Browsers cannot speak raw gRPC over HTTP/2.
  • Envoy translates gRPC-Web frames to standard gRPC.
// grpc-web: Proxy required
// Browser -> Envoy (HTTP/1.1 or HTTP/2) -> Node.js Server

@improbable-eng/grpc-web also requires a proxy.

  • Compatible with the same Envoy setup as official grpc-web.
  • Some configurations allow direct connection if server supports CORS and gRPC-Web frames.
// @improbable-eng/grpc-web: Proxy required
// Browser -> Envoy -> Node.js Server

📦 Maintenance and Ecosystem Health

@grpc/grpc-js is actively maintained by Google.

  • It is the default for Node.js gRPC.
  • Receives regular security updates and feature additions.
// @grpc/grpc-js: Stable API
// Safe for long-term enterprise use

grpc-web is actively maintained by Google.

  • It is the standard for web gRPC.
  • Documentation and tooling are official.
// grpc-web: Stable API
// Safe for long-term enterprise use

@improbable-eng/grpc-web is in maintenance mode.

  • The repository indicates reduced activity.
  • New projects should weigh the risk of reduced support against DX benefits.
// @improbable-eng/grpc-web: Maintenance Mode
// ⚠️ Check repository status before committing

📊 Summary: Key Differences

Feature@grpc/grpc-jsgrpc-web@improbable-eng/grpc-web
Runtime🖥️ Node.js Only🌐 Browser🌐 Browser
Proxy Needed❌ No✅ Yes (Envoy)✅ Yes (Envoy)
API Style🔄 Callbacks🔄 Callbacks⚡ Promises/Async
TS Support🛠️ Good🛠️ Requires Config✅ Excellent
Status✅ Active✅ Active⚠️ Maintenance

💡 The Big Picture

@grpc/grpc-js is the engine for your backend.
Use it to connect microservices within your server infrastructure. It is not an option for frontend code.

grpc-web is the standard bridge for browsers.
Use it if you want official support and long-term stability. It requires setting up a proxy, but it ensures you are following the canonical gRPC-Web spec.

@improbable-eng/grpc-web is the developer-friendly alternative.
Use it if you prioritize TypeScript experience and Promise-based APIs. However, because it is in maintenance mode, you must decide if the improved DX is worth the potential risk of slower updates in the future.

Final Thought: For new projects, pairing @grpc/grpc-js on the server with official grpc-web on the client is the safest architectural choice. If you choose @improbable-eng/grpc-web, plan for a potential migration path should support cease entirely.

How to Choose: @grpc/grpc-js vs @improbable-eng/grpc-web vs grpc-web

  • @grpc/grpc-js:

    Choose @grpc/grpc-js if you are building backend microservices in Node.js that need to communicate with other gRPC services. It is not suitable for browsers. This package is the standard for server-side gRPC in the JavaScript ecosystem and offers full support for streaming and metadata.

  • @improbable-eng/grpc-web:

    Choose @improbable-eng/grpc-web if you need a TypeScript-friendly gRPC-Web client with Promise-based APIs and cannot use the official client's generated code structure. However, note that this package is in maintenance mode, so evaluate if the trade-off in long-term support is acceptable for your project.

  • grpc-web:

    Choose grpc-web if you need an officially supported browser client and can configure an Envoy proxy in your infrastructure. It is the safest long-term bet for stability and compliance with the gRPC-Web standard, though it requires more initial setup for code generation.

README for @grpc/grpc-js

Pure JavaScript gRPC Client

Installation

Node 12 is recommended. The exact set of compatible Node versions can be found in the engines field of the package.json file.

npm install @grpc/grpc-js

Documentation

Documentation specifically for the @grpc/grpc-js package is currently not available. However, documentation is available for the grpc package, and the two packages contain mostly the same interface. There are a few notable differences, however, and these differences are noted in the "Migrating from grpc" section below.

Features

  • Clients
  • Automatic reconnection
  • Servers
  • Streaming
  • Metadata
  • Partial compression support: clients can compress and decompress messages, and servers can decompress request messages
  • Pick first and round robin load balancing policies
  • Client Interceptors
  • Connection Keepalives
  • HTTP Connect support (proxies)

If you need a feature from the grpc package that is not provided by the @grpc/grpc-js, please file a feature request with that information.

This library does not directly handle .proto files. To use .proto files with this library we recommend using the @grpc/proto-loader package.

Migrating from grpc

@grpc/grpc-js is almost a drop-in replacement for grpc, but you may need to make a few code changes to use it:

  • If you are currently loading .proto files using grpc.load, that function is not available in this library. You should instead load your .proto files using @grpc/proto-loader and load the resulting package definition objects into @grpc/grpc-js using grpc.loadPackageDefinition.
  • If you are currently loading packages generated by grpc-tools, you should instead generate your files using the generate_package_definition option in grpc-tools, then load the object exported by the generated file into @grpc/grpc-js using grpc.loadPackageDefinition.
  • If you have a server and you are using Server#bind to bind ports, you will need to use Server#bindAsync instead.
  • If you are using any channel options supported in grpc but not supported in @grpc/grpc-js, you may need to adjust your code to handle the different behavior. Refer to the list of supported options below.
  • Refer to the detailed package comparison for more details on the differences between grpc and @grpc/grpc-js.

Supported Channel Options

Many channel arguments supported in grpc are not supported in @grpc/grpc-js. The channel arguments supported by @grpc/grpc-js are:

  • grpc.ssl_target_name_override
  • grpc.primary_user_agent
  • grpc.secondary_user_agent
  • grpc.default_authority
  • grpc.keepalive_time_ms
  • grpc.keepalive_timeout_ms
  • grpc.keepalive_permit_without_calls
  • grpc.service_config
  • grpc.max_concurrent_streams
  • grpc.initial_reconnect_backoff_ms
  • grpc.max_reconnect_backoff_ms
  • grpc.use_local_subchannel_pool
  • grpc.max_send_message_length
  • grpc.max_receive_message_length
  • grpc.enable_http_proxy
  • grpc.default_compression_algorithm
  • grpc.enable_channelz
  • grpc.dns_min_time_between_resolutions_ms
  • grpc.enable_retries
  • grpc.max_connection_age_ms
  • grpc.max_connection_age_grace_ms
  • grpc.max_connection_idle_ms
  • grpc.per_rpc_retry_buffer_size
  • grpc.retry_buffer_size
  • grpc.service_config_disable_resolution
  • grpc.client_idle_timeout_ms
  • grpc-node.max_session_memory
  • grpc-node.tls_enable_trace
  • grpc-node.retry_max_attempts_limit
  • grpc-node.flow_control_window
  • channelOverride
  • channelFactoryOverride

Some Notes on API Guarantees

The public API of this library follows semantic versioning, with some caveats:

  • Some methods are prefixed with an underscore. These methods are internal and should not be considered part of the public API.
  • The class Call is only exposed due to limitations of TypeScript. It should not be considered part of the public API.
  • In general, any API that is exposed by this library but is not exposed by the grpc library is likely an error and should not be considered part of the public API.
  • The grpc.experimental namespace contains APIs that have not stabilized. Any API in that namespace may break in any minor version update.