SvelteKit Local Environment Setup

seedlingLast update on Jul 18, 2026
Download .md

Ringkasan

Setup ini diambil dari masmuss/trak — aplikasi tracker full-stack dengan arsitektur monorepo Turborepo.

Stack: Svelte 5 (runes) + SvelteKit + shadcn-svelte + bits-ui + Tailwind v4 + Drizzle ORM + Better Auth + PostgreSQL.


Tools yang Dipakai

ToolFungsiInstalasi
pnpmPackage manager (monorepo)brew install pnpm
TurborepoMonorepo orchestrationpnpm add -D turbo
SvelteKitFull-stack frameworkpnpm create svelte@latest
shadcn-svelteComponent librarypnpm dlx shadcn-svelte@latest init
bits-uiHeadless UI primitivespnpm add -D bits-ui
DrizzleORM (shared package)pnpm add drizzle-orm
Better AuthAuthenticationpnpm add better-auth
VitestUnit testingpnpm add -D vitest
PlaywrightE2E testingpnpm add -D @playwright/test
LefthookGit hooksbrew install lefthook

1. Monorepo Structure (Turborepo + pnpm)

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"
// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".svelte-kit/**", ".vercel/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {},
    "check": {}
  }
}
// package.json (root)
{
  "name": "trak",
  "private": true,
  "scripts": {
    "dev": "turbo dev",
    "build": "turbo build",
    "preview": "pnpm --filter @trak/web preview",
    "check": "turbo check",
    "lint": "turbo lint",
    "format": "prettier --write .",
    "test:unit": "pnpm --filter @trak/web test:unit",
    "test": "pnpm --filter @trak/web test",
    "test:e2e": "pnpm --filter @trak/web test:e2e",
    "db:push": "pnpm --filter @trak/database db:push",
    "db:generate": "pnpm --filter @trak/database db:generate",
    "db:migrate": "pnpm --filter @trak/database db:migrate",
    "db:studio": "pnpm --filter @trak/database db:studio",
    "db:seed": "pnpm --filter @trak/web db:seed"
  }
}

Perintah Sehari-hari

pnpm dev           # Semua app via Turbo
pnpm build         # Build semua
pnpm lint          # Lint semua
pnpm db:push       # Push schema Drizzle ke DB
pnpm db:studio     # Drizzle Studio
pnpm test          # Unit + E2E

2. SvelteKit Config

// apps/web/svelte.config.ts
import adapter from "@sveltejs/adapter-auto";

const config = {
  compilerOptions: {
    // Force Svelte 5 runes mode
    runes: ({ filename }) =>
      filename.split(/[/\\]/).includes("node_modules") ? undefined : true,
  },
  kit: {
    adapter: adapter(),
  },
};

export default config;

3. Vite Config

// apps/web/vite.config.ts
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vitest/config";
import { sveltekit } from "@sveltejs/kit/vite";
import { config } from "dotenv";
import path from "path";

// Load .env from monorepo root
config({ path: path.resolve(__dirname, "../../.env") });

export default defineConfig({
  plugins: [tailwindcss(), sveltekit()],
  test: {
    include: ["src/**/*.{test,spec}.{js,ts}"],
    exclude: ["src/lib/server/**"],
  },
});

4. shadcn-svelte + bits-ui

Init

cd apps/web
pnpm dlx shadcn-svelte@latest init
pnpm dlx shadcn-svelte@latest add button card dialog form input table select

Struktur Komponen

<script lang="ts">
  import * as Card from '$lib/components/ui/card';
  import { Button } from '$lib/components/ui/button';
  import { Separator } from '$lib/components/ui/separator';
</script>

<Card.Root>
  <Card.Header>
    <Card.Title>Title</Card.Title>
    <Card.Description>Description</Card.Description>
  </Card.Header>
  <Card.Content>Content here</Card.Content>
  <Card.Footer>
    <Button>Action</Button>
  </Card.Footer>
</Card.Root>

Library Tambahan

LibraryFungsi
formsnap + sveltekit-superformsForm handling + validasi Zod
bits-uiHeadless UI primitives (dipakai shadcn-svelte)
phosphor-svelteIcon library
mode-watcherDark/light mode toggle
svelte-sonnerToast notifications
layerchartCharts & visualisasi
tailwind-variantsComponent variant API
tw-animate-cssAnimasi Tailwind

5. Database (Shared Package)

// packages/database/package.json
{
  "name": "@trak/database",
  "scripts": {
    "db:push": "drizzle-kit push",
    "db:generate": "drizzle-kit generate",
    "db:migrate": "drizzle-kit migrate",
    "db:studio": "drizzle-kit studio"
  }
}

Schema Drizzle di-share antar app via @trak/database. App web import dari package:

// apps/web/src/lib/server/db.ts
import { db } from "@trak/database";

6. Authentication (Better Auth)

// apps/web/src/lib/server/auth.ts
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { db } from "@trak/database";

export const auth = betterAuth({
  database: drizzleAdapter(db, { provider: "pg" }),
  emailAndPassword: { enabled: true },
});

// Client-side helper
// apps/web/src/lib/auth-client.ts
import { createAuthClient } from "better-auth/client";
export const authClient = createAuthClient();

7. ESLint + Prettier

Root ESLint

// eslint.config.js (root)
import js from "@eslint/js";
import path from "node:path";
import { includeIgnoreFile } from "@eslint/compat";
import { defineConfig } from "eslint/config";
import globals from "globals";

export default defineConfig(
  includeIgnoreFile(path.resolve(import.meta.dirname, ".gitignore")),
  js.configs.recommended,
  {
    languageOptions: { globals: { ...globals.node } },
  },
);

App web punya ESLint sendiri dengan eslint-plugin-svelte.


8. Lefthook (Git Hooks)

# lefthook.yml
pre-commit:
  parallel: true
  commands:
    svelte-check:
      glob: "*.{svelte,ts,js}"
      run: pnpm --filter @trak/web run check
    prettier:
      glob: "*.{js,ts,svelte,json,css,md}"
      run: pnpm prettier --write {staged_files}
      stage_fixed: true

9. Testing

Unit (Vitest)

// apps/web/vite.config.ts (sudah include)
test: {
  include: ['src/**/*.{test,spec}.{js,ts}'],
  exclude: ['src/lib/server/**'],
}

Jalankan: pnpm test:unit

E2E (Playwright)

pnpm test:e2e
# playwright install && playwright test

10. Docker Compose

# compose.yaml
services:
  db:
    image: postgres
    restart: always
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: root
      POSTGRES_PASSWORD: mysecretpassword
      POSTGRES_DB: local
    volumes:
      - pgdata:/var/lib/postgresql
volumes:
  pgdata:

11. Monorepo File Tree

  • trak
    • apps
      • web/ # SvelteKit frontend
        • src
          • lib
            • components/ui/ # shadcn-svelte
            • features/ # Feature modules
            • server/ # Auth, db helpers
            • auth-client.ts
          • routes/ # SvelteKit routing
          • hooks.server.ts
          • app.html
        • svelte.config.ts
        • vite.config.ts
      • bot/ # Bot app
    • packages
      • database/ # Drizzle schema + config
      • services/ # Shared business logic
      • shared/ # Shared types, utils
    • pnpm-workspace.yaml
    • turbo.json
    • compose.yaml
    • lefthook.yml
    • eslint.config.js

Quick Start (Proyek Baru)

# 1. Create SvelteKit app
pnpm create svelte@latest my-app
cd my-app

# 2. Init monorepo (opsional)
pnpm add -D turbo
# Setup pnpm-workspace.yaml + turbo.json

# 3. Add core deps
pnpm add -D @sveltejs/adapter-auto @tailwindcss/vite tailwindcss
pnpm add -D bits-ui formsnap sveltekit-superforms zod

# 4. Init shadcn-svelte
pnpm dlx shadcn-svelte@latest init
pnpm dlx shadcn-svelte@latest add button card dialog form input

# 5. Add auth
pnpm add better-auth
pnpm add -D @better-auth/cli

# 6. Add database
pnpm add drizzle-orm postgres
pnpm add -D drizzle-kit

# 7. Setup git hooks
pnpm add -D lefthook
pnpm lefthook install

# 8. Start infrastructure
docker compose up -d

# 9. Start dev
pnpm dev

Referensi: masmuss/trak