Development Guide
Shipkit is built for developers who want to ship fast. Let's get you set up and building.
Quick Start
Get Shipkit running in 4 steps:
-
Clone the repo:
git clone https://github.com/your-repo/shipkit.git cd shipkit -
Install dependencies:
bun install --frozen-lockfile -
Set up environment:
cp .env.example .env.local # Edit .env.local with your values -
Start developing:
bun dev
That's it! You're ready to build.
What You Need
Required Tools
- Node.js v18+ (download)
- Bun v1.1+ (install)
- PostgreSQL v15+ (for database features)
- VS Code (recommended)
VS Code Setup
Install these extensions for the best experience:
- Biome - Code formatting and linting
- Tailwind CSS IntelliSense - CSS autocompletion
- TypeScript Importer - Smart imports
- MDX - Markdown with JSX support
Project Structure
Shipkit follows a clean, logical structure:
src/
├── app/ # Next.js App Router pages
├── components/ # React components
│ ├── ui/ # Reusable UI components
│ └── blocks/ # Page-specific components
├── lib/ # Utility functions
├── server/ # Backend code
│ ├── actions/ # Server actions
│ ├── auth/ # Authentication config
│ └── services/ # Business logic
└── styles/ # Global styles
Development Workflow
Components
- Server components first - Better performance, fewer bugs
- Client components only when needed - For interactivity (forms, animations)
- Organize by purpose - UI components in
ui/, page blocks inblocks/
API Routes
- Server actions for forms and mutations
- API routes for external integrations
- Zod validation on all inputs
- Consistent error handling
Database
- Drizzle ORM for type-safe queries
- Migrations for schema changes
- Transactions for data consistency
Authentication
- Auth.js v5 for all auth needs
- Multiple providers supported
- Server-side sessions preferred
Common Tasks
Add a New Page
# Create app/(app)/my-page/page.tsx
export default function MyPage() {
return <div>Hello World</div>;
}
Add a Component
// src/components/ui/my-component.tsx
export function MyComponent() {
return <div>My Component</div>;
}
Add Database Schema
bun run db:generate
# Edit the migration file
bun run db:migrate
Feature Flags
Control features with environment variables:
# Enable Stripe payments
NEXT_PUBLIC_FEATURE_STRIPE_ENABLED=true
# Enable GitHub auth
NEXT_PUBLIC_FEATURE_AUTH_GITHUB_ENABLED=true
Features auto-enable when you add the required env vars.
Design-system lint (@shadcn/lint)
bun run lint:eslint includes @shadcn/lint, an
ESLint plugin that checks Tailwind v4 usage against Shipkit's own design system: it reads
components.json, src/styles/theme.css, and each component's variants, and reports when a
call site restyles a component or hardcodes an off-token value instead of using what the
component already offers.
Two rules are enabled, both in eslint.config.mjs:
shadcn/no-restyleflagsclassNameoverrides on design-system components. Contracts (also ineslint.config.mjs) set what each component accepts:Button: layout/margin/width only; padding, height, radius, and type come fromsize(src/components/ui/button.tsx).CardTitlemay resize text, not change font family or weight (src/components/ui/card.tsx).CardContentmay change spacing (padding/gap), not typography or color.- Every other recognized
src/components/ui/**component defaults to layout-only.
shadcn/no-arbitrary-valuesflags off-scale values likep-[13px]in favor of the theme's spacing/radius/color scale (layout values such asw-[320px]are still allowed).
Both rules are set to warn, not error, because existing code already has hundreds of
findings and error would fail CI on unrelated, pre-existing code. Fix findings as you touch those files; promote a rule to error once it's
clean.
src/components/ui/** and src/components/blocks/** are excluded from ESLint entirely (see
the ignores in eslint.config.mjs), so these rules only apply at call sites, not inside the
components themselves.
To add or loosen a contract, edit the contracts array under shadcn/no-restyle in
eslint.config.mjs. See the design-systems docs
for the contract and custom-message format. To silence a specific, reviewed exception:
<Button
// eslint-disable-next-line shadcn/no-restyle -- reason
className="p-4"
/>
Before Production
Run these checks:
# Type checking
bun run typecheck
# Code quality
bun run lint
# Tests (if you have them)
bun run test
# Build test
bun run build