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

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 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 and 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 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, the orchestrator coordinates the entire deployment lifecycle. It manages the internal job queue (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 defines a common interface that every cloud provider must implement. Concrete implementations like packages/adapters/src/vercel.ts and 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.

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, enabling code sharing between the web app, core logic, and adapters while maintaining clear boundaries as shown in 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 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), 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:


# 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:

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:

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 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.
  • 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. 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 and utilized by the orchestrator in 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →