# How Openship's Architecture Works: A Deep Dive into the Modular Monorepo

> Understand Openship's modular monorepo architecture. Explore its Next.js dashboard, Prisma DB, orchestrator, and pluggable adapters for flexible multi-platform deployments.

- Repository: [oblien/openship](https://github.com/oblien/openship)
- Tags: architecture
- Published: 2026-07-23

---

**Openship's architecture is a monorepo-based deployment platform that separates concerns into a Next.js web dashboard, a Prisma-backed database layer, a core orchestrator for lifecycle management, and pluggable adapters for cloud providers, enabling extensible multi-platform deployments without modifying core code.**

Openship is an open-source deployment orchestrator built as a **monorepo** that stitches together a web front-end, persistent storage, and cloud-adapter modules. Understanding Openship's architecture reveals how it manages complex deployment workflows across diverse platforms like Vercel, Docker, and SSH/SFTP through a clean separation of concerns and a plugin-based adapter system as implemented in `oblien/openship`.

## The Four Core Components of Openship's Architecture

### Web UI (Next.js Dashboard)

The user-facing layer lives in [`apps/web/pages/index.tsx`](https://github.com/oblien/openship/blob/main/apps/web/pages/index.tsx) and provides the interface for creating projects, viewing deployment status, and configuring adapters. Built on Next.js, this dashboard communicates with the backend through a thin API layer, abstracting the complexity of deployment orchestration behind a clean visual interface while remaining decoupled from the core logic.

### Database Layer (Prisma Schema)

All persistent state resides in a database managed by **Prisma**. The schema definitions in [`packages/db/src/schema/project.ts`](https://github.com/oblien/openship/blob/main/packages/db/src/schema/project.ts) and [`packages/db/src/schema/deployment.ts`](https://github.com/oblien/openship/blob/main/packages/db/src/schema/deployment.ts) define the data models for projects, deployments, secrets, and logs. The main export in [`packages/db/src/schema/index.ts`](https://github.com/oblien/openship/blob/main/packages/db/src/schema/index.ts) provides type-safe database access across the entire monorepo, ensuring compile-time safety for all domain objects accessed by adapters and the orchestrator.

### Core Orchestrator

Located in [`packages/core/src/orchestrator.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/orchestrator.ts), the orchestrator coordinates the entire deployment lifecycle. It manages the internal job queue ([`packages/core/src/jobQueue.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/jobQueue.ts)), invokes the appropriate adapters based on the project's `adapter` field, persists results, and emits events. This component acts as the central nervous system, reading deployment records from Prisma and enqueueing jobs for execution by the appropriate platform adapter.

### Pluggable Adapters

The adapter system in [`packages/adapters/src/adapter.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/adapter.ts) defines a common interface that every cloud provider must implement. Concrete implementations like [`packages/adapters/src/vercel.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/vercel.ts) and [`packages/adapters/src/ssh-sftp.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/ssh-sftp.ts) translate the generic deployment model into platform-specific actions. Each adapter registers itself with the orchestrator's adapter registry, allowing new providers to be added without modifying core orchestration logic.

## Data Flow Through Openship's Architecture

The deployment lifecycle follows a predictable pipeline that demonstrates how Openship's architecture handles state transitions:

1. **User Interaction** – A user creates a project or triggers a deployment via the web UI or CLI.
2. **Persistence** – The request is stored via Prisma using `prisma.project.create` or `prisma.deployment.create`, establishing a record with `status: 'queued'`.
3. **Orchestration** – The core orchestrator reads the deployment record, selects the appropriate adapter based on the project's configuration, and enqueues the job in the internal queue.
4. **Adapter Execution** – The selected adapter executes platform-specific steps (building Docker images, uploading artifacts, configuring DNS), updating the database with intermediate status via `deployment.update` after each step.
5. **Result Propagation** – Upon completion, the orchestrator marks the deployment as **success** or **failed**, stores logs, and notifies the UI through websockets defined in [`packages/websocket/server.ts`](https://github.com/oblien/openship/blob/main/packages/websocket/server.ts).

## Key Architectural Patterns

Several patterns make Openship's architecture maintainable and extensible:

**Monorepo with pnpm Workspaces** – All packages live under `packages/` and share a single [`pnpm-lock.yaml`](https://github.com/oblien/openship/blob/main/pnpm-lock.yaml), enabling code sharing between the web app, core logic, and adapters while maintaining clear boundaries as shown in [`scripts/release.ts`](https://github.com/oblien/openship/blob/main/scripts/release.ts).

**Adapter-Based Extensibility** – Adding a new cloud provider requires only implementing the `Adapter` interface and registering the class in the adapter registry. No changes to the orchestrator in [`packages/core/src/orchestrator.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/orchestrator.ts) or database schema are necessary.

**Prisma-Driven Persistence** – Type-safe database models ensure that adapters and the orchestrator interact with consistent data structures, reducing runtime errors across the deployment pipeline.

**Job Queue Reliability** – The orchestrator uses an in-process queue backed by a lightweight SQLite store (implemented in [`packages/core/src/jobQueue.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/jobQueue.ts)), enabling retries, graceful shutdowns, and failure recovery without external dependencies.

## Implementing Openship's Architecture

Developers can interact with Openship's architecture through multiple interfaces:

### Command Line Interface

Initialize a project and deploy using the Vercel adapter:

```bash

# Initialise a project (creates DB entries)

openship init my-app

# Trigger a deployment using the "vercel" adapter

openship deploy --adapter vercel

```

### Programmatic Usage (Node.js/TypeScript)

Integrate Openship directly into applications:

```typescript
import { PrismaClient } from '@prisma/client';
import { Orchestrator } from '@openship/core';
import { VercelAdapter } from '@openship/adapters';

const prisma = new PrismaClient();
const orchestrator = new Orchestrator(prisma);

// Register adapters
orchestrator.registerAdapter('vercel', new VercelAdapter());

// Create a deployment record
await prisma.deployment.create({
  data: { projectId: 1, adapter: 'vercel', status: 'queued' },
});

// Kick off the orchestration
await orchestrator.start();

```

### Custom Adapter Implementation

Create platform-specific adapters by implementing the base interface:

```typescript
import { Adapter, DeployContext } from '@openship/adapters';

export class VercelAdapter implements Adapter {
  async deploy(ctx: DeployContext): Promise<void> {
    // 1️⃣ Build Docker image
    await this.buildImage(ctx);

    // 2️⃣ Upload to Vercel
    await this.uploadToVercel(ctx);

    // 3️⃣ Update DNS / routes
    await this.configureRouting(ctx);
  }
}

```

## Summary

- Openship's architecture follows a **modular monorepo pattern** using pnpm workspaces to separate the web UI, database layer, core orchestrator, and platform adapters.
- The **orchestrator** in [`packages/core/src/orchestrator.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/orchestrator.ts) manages deployment lifecycles through an internal job queue, delegating platform-specific work to registered adapters.
- **Prisma schemas** in `packages/db/src/schema/` provide type-safe persistence for projects, deployments, and logs across all components.
- The **adapter pattern** enables support for new cloud providers (Vercel, Docker, SSH/SFTP) without modifying core logic, as demonstrated by [`packages/adapters/src/vercel.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/vercel.ts).
- Deployment data flows from user interaction → database persistence → orchestration → adapter execution → real-time UI updates via websockets.

## Frequently Asked Questions

### What database does Openship use?

Openship uses **Prisma** as its ORM layer with support for SQLite in development (via the job queue) and scalable SQL databases in production. The schema definitions in `packages/db/src/schema/` define all data models including projects, deployments, and secrets, ensuring type safety across the monorepo.

### How does Openship handle different cloud providers?

Openship handles cloud providers through a **pluggable adapter system**. Each provider implements the `Adapter` interface defined in [`packages/adapters/src/adapter.ts`](https://github.com/oblien/openship/blob/main/packages/adapters/src/adapter.ts). The core orchestrator selects the appropriate adapter based on the project's `adapter` configuration field, allowing seamless support for Vercel, Docker, Cloud Run, and SSH/SFTP deployments without core code changes.

### Can I use Openship programmatically without the web UI?

Yes. The core orchestrator and adapters are published as separate packages in the monorepo, allowing direct programmatic usage. Instantiate the `Orchestrator` class from `@openship/core`, register adapters manually using `orchestrator.registerAdapter()`, and trigger deployments via the Prisma client, as shown in the Node.js/TypeScript examples above.

### Where is the deployment job queue implemented?

The deployment job queue is implemented in [`packages/core/src/jobQueue.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/jobQueue.ts) and utilized by the orchestrator in [`packages/core/src/orchestrator.ts`](https://github.com/oblien/openship/blob/main/packages/core/src/orchestrator.ts). It uses an in-process queue backed by SQLite for persistence, enabling retries and graceful shutdowns without requiring external message brokers like Redis.