Table of Contents
- 📝 File Parsers Guide
- What Are Parsers?
- The Five Main Parsers
- Properties vs File Parser — What's the Difference? 🤔
- Choosing the Right Parser
- Practical Examples
- Example 1: Minecraft Server
- Example 2: Discord Bot
- Example 3: Database Configuration
- Example 4: Code Server (File Parser on a YAML file)
- Advanced: Managing Multiple Files
- Tips and Tricks 💡
- Tip 1: Escape Special Characters
- Tip 2: Be Precise with Search Strings for the File Parser
- Tip 3: Use Dot Notation Correctly for JSON/YAML
- Tip 4: Test Your Config Before Releasing
- Tip 5: Create Default Config Files During Installation
- Common Mistakes ❌
- Mistake 1: Properties Parser — Putting the Full Line in the Value
- Mistake 2: File Parser — Forgetting to Write the Full Line
- Mistake 3: Using Minecraft server.properties With the File Parser
- Mistake 4: Wrong Dot Notation Path for YAML
- Mistake 5: Forgetting to Create the Config File During Installation
- Troubleshooting 🔧
- Problem: Variables Not Being Substituted
- Problem: File Not Being Modified
- Problem: Syntax Error in Modified File
- Problem: Right File, Wrong Parser Results
- Checklist Before Using Parsers ✅
- Real Examples from Real Eggs
- Example: Paper (Minecraft)
- Example: Code Server
- Example: 5e Tools
- Example: Ree6 Bot (partial — shows correct dot notation)
- Example: MariaDB
- See Also 📚
- Summary 📝
- Learning Path 📚
- Helpful Links 🔗
📝 File Parsers Guide
When you create eggs, you often need to update configuration files automatically. Wings uses parsers to understand different file formats. This guide teaches you how to use them! 🎯
What Are Parsers?
A parser is like a translator. It understands different file formats and can find and replace values in them.
Think of it this way:
- 📋 JSON — Structured data with braces and quotes
- 🔹 YAML — Configuration files with indentation
- 🏷️ Properties — Java-style
key=valuefiles - ⚙️ INI — Settings with
[section]blocks - 📄 File — Any plain text file, replaced line by line
Wings can edit all of these automatically!
The Five Main Parsers
1. JSON Parser 📦
Used for: Files with .json extension (like config.json)
What it looks like:
{
"server": {
"port": 8080,
"name": "My Server"
},
"features": {
"enabled": true
}
}
How to use it in your egg:
{
"config.json": {
"parser": "json",
"find": {
"server.port": "{{server.build.default.port}}",
"server.name": "{{server.build.env.SERVER_NAME}}"
}
}
}
How it works:
- Uses dot notation:
server.portfinds theportkey inside theserverobject - Nested objects:
database.credentials.hostgoes three levels deep - Arrays: use numbers to access items —
listen.0means the first item in thelistenarray,listen.1is the second, etc.
Real example from 5e-tools (array access):
{
"caddy.json": {
"parser": "json",
"find": {
"apps.http.servers.srv0.listen.0": ":{{server.build.default.port}}"
}
}
}
Real example from Corpbot (Discord bot):
{
"config.json": {
"parser": "json",
"find": {
"token": "{{server.build.env.TOKEN}}",
"prefix": "{{server.build.env.PREFIX}}"
}
}
}
Common JSON config files:
config.jsonsettings.jsonbot.jsoncaddy.json
2. YAML Parser 🔹
Used for: Files with .yml or .yaml extension
What it looks like:
server:
port: 8080
name: My Server
ssl: true
database:
host: localhost
port: 5432
credentials:
user: admin
password: secret
How to use it in your egg:
{
"config.yml": {
"parser": "yaml",
"find": {
"server.port": "{{server.build.default.port}}",
"server.name": "{{server.build.env.SERVER_NAME}}",
"database.credentials.user": "{{server.build.env.DB_USER}}"
}
}
}
How it works:
- Uses dot notation like JSON:
server.portdrills into the nested structure - Very strict about spacing — YAML uses indentation (spaces, NOT tabs!) to show structure
- Case-sensitive:
hikari.sql.useris different fromHikari.SQL.User
Real example from Ree6 (Discord bot) — showing the full parser config:
{
"config.yml": {
"parser": "yaml",
"find": {
"bot.tokens.release": "{{server.build.env.BOT_TOKEN}}",
"hikari.sql.user": "{{server.build.env.DATABASE_USER}}",
"hikari.sql.db": "{{server.build.env.DATABASE_DB}}",
"hikari.sql.pw": "{{server.build.env.DATABASE_PW}}",
"hikari.sql.host": "{{server.build.env.DATABASE_HOST}}",
"hikari.sql.port": "{{server.build.env.DATABASE_PORT}}",
"spotify.client.id": "{{server.build.env.SPOTIFY_CLIENT_ID}}",
"spotify.client.secret": "{{server.build.env.SPOTIFY_CLIENT_SECRET}}",
"twitch.client.id": "{{server.build.env.TWITCH_CLIENT_ID}}",
"twitch.client.secret": "{{server.build.env.TWITCH_CLIENT_SECRET}}",
"openai.apiToken": "{{server.build.env.AI_TOKEN}}",
"openai.apiUrl": "{{server.build.env.AI_URL}}",
"openai.model": "{{server.build.env.AI_MODEL}}",
"bot.misc.status": "{{server.build.env.MISC_STATUS}}"
}
}
}
Notice the dot notation carefully: hikari.sql.host navigates into the hikari → sql → host path in the YAML file. The key names must match the actual YAML structure exactly!
Common YAML config files:
config.ymlsettings.yaml- Application-specific configs
3. Properties Parser 🏷️
Used for: Java-style key=value files
What it looks like:
server-port=25565
max-players=20
online-mode=true
difficulty=hard
How to use it in your egg:
{
"server.properties": {
"parser": "properties",
"find": {
"server-ip": "0.0.0.0",
"server-port": "{{server.build.default.port}}",
"query.port": "{{server.build.default.port}}"
}
}
}
🚨 How it works — this is the most important part!
- The
findkey is the property name (e.g.server-port) - The
findvalue is ONLY the new value — NOT the fullkey=valueline - Wings handles writing
key=valuefor you automatically
So if you write "server-port": "{{server.build.default.port}}", Wings finds the server-port line and rewrites it as server-port=25565 (or whatever port was assigned). You never write server-port= yourself — Wings does it!
Real example from Paper (Minecraft) egg:
{
"server.properties": {
"parser": "properties",
"find": {
"server-ip": "0.0.0.0",
"server-port": "{{server.build.default.port}}",
"query.port": "{{server.build.default.port}}"
}
}
}
Real example from PhantomBot (Twitch bot):
{
"config/botlogin.txt": {
"parser": "properties",
"find": {
"baseport": "{{server.build.default.port}}",
"channel": "{{server.build.env.CHANNEL_NAME}}",
"owner": "{{server.build.env.CHANNEL_OWNER}}",
"paneluser": "{{server.build.env.WEBPANEL_USERNAME}}",
"youtubekey": "{{server.build.env.YOUTUBE_API_KEY}}"
}
}
}
Common properties files:
server.properties(Minecraft)system.propertiesbot.properties- Custom
key=valueconfig files
4. File Parser 📄
Used for: Any plain text file where you want to replace an entire line
What a target file might look like:
bind-addr: 127.0.0.1:8080
auth: password
password: changeme
cert: false
How to use it in your egg:
{
".config/code-server/config.yaml": {
"parser": "file",
"find": {
"password": "password: {{server.build.env.PASSWORD}}",
"bind-addr": "bind-addr: 0.0.0.0:{{server.build.default.port}}"
}
}
}
🚨 How it works — this is the most important part!
- The
findkey is text that appears at the start of the line you want to replace - The
findvalue is the entire replacement line — you write the completekey: valueyourself - Wings finds any line starting with that text and replaces the whole line with exactly what you wrote
So "bind-addr": "bind-addr: 0.0.0.0:{{server.build.default.port}}" tells Wings: "find any line starting with bind-addr and replace the whole line with bind-addr: 0.0.0.0:25565" (using whatever port Wings assigned).
Real example from Code Server:
{
".config/code-server/config.yaml": {
"parser": "file",
"find": {
"password": "password: {{server.build.env.PASSWORD}}",
"bind-addr": "bind-addr: 0.0.0.0:{{server.build.default.port}}"
}
}
}
Important note: This is a .yaml file but it uses "parser": "file" — and that is completely correct! The parser name does NOT have to match the file extension. The file parser treats everything as plain text and replaces lines. You pick the parser that fits how you want to edit the file, not just what the extension says.
Common file parser use cases:
- Config files where you need full control over the replacement line
- YAML-ish files where line-by-line replacement is simpler than full YAML parsing
- Any text file with an unusual
key: valueformat
5. INI Parser ⚙️
Used for: INI files with [section] blocks (like .my.cnf for MySQL/MariaDB)
What it looks like:
[mysqld]
port = 3306
bind-address = 0.0.0.0
max_connections = 100
[client]
user = admin
port = 3306
socket = /run/mysqld/mysqld.sock
How to use it in your egg:
{
".my.cnf": {
"parser": "ini",
"find": {
"mysqld.port": "{{server.build.default.port}}",
"mysqld.bind-address": "0.0.0.0",
"client.port": "{{server.build.default.port}}",
"client.user": "container"
}
}
}
How it works:
- Uses
section.keydot notation:mysqld.porttargets theportkey inside the[mysqld]section - Each section is independent —
mysqld.portandclient.portare two different keys even though they share the nameport
Real example from MariaDB egg:
{
".my.cnf": {
"parser": "ini",
"find": {
"mysqld.port": "{{server.build.default.port}}",
"client.port": "{{server.build.default.port}}",
"mysqld.bind-address": "0.0.0.0",
"mysqld.pid-file": "/home/container/run/mysqld/mysqld.pid",
"mysqld.socket": "/home/container/run/mysqld/mysqld.sock",
"client.socket": "/home/container/run/mysqld/mysqld.sock",
"client.user": "container"
}
}
}
Common INI files:
.my.cnf(MySQL/MariaDB).iniWindows-style config files- Application settings with
[section]structure
Properties vs File Parser — What's the Difference? 🤔
These two are easy to mix up! Here's the key difference side by side:
properties parser |
file parser |
|
|---|---|---|
find key |
The property name (server-port) |
Text at the start of the line (bind-addr) |
find value |
ONLY the new value (25565) |
The ENTIRE replacement line (bind-addr: 0.0.0.0:25565) |
| Wings writes | key=YOUR_VALUE for you |
Exactly what you put as the value |
| Best for | Clean key=value files like .properties |
Files where you need full control of the output line |
Properties parser example:
{
"parser": "properties",
"find": {
"server-port": "{{server.build.default.port}}"
}
}
Wings finds server-port=25565 and rewrites it as server-port=NEW_PORT. You supply only the new value.
File parser example:
{
"parser": "file",
"find": {
"bind-addr": "bind-addr: 0.0.0.0:{{server.build.default.port}}"
}
}
Wings finds any line starting with bind-addr and replaces the WHOLE line with bind-addr: 0.0.0.0:NEW_PORT. You write the full replacement line yourself.
Choosing the Right Parser
Here's a quick reference:
| File Type | Extension | Parser | Notes |
|---|---|---|---|
| JSON | .json |
json |
Dot notation for nested keys |
| YAML | .yml, .yaml |
yaml |
Dot notation for nested keys |
| Properties | .properties, .txt |
properties |
find value is ONLY the new value |
| INI | .ini, .cnf |
ini |
section.key notation |
| Plain Text | any | file |
find value is the ENTIRE replacement line |
Quick decision tree:
Does your file have {...}? → Use json
Does your file use indentation? → Use yaml
Does your file have [sections]? → Use ini
Is it simple key=value? → Use properties
Need full line replacement? → Use file
Remember: the file parser works on any text file, even .yaml ones, if you prefer simple line replacement!
Practical Examples
Example 1: Minecraft Server
Minecraft's server.properties is a Java properties file, so use the properties parser:
# server.properties
server-port=25565
max-players=20
online-mode=true
difficulty=hard
gamemode=survival
In our egg:
{
"server.properties": {
"parser": "properties",
"find": {
"server-ip": "0.0.0.0",
"server-port": "{{server.build.default.port}}",
"query.port": "{{server.build.default.port}}",
"max-players": "{{server.build.env.MAX_PLAYERS}}"
}
}
}
The values in find are just the new values — {{server.build.default.port}} becomes 25565 (or whatever Wings assigned). Wings writes server-port=25565 automatically. You do NOT include the = sign in the key!
Example 2: Discord Bot
Discord bots often use JSON config files:
Option 1: JSON config
{
"config.json": {
"parser": "json",
"find": {
"token": "{{server.build.env.DISCORD_TOKEN}}",
"prefix": "{{server.build.env.BOT_PREFIX}}",
"owner_id": "{{server.build.env.OWNER_ID}}"
}
}
}
Option 2: Properties-format config file
{
"config.properties": {
"parser": "properties",
"find": {
"DISCORD_TOKEN": "{{server.build.env.DISCORD_TOKEN}}",
"BOT_PREFIX": "{{server.build.env.BOT_PREFIX}}"
}
}
}
With the properties parser, the find value is only the new value — not the full KEY=VALUE line. Wings will write DISCORD_TOKEN=your_token_here for you.
Example 3: Database Configuration
MySQL/MariaDB uses INI format:
[mysqld]
port=3306
bind-address=0.0.0.0
max_connections=100
[client]
user=admin
password=secret
In our egg:
{
".my.cnf": {
"parser": "ini",
"find": {
"mysqld.port": "{{server.build.default.port}}",
"mysqld.bind-address": "0.0.0.0",
"client.user": "{{server.build.env.DB_USER}}",
"client.password": "{{server.build.env.DB_PASSWORD}}"
}
}
}
Example 4: Code Server (File Parser on a YAML file)
Code Server stores its config as YAML, but we use the file parser for simple line replacement:
bind-addr: 127.0.0.1:8080
auth: password
password: changeme
cert: false
In our egg:
{
".config/code-server/config.yaml": {
"parser": "file",
"find": {
"password": "password: {{server.build.env.PASSWORD}}",
"bind-addr": "bind-addr: 0.0.0.0:{{server.build.default.port}}"
}
}
}
Why file instead of yaml? Because we want simple, direct line replacement and full control over what the output line looks like. The parser choice is based on how we want to edit the file, not just its extension.
Advanced: Managing Multiple Files
You can manage multiple files in one egg, each with its own parser:
{
"config": {
"files": {
"config.json": {
"parser": "json",
"find": {
"server.port": "{{server.build.default.port}}"
}
},
"config/database.yaml": {
"parser": "yaml",
"find": {
"database.host": "{{server.build.env.DB_HOST}}"
}
},
"server.properties": {
"parser": "properties",
"find": {
"server-port": "{{server.build.default.port}}"
}
}
}
}
}
This egg manages three different configuration files with three different parsers — all at once!
Tips and Tricks 💡
Tip 1: Escape Special Characters
When your value contains quotes or backslashes, escape them:
{
"find": {
"server.motd": "Welcome to \"My Server\"!"
}
}
Tip 2: Be Precise with Search Strings for the File Parser
When using "parser": "file", your search key must match the exact start of the line:
{
"parser": "file",
"find": {
"bind-addr": "bind-addr: 0.0.0.0:{{server.build.default.port}}"
}
}
This matches any line starting with bind-addr. If the line is commented out (starts with # bind-addr), it won't match.
Tip 3: Use Dot Notation Correctly for JSON/YAML
For JSON and YAML, dot notation navigates the nested structure. Follow the exact nesting in the file:
{
"parser": "yaml",
"find": {
"hikari.sql.user": "{{server.build.env.DATABASE_USER}}"
}
}
This navigates: hikari → sql → user. If your file has database.host instead of hikari.sql.host, use database.host!
Tip 4: Test Your Config Before Releasing
Always test with sample values before sharing your egg:
- Create a fresh server with your egg
- Check the config files look right after startup
- Try edge cases — empty values, special characters in passwords
Tip 5: Create Default Config Files During Installation
Wings can only modify files that already exist. Create them during installation:
#!/bin/bash
# Create a default config for Wings to modify at startup
cat > /home/container/config.json << 'EOF'
{
"server": {
"port": 8080,
"name": "Default Server"
}
}
EOF
Then Wings modifies it every time the server starts!
Common Mistakes ❌
Mistake 1: Properties Parser — Putting the Full Line in the Value
{
"parser": "properties",
"find": {
"server-port": "server-port={{server.build.default.port}}"
}
}
❌ Wrong! With properties parser, the value should be ONLY the new value:
{
"parser": "properties",
"find": {
"server-port": "{{server.build.default.port}}"
}
}
✅ Wings writes server-port=25565 for you — you just supply 25565!
Mistake 2: File Parser — Forgetting to Write the Full Line
{
"parser": "file",
"find": {
"bind-addr": "{{server.build.default.port}}"
}
}
❌ Wrong! With file parser, the value must be the ENTIRE replacement line:
{
"parser": "file",
"find": {
"bind-addr": "bind-addr: 0.0.0.0:{{server.build.default.port}}"
}
}
✅ Wings replaces the whole line with exactly what you wrote!
Mistake 3: Using Minecraft server.properties With the File Parser
{
"server.properties": {
"parser": "file",
"find": {
"server-port=": "server-port={{server.build.default.port}}"
}
}
}
❌ This works technically, but it's more fragile than necessary. Use the properties parser instead:
{
"server.properties": {
"parser": "properties",
"find": {
"server-port": "{{server.build.default.port}}"
}
}
}
✅ Cleaner and more correct for Java .properties files!
Mistake 4: Wrong Dot Notation Path for YAML
{
"parser": "yaml",
"find": {
"database.host": "{{server.build.env.DATABASE_HOST}}"
}
}
❌ Wrong if the actual YAML key path is hikari.sql.host! The dot notation must match the real structure in the file:
{
"parser": "yaml",
"find": {
"hikari.sql.host": "{{server.build.env.DATABASE_HOST}}"
}
}
✅ Always check the actual YAML structure. Case matters too!
Mistake 5: Forgetting to Create the Config File During Installation
Wings can only modify files that exist. If the file hasn't been created during installation, the parser silently does nothing. Always create your config files in the install script!
Troubleshooting 🔧
Problem: Variables Not Being Substituted
Symptoms: File shows {{server.build.env.TOKEN}} instead of the actual token
Solutions:
- Check the variable name is spelled exactly right (case-sensitive!)
- Make sure the variable is defined in your
variablessection - Check the user actually entered a value in the panel
- For JSON/YAML, verify the dot notation path matches the real file structure
Problem: File Not Being Modified
Symptoms: Your configuration file isn't changing at all
Solutions:
- Make sure the file actually exists (did your install script create it?)
- For
fileparser: check your search key exactly matches the start of a line - For
propertiesparser: make sure the key name (without=) matches exactly - For
yaml/jsonparser: validate the dot notation path
Problem: Syntax Error in Modified File
Symptoms: Server won't start because the config file has syntax errors
Solutions:
- For
propertiesparser: double-check you're not puttingkey=valuein the value — just the value! - For
fileparser: make sure your replacement line is well-formed - For JSON/YAML: check that special characters in values don't break the format
Problem: Right File, Wrong Parser Results
Symptoms: Some keys change but others don't, or the format looks garbled
Solution: Double-check the parser choice:
server.properties→propertiesparser (keys without=)config.json→jsonparserconfig.yml→yamlparser (orfileif you prefer line replacement).my.cnf→iniparser
Checklist Before Using Parsers ✅
- ✅ Chosen the correct parser for how you want to edit the file
- ✅ For
propertiesparser:findvalue is ONLY the new value (nokey=prefix!) - ✅ For
fileparser:findvalue is the ENTIRE replacement line - ✅ Search string / key is exactly correct (case-sensitive!)
- ✅ File exists before Wings tries to modify it (created in install script)
- ✅ File format is valid before Wings modifies it
- ✅ Special characters are properly escaped
- ✅ Variables are defined in your egg
- ✅ Tested with sample values
Real Examples from Real Eggs
Example: Paper (Minecraft)
{
"server.properties": {
"parser": "properties",
"find": {
"server-ip": "0.0.0.0",
"server-port": "{{server.build.default.port}}",
"query.port": "{{server.build.default.port}}"
}
}
}
Example: Code Server
{
".config/code-server/config.yaml": {
"parser": "file",
"find": {
"password": "password: {{server.build.env.PASSWORD}}",
"bind-addr": "bind-addr: 0.0.0.0:{{server.build.default.port}}"
}
}
}
Example: 5e Tools
{
"caddy.json": {
"parser": "json",
"find": {
"apps.http.servers.srv0.listen.0": ":{{server.build.default.port}}"
}
}
}
Example: Ree6 Bot (partial — shows correct dot notation)
{
"config.yml": {
"parser": "yaml",
"find": {
"bot.tokens.release": "{{server.build.env.BOT_TOKEN}}",
"hikari.sql.host": "{{server.build.env.DATABASE_HOST}}",
"hikari.sql.user": "{{server.build.env.DATABASE_USER}}",
"hikari.sql.pw": "{{server.build.env.DATABASE_PW}}",
"hikari.sql.port": "{{server.build.env.DATABASE_PORT}}"
}
}
}
Note: hikari.sql.host — NOT database.host! The dot notation must match the actual YAML structure of the Ree6 config file.
Example: MariaDB
{
".my.cnf": {
"parser": "ini",
"find": {
"mysqld.port": "{{server.build.default.port}}",
"client.port": "{{server.build.default.port}}",
"mysqld.bind-address": "0.0.0.0",
"client.user": "container"
}
}
}
See Also 📚
- Extending and Creating Eggs — Use parsers in your eggs
- Wings Variables Reference — Variables to use in parsers
- Configuration Variables Reference — Create user variables
Summary 📝
Five main parsers:
- JSON — For
.jsonfiles; dot notation for nested keys - YAML — For
.ymlfiles; dot notation for nested keys - Properties — For
key=valuefiles; thefindvalue is ONLY the new value - INI — For
[section]files; usesection.keydot notation - File — For any text file; the
findvalue is the ENTIRE replacement line
The single most important rule:
propertiesparser → you provide the new value only, Wings writeskey=valuefileparser → you provide the complete replacement line, Wings uses it verbatim
Now you can manage any configuration file! 🎉
Learning Path 📚
You should read the documentation in this order:
- Egg Basics — What are eggs and basic structure
- Configuration Variables — How to make your egg customizable
- Extending Eggs — Creating and extending eggs
- Wings Variables — Special variables from the panel
- File Parsers — This page! Managing configuration files
Helpful Links 🔗
- Back to README — Overview of all documentation
- Egg Basics — Start here if you're new
- Configuration Variables — Create customizable settings
- Extending Eggs — How to extend and create eggs
- Wings Variables — Panel-provided variables
Happy parsing! 🥚