···223223224224## What's Next?
225225226226-Finally, let's learn about the prelude - built-in types available in every file.
226226+Next, let's learn about the prelude - built-in types available in every file. After that, we'll cover important information about how MLF maps to ATProto Lexicons.
+5-1
website/content/docs/language-guide/09-prelude.md
···193193194194You've now learned all the core features of MLF! You can define records, add constraints, create custom types, use unions and tokens, define XRPC operations, import from other files, and use prelude types.
195195196196-Check out the [Playground](/playground/) to experiment with MLF, or read the [CLI documentation](/docs/cli/) to learn how to compile your lexicons.
196196+## What's Next?
197197+198198+Read the [Important Info](/docs/language-guide/10-important-info/) section to understand how MLF maps to ATProto Lexicons, especially the rules for the `"main"` definition.
199199+200200+Then check out the [Playground](/playground/) to experiment with MLF, or read the [CLI documentation](/docs/cli/) to learn how to compile your lexicons.
···11++++
22+title = "Important Info"
33+weight = 10
44++++
55+66+This section covers important details about how MLF maps to ATProto Lexicons.
77+88+## The "main" Definition
99+1010+In ATProto Lexicons, each lexicon has a `defs` object where definitions are stored. One special definition is called `"main"` - it's the primary definition for that lexicon.
1111+1212+### When Does a Definition Become "main"?
1313+1414+MLF automatically determines which definition becomes `"main"` based on two rules:
1515+1616+**Rule 1: Single Main-Eligible Item**
1717+1818+If your file contains **exactly one** record, query, procedure, or subscription, it automatically becomes `"main"`:
1919+2020+```mlf
2121+// File: com/example/forum/post.mlf
2222+record post {
2323+ text: string,
2424+ author: Did,
2525+}
2626+```
2727+2828+This generates:
2929+```json
3030+{
3131+ "lexicon": 1,
3232+ "id": "com.example.forum.post",
3333+ "defs": {
3434+ "main": {
3535+ "type": "record",
3636+ ...
3737+ }
3838+ }
3939+}
4040+```
4141+4242+**Rule 2: Name Matches NSID Fragment**
4343+4444+If your definition name matches the **last segment** of the NSID, it becomes `"main"`:
4545+4646+```mlf
4747+// File: com/example/forum/post.mlf
4848+record post { // Name "post" matches last NSID segment
4949+ text: string,
5050+}
5151+5252+def type author = {
5353+ did: Did,
5454+};
5555+```
5656+5757+The `post` record becomes `"main"`, while `author` becomes a named def:
5858+5959+```json
6060+{
6161+ "lexicon": 1,
6262+ "id": "com.example.forum.post",
6363+ "defs": {
6464+ "main": {
6565+ "type": "record",
6666+ ...
6767+ },
6868+ "author": {
6969+ "type": "object",
7070+ ...
7171+ }
7272+ }
7373+}
7474+```
7575+7676+### Multiple Main-Eligible Items
7777+7878+If you have multiple main-eligible items and none match the NSID fragment, they all become named defs:
7979+8080+```mlf
8181+// File: com/example/forum/thread.mlf
8282+record post { // Doesn't match "thread"
8383+ text: string,
8484+}
8585+8686+record reply { // Doesn't match "thread"
8787+ text: string,
8888+}
8989+```
9090+9191+Generates:
9292+```json
9393+{
9494+ "lexicon": 1,
9595+ "id": "com.example.forum.thread",
9696+ "defs": {
9797+ "post": { ... },
9898+ "reply": { ... }
9999+ }
100100+}
101101+```
102102+103103+**Note:** Neither becomes `"main"` because the file is named `thread.mlf` but contains `post` and `reply`.
104104+105105+### Supporting Definitions
106106+107107+These are **never** `"main"` - they're always named defs:
108108+- `def type` definitions
109109+- `token` definitions
110110+- `inline type` definitions (don't appear in output at all)
111111+112112+### Best Practices
113113+114114+**For single-definition files:**
115115+```mlf
116116+// File: com/example/forum/post.mlf
117117+record post {
118118+ // The record name matches the filename
119119+ text: string,
120120+}
121121+```
122122+123123+**For multi-definition files:**
124124+```mlf
125125+// File: com/example/forum/post.mlf
126126+record post { // Becomes "main" (matches NSID)
127127+ text: string,
128128+ author: author,
129129+}
130130+131131+def type author = { // Named def: "author"
132132+ did: Did,
133133+ handle: Handle,
134134+};
135135+136136+token draft; // Named def: "draft"
137137+token published; // Named def: "published"
138138+```
139139+140140+**For shared types files:**
141141+```mlf
142142+// File: com/example/forum/defs.mlf
143143+def type author = {
144144+ did: Did,
145145+};
146146+147147+def type postRef = {
148148+ uri: AtUri,
149149+};
150150+```
151151+152152+When the NSID ends with `defs`, all items become named defs (no `"main"`).
153153+154154+## NSID and File Path Mapping
155155+156156+The file path **is** the NSID. MLF derives the lexicon NSID from the file path:
157157+158158+| File Path | NSID | Last Segment |
159159+|-----------|------|--------------|
160160+| `com/example/forum/post.mlf` | `com.example.forum.post` | `post` |
161161+| `com/example/forum/thread.mlf` | `com.example.forum.thread` | `thread` |
162162+| `com/example/forum/defs.mlf` | `com.example.forum.defs` | `defs` |
163163+164164+The last segment determines which definition becomes `"main"` (when using Rule 2).
165165+166166+## Reserved Names
167167+168168+You **cannot** use these as definition names under any circumstances:
169169+- `main` - Reserved for the main definition
170170+- `defs` - Reserved for the definitions container
171171+172172+MLF will reject these names even with raw identifiers (backticks).
173173+174174+## Reserved Keywords and Raw Identifiers
175175+176176+MLF has reserved keywords that normally cannot be used as field or type names:
177177+178178+```
179179+as, blob, boolean, bytes, constrained, def, error, inline, integer,
180180+null, procedure, query, record, string, subscription, token,
181181+type, unknown, use
182182+```
183183+184184+**Note:** The `number` type is not supported by ATProto Lexicons. Only `integer` is available for numeric values.
185185+186186+However, you can use keywords as identifiers by wrapping them in **backticks** (`` ` ``):
187187+188188+```mlf
189189+def type metadata = {
190190+ `type`: string, // "type" is a keyword, escaped with backticks
191191+ `record`: AtUri, // "record" is a keyword, escaped
192192+ `error`: string, // "error" is a keyword, escaped
193193+ name: string, // "name" is not a keyword, no escaping needed
194194+};
195195+```
196196+197197+This is useful for compatibility with existing ATProto schemas that use these names.
198198+199199+**Type names can also be escaped:**
200200+```mlf
201201+def type `record` = { // Type name "record" escaped
202202+ uri: AtUri,
203203+ cid: Cid,
204204+};
205205+```
206206+207207+**When you need raw identifiers:**
208208+- Importing existing ATProto lexicons that use keyword names
209209+- Maintaining compatibility with JSON schemas
210210+- Working with established conventions in the ATProto ecosystem
211211+212212+**Important:** This only works for field names and type names. You cannot escape `main` or `defs` - they are always forbidden.
213213+214214+## Summary
215215+216216+- **Single main-eligible item** → automatically becomes `"main"`
217217+- **Name matches last NSID segment** → becomes `"main"`
218218+- **Neither condition met** → all items become named defs
219219+- **Supporting definitions** (def type, token) → always named defs
220220+- **File path** → determines the NSID