# Instatic Server Architecture Using Bun.serve and Worker Pools: A Technical Deep Dive

> Discover the Instatic server architecture using Bun.serve and worker pools for efficient, isolated handling of HTTP and WebSocket traffic. Learn how CPU-intensive tasks are managed.

- Repository: [CoreBunch/Instatic](https://github.com/CoreBunch/Instatic)
- Tags: deep-dive
- Published: 2026-08-01

---

**Instatic runs a single Bun.serve instance to handle all HTTP traffic and WebSocket connections, while isolating CPU-intensive operations and untrusted plugin code in a managed pool of Bun.Worker processes.**

Instatic, developed by CoreBunch, is an open-source CMS that leverages the Bun runtime's native APIs to create a high-performance server architecture. The system combines **Bun.serve** for synchronous request handling with a sophisticated **worker pool** pattern using **Bun.Worker**, ensuring that heavy background tasks never block the main event loop.

## Single-Process HTTP Entry Point with Bun.serve

The server initializes through a single call to `Bun.serve` in [`server/index.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/index.ts) (line 69). This creates one unified HTTP server that handles all incoming traffic—admin UI, public site requests, CMS API endpoints, and WebSocket upgrades—within the same process.

```typescript
// server/index.ts (line 69)
const server = Bun.serve({
  fetch: router.handle,          // route every request through the router
  port: Number(process.env.PORT) || 3000,
  // Upgrade HTTP → WebSocket for collab
  upgrade: collabSocketUpgrade,
});

```

By centralizing the entry point, Instatic eliminates the complexity of multi-process HTTP servers while maintaining the ability to offload work through background workers.

## Centralized Request Routing

All requests pass through the handcrafted router defined in [`server/router.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/router.ts). This router matches incoming paths and dispatches them to specialized handlers without spawning additional processes.

```typescript
// server/router.ts (excerpt)
export const router = {
  async handle(req: Request) {
    const url = new URL(req.url);
    // CMS API
    if (url.pathname.startsWith('/admin/api/cms')) {
      return cmsRouter.handle(req);
    }
    // Public site
    if (url.pathname.startsWith('/_instatic')) {
      return publicRouter.handle(req);
    }
    // Fallback 404
    return new Response('Not found', { status: 404 });
  },
};

```

The router delegates to three primary destinations: CMS API handlers (`server/handlers/cms/*.ts`), public site routes (`server/publish/*.ts`), and WebSocket upgrade logic ([`server/collab/socket.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/collab/socket.ts)) for real-time collaborative editing.

## Worker Pool Architecture for Background Processing

For CPU-intensive or isolated tasks, Instatic does not spawn processes directly from request handlers. Instead, it maintains a **managed pool of Bun.Worker instances** orchestrated by [`server/plugins/host/workerPool.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/host/workerPool.ts).

### Isolating Plugins with Bun.Worker

Each plugin or specialized task runs inside its own `Bun.Worker`, providing isolation for untrusted code and establishing clean crash-recovery boundaries. The system creates workers on-demand using the native `Worker` constructor:

```typescript
// server/plugins/host/workerPool.ts (excerpt)
export async function getWorker(pluginId: string): Promise<Worker> {
  const existing = workers.get(pluginId);
  if (existing) return existing;

  // Spawn a new worker that loads the plugin entrypoint
  const w = new Worker(
    new URL('../pluginWorker.ts', import.meta.url).href,
    { type: 'module' }
  );
  workers.set(pluginId, w);
  return w;
}

```

### Worker Lifecycle and State Management

The worker pool tracks active instances in a shared `Map<string, Worker>` defined in [`server/plugins/host/workerState.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/host/workerState.ts). This state management enables the pool to route API calls to existing workers, handle crashes, and automatically respawn failed processes without restarting the main server.

### Type-Safe Communication Protocol

All host-to-worker communication uses a typed message protocol defined in `server/plugins/protocol/*.ts`. These TypeBox-validated schemas guarantee type-safe RPC calls between the main thread and worker contexts:

```typescript
// server/plugins/pluginWorker.ts (excerpt)
self.onmessage = async (event) => {
  const { kind, payload } = event.data;
  if (kind === 'imageVariant') {
    const image = await generateVariant(payload);
    self.postMessage({ kind: 'response', result: image });
  }
};

```

### Concurrency Control

To prevent the server from being overwhelmed by queued jobs, the worker pool integrates with [`server/util/mapWithConcurrency.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/util/mapWithConcurrency.ts). This utility limits the number of simultaneous operations per worker pool, ensuring that background processing remains predictable under load.

## Real-World Implementation: Image Variant Generation

The image processing pipeline exemplifies the architecture's separation of concerns. When a client requests an image variant, the handler in [`server/handlers/cms/imageVariantWorkerHost.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/handlers/cms/imageVariantWorkerHost.ts) delegates the computation to a dedicated worker while immediately freeing the main thread to serve other requests.

```typescript
// server/handlers/cms/imageVariantWorkerHost.ts (excerpt)
export async function handleImageVariant(req: Request) {
  const worker = await getWorker('image-variant');
  const job = { kind: 'imageVariant', payload: {/* … */} };
  const result = await workerCall(worker, job);   // defined in workerPool.ts
  return new Response(result.image, {
    headers: { 'Content-Type': result.mime },
  });
}

```

The actual processing occurs in [`server/handlers/cms/imageVariantWorker.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/handlers/cms/imageVariantWorker.ts), which runs in complete isolation from the main server's memory space.

## Summary

- **Bun.serve** acts as the single entry point for all HTTP and WebSocket traffic, initialized in [`server/index.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/index.ts).
- The **central router** ([`server/router.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/router.ts)) dispatches requests to CMS APIs, public site handlers, or WebSocket upgrades without process forking.
- **Bun.Worker** instances provide isolation for plugins and CPU-intensive tasks, with each worker managed through the pool in [`server/plugins/host/workerPool.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/host/workerPool.ts).
- **TypeBox-validated protocols** (`server/plugins/protocol/*.ts`) ensure type-safe communication between the host and workers.
- **Concurrency limits** ([`server/util/mapWithConcurrency.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/util/mapWithConcurrency.ts)) prevent worker pools from exhausting server resources.
- **Crash resilience** is built into the worker lifecycle, allowing automatic respawning without affecting the main Bun.serve process.

## Frequently Asked Questions

### How does Instatic handle CPU-intensive tasks without blocking the main server?

Instatic delegates heavy operations to **Bun.Worker** instances running in separate JavaScript workers. The main server posts messages to these workers via [`server/plugins/host/workerPool.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/host/workerPool.ts) and continues serving other requests asynchronously. This pattern ensures that image processing or plugin execution never blocks the Bun.serve event loop.

### What communication protocol does Instatic use between the host and workers?

The system uses a typed message protocol defined in `server/plugins/protocol/*.ts`, implemented with **TypeBox** schemas. This guarantees that all RPC calls between the main thread and workers are type-safe and validated at runtime, preventing serialization errors and interface mismatches.

### How does Instatic ensure crash resilience for plugin workers?

The worker pool in [`server/plugins/host/workerPool.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/host/workerPool.ts) tracks each worker instance in a `Map<string, Worker>` (managed by [`server/plugins/host/workerState.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/plugins/host/workerState.ts)). When a worker crashes, the pool detects the failure and automatically respawns a new instance for that plugin ID, maintaining service availability without restarting the main HTTP server.

### Can the worker pool handle multiple concurrent image processing jobs?

Yes, the worker pool integrates with [`server/util/mapWithConcurrency.ts`](https://github.com/CoreBunch/Instatic/blob/main/server/util/mapWithConcurrency.ts) to limit simultaneous operations. While multiple jobs can be queued, the concurrency controller ensures that only a defined number run in parallel, preventing memory exhaustion and maintaining predictable performance for the main Bun.serve instance.