Getting Started Tutorial
This tutorial walks you through building a complete directory website from scratch using the Ever Works Minimal Directory Template. By the end, you will have a fully functional, styled, and deployable directory site with search, filtering, and pagination.
We will build a "Dev Tools Directory" — a curated list of developer tools organized by category and tag.
Prerequisites
Before you begin, make sure you have the following installed:
| Tool | Version | Check command |
|---|---|---|
| Node.js | 22+ (24 LTS recommended) | node --version |
| pnpm | 10+ | pnpm --version |
| Git | 2.30+ | git --version |
If you need to install pnpm:
corepack enable
corepack prepare pnpm@latest --activate
You should also have a code editor with TypeScript support (VS Code recommended) and a terminal.
Step 1: Clone and Install
Clone the template repository and install dependencies:
git clone https://github.com/ever-works/directory-web-minimal-template dev-tools-directory
cd dev-tools-directory
pnpm install
This is a monorepo managed by pnpm workspaces and Turborepo. The install command pulls dependencies for all packages at once.
Verify the install
Run a quick type check to confirm everything is wired up:
pnpm typecheck
If this passes with no errors, you are ready to go.
Step 2: Understand the Project Structure
Before writing any code, take a moment to understand what you are working with:
dev-tools-directory/
├── apps/
│ ├── web/ # Your main Astro site (this is what you edit)
│ ├── sample-basic/ # Reference implementation — look here for examples
│ └── web-e2e/ # Playwright end-to-end tests
├── packages/
│ ├── core/ # Data loading, types, schemas
│ ├── ui/ # Headless UI components (unstyled building blocks)
│ ├─ ─ plugins/ # Plugin system runner and types
│ ├── plugin-seo/ # Meta tags, Open Graph, JSON-LD
│ ├── plugin-pagination/ # Paginate item arrays
│ ├── plugin-filters/ # Client-side category/tag filtering
│ ├── plugin-search/ # Static search via Pagefind
│ ├── plugin-sort/ # Sort items by name, date, featured
│ ├── plugin-sitemap/ # XML sitemap generation
│ ├── plugin-breadcrumbs/ # Auto-generate breadcrumb trails
│ ├── adapters/ # Data source adapters (git, filesystem)
│ ├── sync/ # Content sync orchestration
│ └── astro-integration/ # Astro integration for plugin lifecycle hooks
├── docs/ # Documentation (you are reading it)
├── .env.example # Environment variable template
├── turbo.json # Turborepo task config
└── pnpm-workspace.yaml # Workspace definitions
Key directories in apps/web/
apps/web/
├── src/
│ ├── pages/ # Astro pages (file-based routing)
│ ├── layouts/ # Base page layout (HTML shell, header, footer)
│ ├── components/ # App-specific components (Astro + Preact islands)
│ ├── styles/ # Global CSS (Tailwind setup, theme variables)
│ └── lib/
│ ├── content.ts # Data loading utility (you rarely edit this)
│ └── plugins.config.ts # Plugin registration (you configure this)
├── .content/ # Your YAML content (created in Step 3)
├── public/ # Static assets (images, favicons)
├── astro.config.ts # Astro framework configuration
└── package.json
How data flows
- YAML files in
.content/define your directory data (items, categories, tags, config) @ever-works/corereads and parses the YAML into typed objects- Plugins process the data (SEO metadata, pagination slicing, etc.)
- Astro pages import
getContent()to access the processed data - UI components from
@ever-works/uirender the data — you style them with Tailwind
The sample app
The apps/sample-basic/ directory is a fully working reference implementation. If you ever get stuck, look there for a complete example of how everything fits together.
Step 3: Create Your Content
Content lives in apps/web/.content/. This directory holds all the YAML files that define your directory. Create it now:
mkdir -p apps/web/.content/data
3.1: Site Configuration (.works/works.yml)
Create apps/web/.content/.works/works.yml — this defines your site's identity:
company_name: "Dev Tools Directory"
item_name: "Tool"
items_name: "Tools"
copyright_year: 2026
app_url: "https://dev-tools.example.com"
logo:
favicon: "/favicon.ico"
pagination:
type: "standard"
itemsPerPage: 12
settings:
categories_enabled: true
tags_enabled: true
Field reference:
| Field | Required | Description |
|---|---|---|
company_name | Yes | Displayed in the header and page titles |
item_name | Yes | Singular name for a directory entry (e.g., "Tool") |
items_name | Yes | Plural name for directory entries (e.g., "Tools") |
copyright_year | No | Year shown in footer |
app_url | No | Canonical URL for SEO and sitemap |
logo.favicon | No | Path to favicon (relative to public/) |
pagination.type | No | "standard" (page numbers) or "infinite" (scroll) |
pagination.itemsPerPage | No | Items per listing page (default: 20) |
settings.categories_enabled | No | Show category navigation (default: true) |
settings.tags_enabled | No | Show tag navigation (default: true) |
3.2: Categories (categories.yml)
Create apps/web/.content/categories.yml — these group your items:
- id: "frontend"
name: "Frontend Frameworks"
- id: "testing"
name: "Testing"
- id: "build-tools"
name: "Build Tools"
- id: "devops"
name: "DevOps & CI/CD"
- id: "databases"
name: "Databases"
- id: "api"
name: "API & Backend"
Each category needs an id (used in item YAML to assign categories) and a name (displayed in the UI). You can optionally add icon_url and image_url for richer visuals.