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:
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
Add Dependency
Remove Dependency
Update 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:
{
"$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:
{
"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
Development
Start all apps in parallel:
Specific App
Run a specific app using filters: bun dev:dashboard
# or
turbo dev --filter=@midday/dashboard
Multiple Apps
Run multiple specific apps: turbo dev --filter=@midday/dashboard --filter=@midday/api
With Dependencies
Include package dependencies: turbo build --filter=@midday/dashboard...
Shared Packages
Packages are internal libraries shared across apps:
Package Structure
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:
{
"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:
{
"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
{
"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"
}
Midday uses Biome for fast linting and formatting:
{
"$schema" : "https://biomejs.dev/schemas/1.9.4/schema.json" ,
"formatter" : {
"enabled" : true ,
"indentStyle" : "space" ,
"lineWidth" : 80
},
"linter" : {
"enabled" : true ,
"rules" : {
"recommended" : true
}
}
}
Format Code
Lint
Type Check
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
Clone Repository
git clone https://github.com/midday-ai/midday.git
cd midday
Set Up Environment
Copy environment variables: cp .env.example .env.local
Start Development
# Start all apps
bun dev
# Or start specific app
bun dev:dashboard
Make Changes
Edit code in any package or app. Hot reload is enabled.
Build
# Build all
bun build
# Build specific app
bun build:dashboard
Adding New Packages
Create Package Directory
mkdir -p packages/my-package/src
cd packages/my-package
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:*"
}
}
Create Source Files
packages/my-package/src/index.ts
export function myFunction () {
return 'Hello from my-package' ;
}
Add TypeScript Config
packages/my-package/tsconfig.json
{
"extends" : "../../tsconfig.json" ,
"compilerOptions" : {
"outDir" : "dist" ,
"rootDir" : "src"
},
"include" : [ "src/**/*" ]
}
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:
Added to dependencies with workspace:*
Has proper exports in package.json
Installed: bun install
Type errors across packages
Run type check: 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
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