This is a plugin for using cloudflare workers service bindings in Remix.

Script size must be kept under 1 megabyte to deploy to Cloudflare Workers. By splitting services and connecting them with service bindings, they are freed from that limitation.

Automatically split scripts during production deployment and deploy to two workers.

One side receives access at the edge. But it does not have loader and action logic, it just SSRs the React component. The other holds the loader and action logic on behalf of the edge and is called from the edge by the service binding. In other words, the bundle size per worker can be reduced because it is automatically divided into two groups: workers with design-related libraries, such as UI libraries, and workers with logic and libraries for processing server-side data.

This worker isolation process is handled by esbuild plug-ins, so the developer does not need to be aware of any control over it.


You need wrangler >= 2.0.0.

npm install -D wrangler remix-service-bindings remix-esbuild-override


// remix.config.js
const { withEsbuildOverride } = require("remix-esbuild-override");
const remixServiceBindings = require("remix-service-bindings").default;

withEsbuildOverride((option, { isServer }) => {
  if (isServer) {
    option.plugins = [
       * remixServiceBindings
       * @param isEdgeSide {boolean} - When this is true, the build is for edge (binder) and when false, the build is for bindee.
       *                               (Deployment (build) must be done in two parts.)
       * @param bindingsName {string} - The bind name set in toml. This name will be converted to a bind object.
       * @param enabled {boolean} - If this is false, this plugin is disabled.
      remixServiceBindings(!process.env.BINDEE, "BINDEE", !!process.env.DEPLOY),

  return option;

 * @type {import('@remix-run/dev').AppConfig}
module.exports = {
  serverBuildTarget: "cloudflare-workers",
  server: "./server.js",
  devServerBroadcastDelay: 1000,
  ignoredRouteFiles: ["**/.*"],
  // appDirectory: "app",
  // assetsBuildDirectory: "public/build",
  // serverBuildPath: "build/index.js",
  // publicPath: "/build/",


import { createEventHandler } from "@remix-run/cloudflare-workers";
import * as build from "@remix-run/dev/server-build";

    mode: process.env.NODE_ENV,
    getLoadContext: (event) => {
      return { event };


# wrangler.toml
name = "your-service-name"

compatibility_date = "2022-05-11"

account_id = ""
workers_dev = true
main = "./build/index.js"

name = "BINDEE"
type = "service"
service = "your-bindee-service-name"
environment = "production"

bucket = "./public"

command = "DEPLOY=true npm run build"


# wrangler.bindee.toml
name = "your-bindee-service-name"

compatibility_date = "2022-05-11"

account_id = ""
workers_dev = true
main = "./build/index.js"

bucket = "./public"

command = "DEPLOY=true BINDEE=true npm run build"


"scripts": {
  "deploy": "npm run deploy:bindee && npm run deploy:edge",
  "deploy:edge": "wrangler publish -c wrangler.edge.toml",
  "deploy:bindee": "wrangler publish -c wrangler.bindee.toml",


npm run deploy


This project is licensed under the MIT License – see the LICENSE file for details


View Github