# Add a Shared Package to Your Makerkit Monorepo

> Create reusable packages for shared business logic, utilities, or components across your Turborepo monorepo applications.

*Canonical: https://makerkit.dev/docs/tanstack-supabase/development/adding-turborepo-package*

---

Create shared packages in your Makerkit monorepo using `turbo gen` to scaffold a new package at `packages/@kit/<name>`. Shared packages let you reuse business logic, utilities, or components across multiple applications while maintaining a single source of truth.

{% alert type="default" title="When to Create a Package" %}
Create a package when you have code that needs to be shared across multiple applications or when you want to enforce clear boundaries between different parts of your codebase. For code used only in `apps/web`, a folder within the app is simpler.
{% /alert %}

{% sequence title="Create a Shared Package" description="Add a new package to your monorepo" %}

[Generate the package](#step-1-generate-the-package)

[Configure exports](#step-2-configure-exports)

[Register in the Vite config](#step-3-register-in-the-vite-config)

[Use in your application](#step-4-use-the-package)

{% /sequence %}

## When to Create a Package

Create a shared package when:

- **Multiple applications**: Code needs to be used across `apps/web` and other applications
- **Clear boundaries**: You want to enforce separation between different domains
- **Reusable utilities**: Generic utilities that could be used in any application
- **Shared types**: TypeScript types shared across the codebase

Keep code in `apps/web` when:

- It's only used in one application
- It's tightly coupled to specific routes or pages
- Creating a package adds complexity without benefit

## Step 1: Generate the Package

Use the Turborepo generator to scaffold a new package:

```bash
turbo gen
```

Follow the prompts:

1. Select **"Create a new package"**
2. Enter the package name (e.g., `analytics`)
3. Optionally add dependencies

The generator creates a package at `packages/@kit/analytics` with this structure:

```
packages/@kit/analytics/
├── src/
│   └── index.ts
├── package.json
└── tsconfig.json
```

### Package.json Structure

```json {% title="packages/@kit/analytics/package.json" %}
{
  "name": "@kit/analytics",
  "version": "0.0.1",
  "main": "./src/index.ts",
  "types": "./src/index.ts",
  "exports": {
    ".": "./src/index.ts"
  },
  "scripts": {
    "typecheck": "tsc --noEmit"
  },
  "devDependencies": {
    "typescript": "^5.9.0"
  }
}
```

## Step 2: Configure Exports

### Single Export (Simple)

For packages with a single entry point, export everything from `index.ts`:

```typescript {% title="packages/@kit/analytics/src/index.ts" %}
export { trackEvent, trackPageView } from './tracking';
export { AnalyticsProvider } from './provider';
export type { AnalyticsEvent, AnalyticsConfig } from './types';
```

Import in your application:

```typescript
import { trackEvent, AnalyticsProvider } from '@kit/analytics';
```

### Multiple Exports (Tree-Shaking)

For packages with client and server code, use multiple exports for better tree-shaking:

```json {% title="packages/@kit/analytics/package.json" %}
{
  "name": "@kit/analytics",
  "exports": {
    ".": "./src/index.ts",
    "./client": "./src/client.ts",
    "./server": "./src/server.ts"
  }
}
```

Create separate entry points:

```typescript {% title="packages/@kit/analytics/src/client.ts" %}
// Client-side analytics (runs in browser)
export { useAnalytics } from './hooks/use-analytics';
export { AnalyticsProvider } from './components/provider';
```

```typescript {% title="packages/@kit/analytics/src/server.ts" %}
// Server-side analytics (runs on server only)
export { trackServerEvent } from './server/tracking';
export { getAnalyticsClient } from './server/client';
```

Import the specific export:

```typescript
// In a client component
import { useAnalytics } from '@kit/analytics/client';

// In a server function or loader
import { trackServerEvent } from '@kit/analytics/server';
```

### When to Use Multiple Exports

Use multiple exports when:

- **Client/server separation**: Code that should only run in one environment
- **Large packages**: Reduce bundle size by allowing apps to import only what they need
- **Optional features**: Features that not all consumers need

## Step 3: Register in the Vite Config

Workspace packages ship TypeScript/TSX source, so the SSR build must bundle (not externalize) them. The `apps/web/vite.config.ts` `ssr.noExternal` option already matches every `@kit/*` package via a regex, so a package named `@kit/analytics` is picked up automatically:

```typescript {% title="apps/web/vite.config.ts" %}
ssr: {
  // Bundle workspace packages (they ship TS/TSX) so the SSR runtime can
  // resolve and transpile them.
  noExternal: [
    /^@kit\//,
    '@markdoc/markdoc',
    // ... other bundled deps
  ],
},
```

If you use a scope other than `@kit`, add its package name (or a matching pattern) to `noExternal`. This ensures Vite:
1. Transpiles the package (since it's TypeScript)
2. Watches for changes and triggers HMR
3. Includes it in the SSR bundle

## Step 4: Use the Package

### Add as Dependency

Add the package to your application's dependencies:

```json {% title="apps/web/package.json" %}
{
  "dependencies": {
    "@kit/analytics": "workspace:*"
  }
}
```

Run `pnpm install` to link the workspace package.

### Import and Use

```tsx {% title="apps/web/src/routes/__root.tsx" %}
import { AnalyticsProvider } from '@kit/analytics';

function RootDocument({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <AnalyticsProvider>{children}</AnalyticsProvider>
      </body>
    </html>
  );
}
```

```tsx {% title="apps/web/src/routes/_authenticated/dashboard/index.tsx" %}
import { createFileRoute } from '@tanstack/react-router';

import { trackPageView } from '@kit/analytics';

export const Route = createFileRoute('/_authenticated/dashboard/')({
  component: HomePage,
});

function HomePage() {
  trackPageView({ page: 'home' });

  return <div>Welcome</div>;
}
```

## Package Development Patterns

### Adding Dependencies

Add dependencies to your package:

```bash
pnpm --filter @kit/analytics add zod
```

### Using Other Workspace Packages

Reference other workspace packages:

```json {% title="packages/@kit/analytics/package.json" %}
{
  "dependencies": {
    "@kit/shared": "workspace:*"
  }
}
```

### TypeScript Configuration

The package's `tsconfig.json` should extend the root configuration:

```json {% title="packages/@kit/analytics/tsconfig.json" %}
{
  "extends": "../../../tsconfig.json",
  "compilerOptions": {
    "outDir": "./dist",
    "rootDir": "./src"
  },
  "include": ["src/**/*"]
}
```

### Testing Packages

Add tests alongside your package code:

```
packages/@kit/analytics/
├── src/
│   ├── index.ts
│   └── tracking.ts
└── tests/
    └── tracking.test.ts
```

Run tests:

```bash
pnpm --filter @kit/analytics test
```

## Example: Creating a Feature Package

Here's a complete example of creating a `notifications` package:

### 1. Generate

```bash
turbo gen
# Name: notifications
```

### 2. Structure

```
packages/@kit/notifications/
├── src/
│   ├── index.ts
│   ├── client.ts
│   ├── server.ts
│   ├── components/
│   │   └── notification-bell.tsx
│   ├── hooks/
│   │   └── use-notifications.ts
│   └── server/
│       └── send-notification.ts
└── package.json
```

### 3. Exports

```json {% title="packages/@kit/notifications/package.json" %}
{
  "name": "@kit/notifications",
  "exports": {
    ".": "./src/index.ts",
    "./client": "./src/client.ts",
    "./server": "./src/server.ts"
  },
  "dependencies": {
    "@kit/supabase": "workspace:*"
  }
}
```

### 4. Implementation

```typescript {% title="packages/@kit/notifications/src/client.ts" %}
export { NotificationBell } from './components/notification-bell';
export { useNotifications } from './hooks/use-notifications';
```

```typescript {% title="packages/@kit/notifications/src/server.ts" %}
export { sendNotification } from './server/send-notification';
```

### 5. Use

```typescript
// Client component
import { NotificationBell } from '@kit/notifications/client';

// Server function
import { sendNotification } from '@kit/notifications/server';
```

## Troubleshooting

**Module not found**

1. Ensure the package is matched by `ssr.noExternal` in `apps/web/vite.config.ts`
2. Run `pnpm install` to link workspace packages
3. Check the export path matches your import

**Types not resolving**

Ensure `tsconfig.json` includes the package paths:

```json
{
  "compilerOptions": {
    "paths": {
      "@kit/*": ["./packages/@kit/*/src"]
    }
  }
}
```

**HMR not working**

Verify the package is matched by `ssr.noExternal` in `apps/web/vite.config.ts` and restart the dev server.

## Related Resources

- [Adding Turborepo Apps](/docs/tanstack-supabase/development/adding-turborepo-app) for creating new applications
