Skip to main content
Services are the building blocks of a workerd configuration. Each service has a unique name used to reference it from elsewhere in the config file. Services are not accessible until you explicitly expose them through a socket or binding.

Service types

workerd supports four types of services:
  • Worker: A JavaScript/WebAssembly worker
  • Network: Network access with address filtering
  • ExternalServer: Proxy to a specific remote server
  • DiskDirectory: HTTP interface to a local directory

Defining services

Services are defined in the services list of your configuration:
using Workerd = import "/workerd/workerd.capnp";

const config :Workerd.Config = (
  services = [
    (name = "main", worker = .mainWorker),
    (name = "backend", external = .backendServer),
    (name = "internet", network = .networkConfig),
  ],

  sockets = [
    ( name = "http",
      address = "*:8080",
      http = (),
      service = "main"  # Routes to the "main" service
    ),
  ]
);

Worker services

Worker services execute JavaScript or WebAssembly code. See the Workers configuration page for detailed documentation.
const mainWorker :Workerd.Worker = (
  modules = [
    (name = "index.js", esModule = embed "index.js"),
  ],
  compatibilityDate = "2023-02-28",
);

Network services

Network services define access to networks with configurable address filtering. This is commonly used to define controlled internet access.
allow
List(Text)
default:"[\"public\"]"
Network addresses the worker can connect to, in CIDR notation. Traffic is permitted if the address matches at least one entry in allow and none in deny.Special values:
  • "public": Publicly-routable addresses only (opposite of "private")
  • "private": RFC1918 private networks (superset of "local")
  • "local": Localhost addresses only (127.0.0.0/8, ::1)
  • "network": Any non-local address (opposite of "local")
  • "unix": Unix domain socket addresses
  • "unix-abstract": Linux abstract Unix domain addresses
deny
List(Text)
Network addresses to explicitly block. Takes precedence over allow.
tlsOptions
TlsOptions
TLS configuration for connections. See Socket configuration for details.

Examples

const publicInternet :Workerd.Network = (
  allow = ["public"],
  tlsOptions = (trustBrowserCas = true),
);
When a worker specifies a DNS hostname, the allow/deny rules filter the addresses returned by the lookup. If no addresses are permitted, the system behaves as if the DNS entry did not exist.

External server services

External server services forward all requests to a specific remote server. This is typically used to connect to back-end servers on your internal network.
address
Text
Address and port of the server. Can be overridden from command line with --external-addr <name>=<addr>.Examples:
  • "1.2.3.4": IPv4 address on default port
  • "1.2.3.4:8080": IPv4 address and port
  • "[1234:5678::abcd]:8080": IPv6 address and port
  • "unix:/path/to/socket": Unix domain socket
  • "unix-abstract:name": Linux abstract Unix socket
  • "example.com:8080": DNS hostname
http
HttpOptions
Connect via unencrypted HTTP.
https
group
Connect via encrypted HTTPS.
  • options: HttpOptions for the connection
  • tlsOptions: TLS configuration
  • certificateHost: Expected hostname in server certificate (defaults to address)
tcp
group
Raw TCP connection. Bindings to this service only support connect(), not fetch().
  • tlsOptions: TLS configuration
  • certificateHost: Expected hostname in server certificate

Examples

const backendServer :Workerd.ExternalServer = (
  address = "10.0.1.5:8080",
  http = (),
);
All fetch() calls on a service binding to an ExternalServer are delivered to that server, regardless of the hostname or protocol in the URL. The original hostname is preserved in the request headers.

Disk directory services

Disk directory services expose an HTTP interface to a directory on disk. This is bare-bones and typically wrapped in a worker that adds proper Content-Type headers and other logic.
path
Text
Filesystem path to the directory. Can be overridden from command line with --directory-path <service-name>=<path>.
Relative paths are interpreted relative to the current working directory, not the config file. Use absolute paths in config files.
writable
Bool
default:false
Whether to support PUT requests for writing files. Uploads are written to a temporary file and atomically moved into place on completion. Parent directories are created as needed.
allowDotfiles
Bool
default:false
Whether to allow access to files and directories whose name starts with .. These are hidden by default since they often store metadata not meant to be served (like .git or .htaccess).The special links . and .. are never accessible regardless of this setting.

Example

const staticFiles :Workerd.DiskDirectory = (
  path = "/var/www/static",
  writable = false,
  allowDotfiles = false,
);

HTTP interface

GET requests:
  • Files return with Content-Type: application/octet-stream and Content-Length header
  • Directories return JSON directory listings: [{"name":"foo","type":"file"},{"name":"bar","type":"directory"}]
  • Possible types: "file", "directory", "symlink", "blockDevice", "characterDevice", "namedPipe", "socket", "other"
  • Symlinks are followed automatically
  • Other inode types return 406 Not Acceptable
HEAD requests:
  • Optimized to perform stat() without opening the file
PUT requests (when writable = true):
  • Write to a temporary file, atomically moved on completion
  • Parent directories created as needed

Service designators

When referencing services from bindings or sockets, you can use a simple string or a full ServiceDesignator structure:
bindings = [
  (name = "backend", service = "backend-api"),
]
name
Text
required
Name of the service in the Config.services list.
entrypoint
Text
For modules-syntax workers with multiple named entrypoints, this specifies which one to use. export default is the default entrypoint, while export let foo = {} defines an entrypoint named "foo".
props
union
Value to provide in ctx.props in the target worker.
  • empty: Empty object (default)
  • json: JSON-encoded value

Next steps

Workers

Configure worker services in detail

Bindings

Connect services through bindings

Build docs developers (and LLMs) love