Skip to main content

Overview

Midday is organized as a monorepo using Bun workspaces and Turborepo for efficient development and building. This structure enables code sharing across multiple applications while maintaining clear boundaries.

Package Manager: Bun

Midday uses Bun 1.3.10 as its package manager and runtime:
package.json
{
  "packageManager": "[email protected]",
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}

Why Bun?

  • Fast: 20-30x faster than npm/yarn for installations
  • Built-in TypeScript: Native TypeScript support without transpilation
  • Hot reload: Instant development feedback
  • All-in-one: Runtime, test runner, bundler, and package manager

Installing Dependencies

# Install all dependencies in workspace
bun install

Workspace Structure

midday/
├── apps/
   ├── dashboard/          # Main Next.js app
   ├── api/                # Hono API server
   ├── website/            # Marketing site
   ├── desktop/            # Tauri desktop app
   └── worker/             # Background jobs
├── packages/
   ├── db/                 # Database layer
   ├── ui/                 # Shared components
   ├── supabase/           # Supabase client
   ├── banking/            # Banking logic
   ├── invoice/            # Invoice logic
   ├── utils/              # Utilities
   └── .../                # 23+ more packages
├── turbo.json              # Turborepo config
├── package.json            # Root package.json
├── bun.lock                # Lock file
└── tsconfig.json           # Base TypeScript config

Turborepo Configuration

Turborepo orchestrates builds, tests, and development across the monorepo:
turbo.json
{
  "$schema": "https://turborepo.org/schema.json",
  "globalDependencies": ["**/.env"],
  "ui": "stream",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [
        ".next/**",
        "!.next/cache/**",
        "dist/**",
        "lib/**"
      ]
    },
    "dev": {
      "persistent": true,
      "cache": false
    },
    "lint": {
      "dependsOn": ["^topo"]
    },
    "typecheck": {
      "outputs": []
    },
    "test": {
      "cache": false
    }
  }
}

Key Features

Task Caching

Turbo caches build outputs. If nothing changed, it skips the build.

Parallel Execution

Runs tasks across workspaces in parallel for maximum speed.

Dependency Graph

Understands dependencies between packages and builds in the correct order.

Incremental Builds

Only rebuilds what changed since the last build.

Package Scripts

Root-level scripts in package.json:
package.json
{
  "scripts": {
    // Development
    "dev": "turbo dev --parallel",
    "dev:dashboard": "turbo dev --filter=@midday/dashboard",
    "dev:api": "turbo dev --filter=@midday/api",
    "dev:website": "turbo dev --filter=@midday/website",
    "dev:desktop": "turbo dev --filter=@midday/desktop",
    
    // Building
    "build": "turbo build",
    "build:dashboard": "turbo build --filter=@midday/dashboard",
    
    // Starting
    "start:dashboard": "turbo start --filter=@midday/dashboard",
    "start:website": "turbo start --filter=@midday/website",
    
    // Code Quality
    "format": "biome format --write .",
    "lint": "turbo lint",
    "typecheck": "turbo typecheck",
    "test": "turbo test --parallel",
    
    // Maintenance
    "clean": "git clean -xdf node_modules",
    "clean:workspaces": "turbo clean"
  }
}

Running Scripts

1

Development

Start all apps in parallel:
bun dev
2

Specific App

Run a specific app using filters:
bun dev:dashboard
# or
turbo dev --filter=@midday/dashboard
3

Multiple Apps

Run multiple specific apps:
turbo dev --filter=@midday/dashboard --filter=@midday/api
4

With Dependencies

Include package dependencies:
turbo build --filter=@midday/dashboard...

Shared Packages

Packages are internal libraries shared across apps:

Package Structure

packages/db/
packages/db/
├── src/
   ├── index.ts           # Main exports
   ├── client.ts
   ├── schema.ts
   └── queries/
├── package.json           # Package config
└── tsconfig.json          # TypeScript config

Package Exports

Define clear entry points in package.json:
packages/db/package.json
{
  "name": "@midday/db",
  "private": true,
  "exports": {
    "./client": "./src/client.ts",
    "./queries": "./src/queries/index.ts",
    "./schema": "./src/schema.ts",
    "./utils/currency": "./src/utils/currency.ts"
  }
}

Using Shared Packages

apps/dashboard/src/app/page.tsx
// Import from shared packages
import { db } from '@midday/db/client';
import { getTransactions } from '@midday/db/queries';
import { Button } from '@midday/ui/button';
import { formatCurrency } from '@midday/utils/currency';
All internal packages are marked as "private": true to prevent accidental publishing to npm.

Workspace Dependencies

Internal Dependencies

Reference other workspace packages using workspace:*:
packages/invoice/package.json
{
  "name": "@midday/invoice",
  "dependencies": {
    "@midday/db": "workspace:*",
    "@midday/utils": "workspace:*",
    "@midday/encryption": "workspace:*"
  }
}

External Dependencies

Use the catalog feature for consistent versions:
package.json (root)
{
  "catalog": {
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "typescript": "^5.9.3",
    "zod": "^4.3.5",
    "date-fns": "^4.1.0"
  }
}
Then use in packages:
packages/dashboard/package.json
{
  "dependencies": {
    "react": "catalog:",
    "zod": "catalog:"
  }
}
The catalog ensures all packages use the same version of shared dependencies.

TypeScript Configuration

Midday uses a shared TypeScript configuration:

Base Config

tsconfig.json (root)
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "skipLibCheck": true,
    "esModuleInterop": true
  }
}

Package Configs

Packages extend the base config:
packages/db/tsconfig.json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules", "dist"]
}

Shared TypeScript Config Package

packages/tsconfig/package.json
{
  "name": "@midday/tsconfig",
  "exports": {
    "./base.json": "./base.json",
    "./nextjs.json": "./nextjs.json",
    "./react.json": "./react.json"
  }
}
Usage:
apps/dashboard/tsconfig.json
{
  "extends": "@midday/tsconfig/nextjs.json"
}

Code Quality Tools

Biome (Linting & Formatting)

Midday uses Biome for fast linting and formatting:
biome.json
{
  "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
  "formatter": {
    "enabled": true,
    "indentStyle": "space",
    "lineWidth": 80
  },
  "linter": {
    "enabled": true,
    "rules": {
      "recommended": true
    }
  }
}
bun format

Testing

Bun has a built-in test runner:
packages/db/src/test/transactions.test.ts
import { describe, it, expect } from 'bun:test';
import { getTransactions } from '../queries/transactions';

describe('Transaction Queries', () => {
  it('should filter by date range', async () => {
    const results = await getTransactions({
      teamId: 'test-team',
      start: '2024-01-01',
      end: '2024-12-31',
    });
    
    expect(results).toBeArray();
  });
});
Run tests:
# All tests
bun test

# Specific package
bun test --filter=@midday/db

# Watch mode
bun test --watch

Development Workflow

1

Clone Repository

git clone https://github.com/midday-ai/midday.git
cd midday
2

Install Dependencies

bun install
3

Set Up Environment

Copy environment variables:
cp .env.example .env.local
4

Start Development

# Start all apps
bun dev

# Or start specific app
bun dev:dashboard
5

Make Changes

Edit code in any package or app. Hot reload is enabled.
6

Build

# Build all
bun build

# Build specific app
bun build:dashboard

Adding New Packages

1

Create Package Directory

mkdir -p packages/my-package/src
cd packages/my-package
2

Create package.json

packages/my-package/package.json
{
  "name": "@midday/my-package",
  "private": true,
  "exports": {
    ".": "./src/index.ts"
  },
  "scripts": {
    "lint": "biome check .",
    "typecheck": "tsc --noEmit"
  },
  "dependencies": {
    "@midday/utils": "workspace:*"
  }
}
3

Create Source Files

packages/my-package/src/index.ts
export function myFunction() {
  return 'Hello from my-package';
}
4

Add TypeScript Config

packages/my-package/tsconfig.json
{
  "extends": "../../tsconfig.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src"
  },
  "include": ["src/**/*"]
}
5

Use in Apps

Install the workspace package:
# Add to another package/app
bun add @midday/my-package --filter=@midday/dashboard
Then import:
import { myFunction } from '@midday/my-package';

Troubleshooting

Common Issues

Ensure the package is:
  1. Added to dependencies with workspace:*
  2. Has proper exports in package.json
  3. Installed: bun install
Run type check:
bun typecheck
Ensure TypeScript configs extend the base config.
Clear Turbo cache:
bun clean:workspaces
rm -rf node_modules .turbo
bun install
Restart dev server:
# Kill all processes
pkill -f "bun|turbo"

# Restart
bun dev:dashboard

Performance Tips

Use Filters

Only run tasks for packages you’re working on:
turbo dev --filter=@midday/dashboard

Leverage Cache

Turbo caches outputs. Clean builds are instant if nothing changed.

Parallel Tasks

Run independent tasks in parallel:
turbo lint test typecheck --parallel

Scope Changes

Only build what changed:
turbo build --filter=[main]

Next Steps

Architecture

Understand the overall system architecture

Database

Learn about the database layer

Contributing

Start contributing to Midday

Build docs developers (and LLMs) love