# "YAML & Project Structure"
_Path: en/start/structure_
> "Project layout, YAML definition files, and naming conventions."
## Table of Contents
- YAML & Project Structure
## Content
## Directory Layout
```
myapp/
├── .wippy.yaml # Runtime configuration
├── wippy.lock # Source directories and locked modules
├── .wippy/ # Installed modules
└── src/ # Application source
├── _index.yaml # Entry definitions
├── api/
│ ├── _index.yaml
│ └── *.lua
└── workers/
├── _index.yaml
└── *.lua
```
## YAML Definition Files
YAML definitions are loaded into the registry at startup. The registry is the source of truth; YAML files are one way to populate it. Entries can also come from other sources or be created programmatically.
### Definition File Format
A definition file contains a `namespace` and either an `entries` array or top-level `name` and `kind` fields. The optional `version` marker is conventionally `"1.0"`; the v0.3.32a loader does not require it.
```yaml
version: "1.0"
namespace: app.api
entries:
- name: get_user
kind: function.lua
meta:
comment: Fetches user by ID
source: file://get_user.lua
method: handler
modules:
- sql
- json
- name: get_user.endpoint
kind: http.endpoint
meta:
comment: User API endpoint
method: GET
path: /users/{id}
func: get_user
```
| Field | Required | Description |
|-------|----------|-------------|
| `version` | No | Manifest version marker (conventionally `"1.0"`) |
| `namespace` | Yes | Entry namespace for this file |
| `entries` | Conditional | Array of entry definitions; omit only when using top-level `name` and `kind` |
### Naming Convention
Use dots (`.`) for semantic separation and underscores (`_`) for words:
```yaml
# Function and its endpoint
- name: get_user # The function
- name: get_user.endpoint # Its HTTP endpoint
# Multiple endpoints for same function
- name: list_orders
- name: list_orders.endpoint.get
- name: list_orders.endpoint.post
# Routers
- name: api.public # Public API router
- name: api.admin # Admin API router
```
Pattern: base_name.variant — dots separate semantic parts, while underscores separate words within a part.
### Namespaces
Namespaces are dot-separated identifiers:
```
app
app.api
app.api.v2
app.workers
```
Entry full ID combines namespace and name: `app.api:get_user`
### The Lock File
`wippy.lock` records where Wippy loads definitions from and which module versions are selected:
```yaml
directories:
modules: .wippy
src: ./src
options:
unpack_modules: false
modules:
- name: acme/http
version: v1.2.0
hash: 4ea816fe84ca58a1f0869e5ca6afa93d6ddd72fa09e1162d9e600a7fbf39f0a2
```
| Field | Description |
|-------|-------------|
| `directories.src` | Application source directory, scanned recursively for YAML definition files |
| `directories.modules` | Base directory for vendored modules; packs land under `/vendor/` |
| `options.unpack_modules` | Extract each `.wapp` into a directory beside it instead of loading the pack directly (default `false`) |
| `modules[].name` | Module identifier in `org/module` form |
| `modules[].version` | Selected version |
| `modules[].hash` | Artifact digest the vendored pack must match |
| `modules[].root` | Marks the selected deployment root; at most one module may carry it |
Vendored packs are kept as `.wapp` files. With `unpack_modules: true`, each module is also extracted into a directory, and the verified `.wapp` stays beside it — installation looks for the pack, so a directory whose pack is missing is downloaded again.
A `replacements:` section in `wippy.lock` is deprecated. It still loads, with a warning; declare local module overrides under `workspace.replacements` in a runtime config file instead. See [Dependency Management](guides/dependency-management.md#local-development-with-replacements).
## Entry Definitions
Each item in the `entries` array defines one entry. Kind-specific fields can appear beside `name`, `kind`, and `meta`, as in this example:
```yaml
entries:
- name: hello
kind: function.lua
meta:
comment: Returns hello world
source: file://hello.lua
method: handler
modules:
- http
- json
- name: hello.endpoint
kind: http.endpoint
meta:
comment: Hello endpoint
method: GET
path: /hello
func: hello
```
An explicit `data:` field is also supported. When present, its value is the complete kind-specific payload, so do not mix it with sibling kind-specific fields:
```yaml
entries:
- name: config
kind: registry.entry
data:
environment: production
features:
dark_mode: true
```
### Metadata
Use `meta` for UI-friendly information:
```yaml
- name: payment_handler
kind: function.lua
meta:
title: Payment Processor
comment: Handles Stripe payments
source: file://payment.lua
```
Use `meta.title` and `meta.comment` for descriptive information that registry consumers and management interfaces can display.
### Application Entries
Use `registry.entry` kind for application-level configuration:
```yaml
- name: config
kind: registry.entry
meta:
title: Application Settings
type: application
environment: production
features:
dark_mode: true
beta_access: false
```
## Common Entry Kinds
| Kind | Purpose |
|------|---------|
| `registry.entry` | General-purpose data stored without normal event dispatch |
| `function.lua` | Callable Lua function |
| `process.lua` | Long-running process |
| `http.service` | HTTP server |
| `http.router` | Route group |
| `http.endpoint` | HTTP handler |
| `process.host` | Process execution host |
See the [Entry Kinds Guide](guides/entry-kinds.md) for the entry-kind reference.
### .wippy.yaml
Runtime configuration at project root:
```yaml
version: "1.0"
logger:
encoding: json
logmanager:
min_level: 0
supervisor:
host:
worker_count: 16
```
See the [Configuration Guide](guides/configuration.md) for runtime configuration fields.
### wippy.lock
Source directories and the selected module graph — see [The Lock File](#the-lock-file) above.
## Referencing Entries
Reference entries by full ID or relative name where the entry kind supports it. HTTP routers and endpoints attach through `meta.server` and `meta.router`, rather than through parent-side child lists:
```yaml
# Router declares itself against a server
- name: api
kind: http.router
meta:
server: app:gateway
prefix: /api
# Endpoint references router by registry ID (cross-namespace works the same way)
- name: get_user.endpoint
kind: http.endpoint
meta:
router: app.api:api
method: GET
path: /users/{id}
func: app.api:get_user
```
## Example Project
```
myapp/
├── .wippy.yaml
├── wippy.lock
└── src/
├── _index.yaml # namespace: app
├── api/
│ ├── _index.yaml # namespace: app.api
│ ├── users.lua
│ └── orders.lua
├── lib/
│ ├── _index.yaml # namespace: app.lib
│ └── database.lua
└── workers/
├── _index.yaml # namespace: app.workers
└── email_sender.lua
```
## See Also
- [Application Architecture](concepts/architecture.md) — Organize an application into slices and layers
- [Entry Kinds Guide](guides/entry-kinds.md) — Review available entry kinds
- [Configuration Guide](guides/configuration.md) — Configure runtime options
- [Custom Entry Kinds](internals/kinds.md) — Implement handlers (advanced)
## Navigation
Previous: "Installation" (start/installation)
Next: "CLI Reference" (guides/cli)