This guide covers everything you need to set up and develop DEX locally.
Before you begin, ensure you have the following installed:
- Node.js >= 22 (check with
node --version) - pnpm >= 10.28.1 (check with
pnpm --version) - Docker and Docker Compose (for PostgreSQL)
- Git
Recommended:
git clone https://github.com/sdslabs/cms.git
cd cmspnpm installThis will install all dependencies for all workspaces (apps and packages).
pnpm prepareThis installs Husky git hooks for:
- Pre-commit: Runs Prettier formatting on staged files
- Ensures code consistency across the team
DEX requires environment variables for each application. Sample files are provided to help you get started.
Copy the sample file:
cp apps/server/sample.env apps/server/.envEdit apps/server/.env with your configuration:
# Database connection string
DB_URL=postgres://postgres:postgres@localhost:5432/postgres
# Application URLs
BACKEND_URL=http://localhost:8787
FRONTEND_URL=http://localhost:5173
# External API Keys
YOUTUBE_API_KEY=your_youtube_api_key_here
GROQ_API_KEY=your_groq_api_key_here
# Google OAuth (required for authentication)
GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret
# Waitlist feature (optional)
WAITLIST_ENABLED=falseGetting API Keys:
- YouTube API Key: Google Cloud Console - Enable YouTube Data API v3
- Groq API Key: Groq Console - For AI-powered summarization
- Google OAuth:
- Go to Google Cloud Console
- Create OAuth 2.0 Client ID
- Add authorized redirect URI:
http://localhost:8787/api/auth/callback/google
Optional Waitlist Configuration:
If you want to enable the waitlist feature, set WAITLIST_ENABLED=true and provide:
GMAIL_USER=your_gmail@gmail.com
GOOGLE_APP_PASSWORD=your_app_password
GRIST_API_KEY=your_grist_api_key
GRIST_DOC_ID=your_grist_doc_id
GRIST_TABLE_ID=Waitlist
GRIST_AUTH_TOKEN=your_random_tokenCopy the sample file:
cp apps/web/sample.env apps/web/.envEdit apps/web/.env:
VITE_BACKEND_URL=http://localhost:8787/Note: The trailing slash is important!
For local development, create apps/extension/.env.local:
WXT_BACKEND_URL=http://localhost:8787
WXT_FRONTEND_URL=http://localhost:5173For production testing, point to production servers:
WXT_BACKEND_URL=https://apidex.sdslabs.co
WXT_FRONTEND_URL=https://dex.sdslabs.coDEX uses PostgreSQL 16 with Docker Compose for local development.
pnpm db:upThis starts a PostgreSQL container in the background with:
- User:
postgres - Password:
postgres - Database:
postgres - Port:
5432
Apply database schema migrations:
pnpm db:migrateThis creates all necessary tables, indexes, and constraints.
Explore your database with a GUI:
pnpm db:studioOpens at https://local.drizzle.studio - a web-based database browser.
When you're done developing:
pnpm db:down| Command | Description |
|---|---|
pnpm db:up |
Start PostgreSQL container |
pnpm db:down |
Stop and remove PostgreSQL container |
pnpm db:migrate |
Run pending migrations |
pnpm db:generate |
Generate new migration from schema changes |
pnpm db:push |
Push schema directly (dev only, skips migrations) |
pnpm db:studio |
Open Drizzle Studio database browser |
Run all apps in development mode simultaneously:
pnpm devThis starts:
- Web App: http://localhost:5173
- Server: http://localhost:8787
- Extension: Development build with hot reload
If you want to run apps separately:
Web App:
pnpm --filter @repo/web devServer:
pnpm --filter @repo/server devExtension:
cd apps/extension
pnpm dev- Web Interface: http://localhost:5173
- API Server: http://localhost:8787
- API Documentation: http://localhost:8787/api/trpc (tRPC endpoints)
- Authentication: http://localhost:8787/api/auth/\*
cd apps/extension
pnpm devThis builds the extension in watch mode and outputs to .output/chrome-mv3-dev/.
- Open Chrome and navigate to
chrome://extensions/ - Enable Developer mode (toggle in top-right)
- Click Load unpacked
- Select the folder:
apps/extension/.output/chrome-mv3-dev/
- Click the extension icon in toolbar, or
- Press
Ctrl+Shift+X(Windows/Linux) orCmd+Shift+X(Mac) - The extension overlay appears in the top-right of any webpage
The extension automatically reloads when you make code changes. If it doesn't:
- Press
Alt+R(reload extension command) - Or manually click the reload button in
chrome://extensions/
cd apps/extension
pnpm dev:firefoxLoad in Firefox:
- Navigate to
about:debugging#/runtime/this-firefox - Click Load Temporary Add-on
- Select any file in
apps/extension/.output/firefox-mv3-dev/
Chrome:
cd apps/extension
pnpm build # Build for Chrome
pnpm zip # Package as ZIP for Chrome Web StoreFirefox:
pnpm build:firefox
pnpm zip:firefoxOutput location: apps/extension/.output/[browser]-mv3.zip
Dex uses Drizzle ORM for type-safe database migrations. The migration workflow involves two steps: generating migration files from schema changes, then applying them to the database.
Edit schema files in apps/server/src/db/schema/:
// apps/server/src/db/schema/collections.ts
export const collections = pgTable("collections", {
id: text("id").primaryKey(),
title: text("title").notNull(),
description: text("description"), // ← New field added
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});pnpm db:generateThis command:
- Compares your schema with the database
- Generates SQL migration files in
apps/server/src/db/drizzle/ - Creates timestamped files like
0005_cool_name.sql
Always review the generated SQL before proceeding to ensure it matches your intent.
pnpm db:migrateThis command:
- Applies all pending migrations to the database
- Updates the migrations tracking table
- Executes SQL in transaction (rollback on error)
# 1. Make schema changes
# Edit apps/server/src/db/schema/collections.ts
# 2. Generate migration
pnpm db:generate
# Output: ✓ Generated migration: 0005_add_collection_description.sql
# 3. Review the SQL file
cat apps/server/src/db/drizzle/0005_add_collection_description.sql
# 4. Apply migration
pnpm db:migrate
# Output: ✓ Migrations applied successfully
# 5. Verify changes
pnpm db:studioFor rapid prototyping, push schema changes directly without creating migrations:
pnpm db:pushWarning: This bypasses migration history. Use only in development.
When to use:
- Initial schema exploration
- Throwaway prototypes
- Local development experiments
When NOT to use:
- Production environments
- Shared development databases
- Any database with data you want to keep
- Always review generated SQL before committing to catch unexpected changes
- Test migrations on a copy of production data before deploying
- Never edit applied migrations - create a new migration to fix issues
- Use descriptive schema changes so generated migration names are meaningful
- Commit migrations to version control along with schema changes
- Run migrations in CI/CD to catch issues before production
DEX uses shadcn/ui components in the shared @repo/ui package.
pnpm ui-add <component-name>Examples:
pnpm ui-add button
pnpm ui-add dialog
pnpm ui-add dropdown-menuComponents are added to packages/ui/components/ and automatically available to all apps.
pnpm formatFormats all TypeScript, JavaScript, JSON, Markdown, and CSS files with Prettier.
pnpm lintRuns ESLint across all workspaces.
pnpm check-typesRuns TypeScript compiler in check mode (no output, just validation).
Husky automatically runs:
- Prettier on staged files (via lint-staged)
- Prevents commits with formatting issues
pnpm buildBuilds all applications in the correct dependency order (Turborepo handles this).
pnpm --filter @repo/web build
pnpm --filter @repo/server build
pnpm --filter dex build- Web:
apps/web/dist/- Static files ready for Nginx - Server:
apps/server/dist/- Node.js executable - Extension:
apps/extension/.output/chrome-mv3/- Extension files
If ports 5173, 8787, or 5432 are already in use:
Find and kill the process:
# On macOS/Linux
lsof -ti:5173 | xargs kill -9
lsof -ti:8787 | xargs kill -9
# On Windows
netstat -ano | findstr :5173
taskkill /PID <PID> /FOr change the port in your .env files.
Check if PostgreSQL is running:
docker psYou should see a container named postgres or similar.
Restart the database:
pnpm db:down
pnpm db:up
pnpm db:migrateIf you encounter dependency issues:
pnpm reinstallThis script:
- Removes all
node_modules/directories - Removes
pnpm-lock.yaml - Clears pnpm store cache
- Reinstalls everything fresh
- Check the browser console for errors
- Ensure
.env.localhas correct URLs - Rebuild:
cd apps/extension && pnpm build - Reload extension in
chrome://extensions/
After changing server procedures:
- Stop the dev server
- Run
pnpm buildto regenerate types - Restart
pnpm dev
Server variables: Must be in apps/server/.env
Web variables: Must be in apps/web/.env and prefixed with VITE_
Extension variables: Must be in apps/extension/.env.local and prefixed with WXT_
Restart the dev server after changing environment variables.
Install recommended extensions (workspace should prompt you):
- ESLint
- Prettier
- Tailwind CSS IntelliSense
- Prisma (for Drizzle schema syntax highlighting)
Settings:
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
}
}The monorepo uses path aliases for clean imports:
// ✅ Instead of this:
import { Button } from "../../../packages/ui/components/button";
// ✅ Use this:
import { Button } from "@repo/ui/components/button";Aliases are configured in each app's tsconfig.json.
# 1. Start database
pnpm db:up
# 2. Pull latest changes
git pull origin main
# 3. Install new dependencies (if any)
pnpm install
# 4. Run migrations (if any)
pnpm db:migrate
# 5. Start development
pnpm dev
# 6. Make changes, test locally
# 7. Format and commit
pnpm format
git add .
git commit -m "feat: add new feature"
# 8. Push changes
git push origin feature/your-feature-name- Web App: http://localhost:5173 - Test UI changes
- Extension: Load in Chrome and test on real websites
- API: Use tRPC panel or tools like Postman
- Database: Check changes in Drizzle Studio
- GitHub Issues: Report bugs or request features
- Discussions: Ask questions or share ideas
- Documentation: Refer to other docs in
/docs/
Happy coding!