title: Project Structure description: Understand the files and directories in a hatk project.#
After creating a project with vp create github:hatk-dev/hatk-template-starter, your project looks like this:
my-app/
├── app/ # SvelteKit frontend
│ ├── app.html # HTML shell
│ ├── app.css # Global styles
│ ├── lib/ # Shared utilities
│ └── routes/ # SvelteKit routes
│ ├── +layout.svelte # Root layout
│ ├── +layout.server.ts # Server-side layout data
│ ├── +page.svelte # Home page
│ └── oauth/callback/
│ └── +page.svelte # OAuth redirect target
├── server/ # Backend logic
│ ├── recent.ts # Feed generator
│ ├── get-profile.ts # XRPC query handler
│ └── on-login.ts # Lifecycle hook
├── lexicons/ # AT Protocol schemas
│ ├── xyz/statusphere/
│ │ ├── status.json # Custom record type
│ │ └── getProfile.json # Custom query endpoint
│ └── app/bsky/actor/
│ └── profile.json # Bluesky profile (to index)
├── seeds/
│ └── seed.ts # Test fixture data
├── test/
│ ├── feeds/ # Feed unit tests
│ ├── xrpc/ # XRPC handler tests
│ ├── browser/ # Playwright browser tests
│ └── fixtures/ # Test data (YAML files)
├── db/
│ └── schema.sql # Custom SQL migrations
├── hatk.config.ts # Project configuration
├── hatk.generated.ts # Generated types (server)
├── hatk.generated.client.ts # Generated types (client)
├── vite.config.ts # Vite + SvelteKit config
├── svelte.config.js # SvelteKit adapter config
├── docker-compose.yml # Local PDS for development
├── Dockerfile # Production container build
├── tsconfig.json # TypeScript config (app)
└── tsconfig.server.json # TypeScript config (server)
app/ -- SvelteKit frontend#
The app/ directory is a standard SvelteKit application. Routes live in app/routes/, shared code goes in app/lib/. The svelte.config.js maps app/ as the SvelteKit source directory (instead of the default src/).
Auth helpers for login, logout, and reading the current viewer are imported from $hatk/client. Data fetching uses callXrpc() from the same import to call your backend's typed endpoints.
See the Frontend section for details on routing, data loading, and mutations.
server/ -- backend logic#
The server/ directory contains all your backend code. hatk auto-discovers files in this directory and registers them based on their exports:
- Feeds -- files that export
defineFeed()become feed generators, queryable viadev.hatk.getFeed - XRPC handlers -- files that export
defineQuery()ordefineProcedure()become typed API endpoints - Hooks -- files named
on-login.tsfire after OAuth authentication - OG images -- files in
server/og/generate dynamic OpenGraph images via satori - Setup scripts -- files in
server/setup/run at boot time for custom migrations or data imports - Labels -- files in
server/labels/define content moderation rules
Files prefixed with _ (like _helpers.ts) are ignored by auto-discovery, so use that convention for shared utilities.
See the guides for Feeds, XRPC Handlers, Hooks, OpenGraph, and Labels.
lexicons/ -- AT Protocol schemas#
Lexicons are JSON schemas that define your data model for the AT Protocol. They describe records (data types stored in user repositories), queries (GET endpoints), and procedures (POST endpoints).
lexicons/
├── xyz/statusphere/
│ ├── status.json # Record: a status emoji
│ └── getProfile.json # Query: get a user's profile
└── app/bsky/actor/
└── profile.json # Bluesky's profile record (to index)
Lexicons drive two things automatically:
- Database tables -- hatk creates SQLite tables for each record type
- TypeScript types --
hatk generate typesproduces typed helpers inhatk.generated.ts
Organized by reverse-DNS namespace (e.g., xyz/statusphere/status.json for the xyz.statusphere.status collection).
seeds/ -- test fixture data#
The seeds/seed.ts file creates test accounts and records against the local PDS during development. It runs automatically when you npm run dev, or manually with hatk seed.
Seeds use the AT Protocol API to create real data -- accounts, records, follows -- so your app has something to display during development without connecting to the live network.
See the Seeds guide.
test/ -- tests#
Tests are organized by type:
| Directory | Purpose | Runner |
|---|---|---|
test/feeds/ |
Feed generator unit tests | Vitest |
test/xrpc/ |
XRPC handler tests | Vitest |
test/browser/ |
End-to-end browser tests | Playwright |
test/fixtures/ |
Shared YAML test data | -- |
Run tests with npm run test (unit/integration) or npm run test:browser (Playwright).
hatk.config.ts -- configuration#
The main configuration file. Controls the relay connection, database path, backfill settings, OAuth, and more. Uses defineConfig() for type safety.
See the Configuration page for all options.
hatk.generated.ts / hatk.generated.client.ts#
Auto-generated TypeScript derived from your lexicon schemas. Do not edit these files directly.
hatk.generated.ts-- server-side types and helpers:defineFeed(),defineQuery(),defineProcedure(),seed(), typed record interfaces, and view typeshatk.generated.client.ts-- client-safe subset:callXrpc()for typed API calls,login()/logout()/parseViewer()for auth, plus re-exported types
Regenerate both with:
npx hatk generate types
vite.config.ts / svelte.config.js#
vite.config.ts-- loads thehatk()Vite plugin (which proxies API routes to the hatk backend during development) and thesveltekit()plugin. Also configures test includes/excludes.svelte.config.js-- setsapp/as the SvelteKit source directory and configures the$hatkand$hatk/clientimport aliases that point to the generated files.
db/schema.sql#
Auto-generated database reference schema. This file is written by hatk on startup and shows the current table structure.
docker-compose.yml / Dockerfile#
docker-compose.yml-- runs a local PDS and PLC directory for development. Started automatically bynpm run dev.Dockerfile-- production container build for deployment.
Runtime files#
The data/ directory is created at runtime and contains the SQLite database (hatk.db). It is gitignored by default.
data/
└── hatk.db