Build products,
not boilerplate

Ship is an AI-native, batteries-included full-stack TypeScript SaaS starter

Terminal
$ npx @paralect/ship init
 
? Database: Postgres
? Infra plugins: Sockets, Storage, Queue, Emails
? Features: Auth, Stripe, AI Chat
 
Scaffolded apps/api/ — 14 endpoints
Scaffolded apps/web/ — Next.js + landing page
Installed auth stripe ai-chat emails
Created packages/ — db, storage, emails, ai, queue, payments
 
Ship ready. Run pnpm dev to start.
list.ts — ship
Explorer
▾ resources/
▾ users/
▾ endpoints/
list.ts
create.ts
update.ts
remove.ts
▸ methods/
▸ jobs/
▸ crons/
users.schema.ts
▸ teams/
▸ payments/
▾ packages/
db/
storage/
emails/
ai/
queue/
payments/
TS list.ts
TS users.schema.ts
1import { z } from 'zod'
2import { db } from '@packages/db'
3
4export default {
5  method'GET',
6  path'/',
7
8  query: z.object({
9    page: z.number().default(1),
10    perPage: z.number().default(20),
11  }),
12
13  async handler(ctx) {
14    const results =await db
15      .select().from(users)
16    return { results }
17  }
18}
Y
JD
Dashboard
+ New Order
Revenue
$24.8k
Orders
384
Customers
126
Order Amount Status
#ORD-2847 $1,240 Paid
#ORD-2846 $890 Paid
#ORD-2845 $2,100 Pending
#ORD-2844 $650 Paid
#ORD-2843 $430 Shipped
Hono Hono
·
oRPC oRPC
·
Next.js Next.js
·
Drizzle Drizzle
·
Postgres Postgres
·
Redis Redis
·
Zod Zod
·
Shadcn Shadcn
·
Tailwind Tailwind
·
BullMQ BullMQ
How it works

Build on top of clean standard patterns

Every resource owns its schema, endpoints, middlewares, handlers, crons and methods. Files are mounted by path, types flow from the API to the client. One obvious way to do things, for you and your agents.

Endpoint: one file, mounted by its path

[userId]/update.ts becomes PUT /users/{userId}. Zod validates input and output, gates put the user on context.

Hono HonooRPC oRPCZod Zod
apps/api/src/resources/users/endpoints/[userId]/update.ts
1 import { ORPCError } from '@orpc/server';
2 import { z } from 'zod';
3
4 import db from '@/db';
5 import endpoint from '@/endpoint';
6 import isAdmin from '@/middlewares/is-admin';
7 import { publicSchema } from '../users.schema';
8
9 export default endpoint
10 .use(isAdmin)
11 .input(
12 z.object({
13 userId: z.string().min(1),
14 fullName: z.string().min(1).max(128).optional(),
15 isAdmin: z.boolean().optional(),
16 }),
17 )
18 .output(publicSchema)
19 .handler(async ({ input }) => {
20 const { userId, ...data } = input;
21
22 const user = await db.users.findFirst({
23 where: { id: userId, deletedAt: null },
24 });
25 if (!user) {
26 throw new ORPCError('NOT_FOUND', {
27 message: 'User not found',
28 });
29 }
30
31 const updated = await db.users.updateOne(
32 { id: userId },
33 data,
34 );
35 return updated!;
36 });
file name → route
1 resources/users/endpoints/
2 ├── list.ts GET /users
3 ├── current.get.ts GET /users/current
4 ├── current.patch.ts PATCH /users/current
5 ├── dev-verify-email.post.ts POST /users/dev-verify-email
6 └── [userId]/
7 ├── update.ts PUT /users/{userId}
8 └── delete.ts DELETE /users/{userId}
9
10 // codegen-router.ts watches this tree and rewrites
11 // src/router.ts and src/contract.ts on save.
12 // The web app imports the contract, so
13 // apiClient.users.update({ userId, fullName })
14 // is typed before the request leaves the browser.
Plugins

Every feature is a separate plugin

A plugin is a folder of API resources, web routes and packages that merges into your codebase. Once installed the files are yours to edit. Like shadcn, but for your entire stack.

$ npx @paralect/ship install ai-chat
Created apps/api/src/resources/ai-chats/ai-chats.schema.ts
Created apps/api/src/resources/ai-chats/endpoints/send-message.ts
Created apps/web/src/routes/_authenticated/app/ai-chat/index.tsx
Created packages/ai/src/index.ts
Infrastructure
plugin
Database
plugins/postgres → @ship/db

Drizzle ORM + Postgres. DbService per table, codegen, migrations, soft delete, mutation events.

postgresdrizzlecodegen-db
plugin
Cloud storage
plugins/cloud-storage → @ship/cloud-storage

S3-compatible uploads and presigned URLs. Garage in Docker locally, Wasabi or AWS in production.

s3garagepresigned urls
plugin
Mailer
plugins/mailer → @ship/emails

React Email templates sent through Resend. Preview server on localhost:4000 while you edit.

resendreact-email
built in
Websockets
apps/api/src/socket-server.ts

Socket.IO with a Redis adapter. ioEmitter.publishToUser() from any handler, rooms gated by session.

socket.ioredis
built in
Scheduler
apps/api/src/scheduler

Crons discovered from resources/*/crons. Runs as its own process with its own Dockerfile.

node-schedulecrons
cli option
Deploy
deploy/

DigitalOcean Apps, Render, DigitalOcean Kubernetes or AWS EKS. Dockerfiles for api, web, scheduler and migrator.

dockerdo-appsrendereks
Feature plugins : API resources + web routes
plugin

Auth

plugins/auth-starter

better-auth: email + password, verification, reset, Google OAuth. Sign-in pages and the app shell.

plugin

Admin

plugins/admin

Admin dashboard with a paginated, searchable user list. isAdmin gate on the API.

plugin

AI chat

plugins/ai-chat → @ship/ai

Conversations and messages on the Vercel AI SDK. Gemini by default, swap the model in one call.

plugin

Notes

plugins/notes

The minimal example: schema, 3 endpoints, a canEdit middleware and a route. Copy it for your own resource.

Get started

Configure and go

One command asks 3 questions, then scaffolds the monorepo, installs the plugins, runs codegen and writes the first migration.

Setup
Plugins
auth-starter needs mailer and cloud-storage. admin and ai-chat need auth-starter.
Deployment
Prerequisites: Node 22+, pnpm, Docker for Postgres and Redis · OrbStack recommended on Mac
Terminal
$ npx @paralect/ship init my-app
Hey! Let's build your Ship
? Which setup do you want? PostgreSQL + TanStack Start (full-stack, default)
? Which plugins do you want to install? mailer, cloud-storage, auth-starter, admin
? What deployment type would you like to use? DigitalOcean Apps
Installing plugins: postgres, mailer, cloud-storage, auth-starter, admin
Installing packages. This might take a couple of minutes.
codegen: src/router.ts, src/contract.ts, src/db.ts
drizzle generate: 1 migration
Initialized a git repository.
Success! Created my-app at ~/my-app
We suggest that you begin by typing:
cd my-app
pnpm run start
apps/api + apps/web, 5 plugins
Coming soon

Ship Dashboard

A local page for every running service, with an API explorer that reads resources/*: each endpoint with its route, middlewares and schemas, plus crons, handlers and methods.

Endpoints
14 routes
GET /users 200 · 12ms
GET /users/current 200 · 9ms
PATCH /users/current 200 · 31ms
PUT /users/{userId} 200 · 23ms
DEL /users/{userId} 200 · 8ms
POST /files/upload 200 · 84ms
GET /notes 200 · 15ms
POST /ai-chats/{chatId}/messages 200 · 1.2s
Coming soon
© 2026 Paralect, Inc 651 N Broad St, Suite 206, Middletown, 19709, Delaware, United States