This document describes how the @notfounnd/ini-parser interprets INI files.
- Processing Order
- Basic Structure
- Comments
- Multi-line Values
- Value Splitting
- Output Formats
- Special Cases
- Supported File Extensions
- Known Limitations
- Complete Examples
The parser processes each line of the INI file sequentially, applying the following logic:
- Trim whitespace from the line
- Check if empty or comment → skip the line
- Check if section (
[...]) → initialize new section - Check if global key (no current section) → process as global key
- Check if indented line → add as value to previous key
- Check if key-value pair (
key=value) → process normally - Check if non-indented value (after empty key) → add as value
Sections group related configuration keys together.
Syntax:
- Defined by
[section_name] - Must be on their own line
- Section name is extracted by removing
[and]and trimming whitespace - Sections can be empty (no keys inside)
Example:
[database]
host=localhost
[empty_section]Output:
{
"database": {
"host": ["localhost"]
},
"empty_section": {}
}Keys defined before any section are considered global.
Behavior:
- Global keys don't belong to any section
- Processed identically to keys within sections
- Appear at the root level of the output
Example:
app_name=MyApp
version=1.0.0
[database]
host=localhostOutput:
{
"app_name": ["MyApp"],
"version": ["1.0.0"],
"database": {
"host": ["localhost"]
}
}Syntax:
- Format:
key=value - Spaces around
=are allowed and will be removed (trimmed) - Keys without
=are ignored (unless they are indented values)
Example:
host=localhost
port = 5432
name = testOutput:
{
"host": ["localhost"],
"port": ["5432"],
"name": ["test"]
}Two characters indicate comments:
#(hash);(semicolon)
Lines starting with # or ; are completely ignored.
Example:
# This is a comment
; This is also a comment
[section]
key=valueOutput:
{
"section": {
"key": ["value"]
}
}Everything after # or ; until the end of the line is considered a comment and removed.
Example:
host=localhost # this is the local server
port=5432 ; default PostgreSQL portOutput:
{
"host": ["localhost"],
"port": ["5432"]
}IMPORTANT: If # or ; appears in a value, everything after it is removed, even if it's part of the original value.
Example:
connection_string=server=localhost;database=testOutput:
{
"connection_string": ["server=localhost"]
}; as a separator will be truncated. This is standard INI specification behavior.
Lines starting with spaces or tabs are considered indented values and belong to the previous key.
Example:
[section]
key=
value1
value2
value3Output:
{
"section": {
"key": ["value1", "value2", "value3"]
}
}The first value can be on the same line as the key, with additional indented values following.
Example:
servers=prod1
prod2
prod3Output:
{
"servers": ["prod1", "prod2", "prod3"]
}If a key has no initial value (just key=), subsequent non-indented lines are treated as values until a new key or section is encountered.
Example:
key=
value1
value2Output:
{
"key": ["value1", "value2"]
}Values containing whitespace (spaces, tabs, etc.) are automatically split into multiple values during parsing.
Example:
tags=production stable v1.0Output:
{
"tags": ["production", "stable", "v1.0"]
}IMPORTANT: Values containing spaces are split regardless of whether they contain = or not.
This ensures consistency, as the INI format doesn't support multi-word strings.
Example:
params=timeout=30 retry=3Output:
{
"params": ["timeout=30", "retry=3"]
}Equivalent to:
params=
timeout=30
retry=3- Remember that
;in values will be treated as a comment (see Comments in Values) .propertiesfiles with multi-word values will be split (use a properties-specific library if you need to preserve spaces)- Splitting occurs during parsing, not as a separate post-processing step
Indented values containing = are treated as normal values, not as new key declarations.
Example (correct - no spaces around =):
[pytest]
addopts=
--cov-config=.coveragerc
--cov-context=testOutput:
{
"pytest": {
"addopts": ["--cov-config=.coveragerc", "--cov-context=test"]
}
}= with spaces around it, it will be automatically split during parsing (see Values with Spaces).
Example (malformed):
key = value
key_indented = value_indentedOutput:
{
"key": ["value", "key_indented", "=", "value_indented"]
}The value "key_indented = value_indented" contains spaces and is split into multiple array elements.
How to avoid this:
- Don't indent key declarations: place them at the beginning of the line
- Remove spaces around
=in indented values: usekey_indented=value_indented
Example (corrected):
key = value
key_indented=value_indentedOutput:
{
"key": ["value", "key_indented=value_indented"]
}By default (meta: false), the parser returns a simplified format:
Input:
global_key=value
[section_name]
key=value1
value2Output:
{
"global_key": ["value"],
"section_name": {
"key": ["value1", "value2"]
}
}With meta: true, the parser returns a format with type information:
Input:
global_key=value
[section_name]
key=value1
value2Output:
{
"global_key": {
"type": "configuration",
"content": ["value"]
},
"section_name": {
"type": "section",
"content": {
"key": {
"type": "configuration",
"content": ["value1", "value2"]
}
}
}
}Returns empty object {}.
null,undefined, or non-string: returns{}- Empty string: returns
{}
Sections without keys result in an empty object for that section.
Example:
[empty_section]
[normal_section]
key=valueOutput:
{
"empty_section": {},
"normal_section": {
"key": ["value"]
}
}Empty lines or lines with only whitespace are ignored.
Files containing only comments return {}.
Keys with no value and no continuation values result in an empty array.
Example:
[section]
empty_key=
key_with_value=testOutput:
{
"section": {
"empty_key": [],
"key_with_value": ["test"]
}
}The parser works with any file extension that follows the INI format:
.ini- Traditional INI files.config- Configuration files.properties- Java-style properties files- Any other extension using INI format
- Values with semicolons: Any value containing
;will be truncated (treated as inline comment) - No quote support: Values with quotes have no special handling
- No escape sequences: Escape characters (
\) are not processed - No nested sections:
[section.subsection]is treated as a unique name, not nested structure - Order not preserved: Key order is not guaranteed (JavaScript object limitation)
- File paths with spaces: Any path containing spaces will be split into multiple values. Use paths without spaces or store paths as multi-value arrays
Input:
# Global configuration
app_name=MyApp
version=1.0.0
[database]
host=localhost
port=5432 ; default PostgreSQL port
users=
admin
readonly
backup
[features]
enabled_modules=auth api loggingOutput:
{
"app_name": ["MyApp"],
"version": ["1.0.0"],
"database": {
"host": ["localhost"],
"port": ["5432"],
"users": ["admin", "readonly", "backup"]
},
"features": {
"enabled_modules": ["auth", "api", "logging"]
}
}Input:
[pytest]
addopts=
-rA
--cov=package
--cov-config=.coveragerc
testpaths=
testsOutput:
{
"pytest": {
"addopts": ["-rA", "--cov=package", "--cov-config=.coveragerc"],
"testpaths": ["tests"]
}
}Input:
; Application metadata
title=Configuration Parser
author=NotFound
[server]
host=0.0.0.0
port=8080
allowed_origins=http://localhost:3000 http://localhost:8080
[logging]
level=info
format=json
outputs=
console
fileOutput:
{
"title": ["Configuration Parser"],
"author": ["NotFound"],
"server": {
"host": ["0.0.0.0"],
"port": ["8080"],
"allowed_origins": ["http://localhost:3000", "http://localhost:8080"]
},
"logging": {
"level": ["info"],
"format": ["json"],
"outputs": ["console", "file"]
}
}- API Reference - Complete API documentation for using the parser programmatically.
- CLI Reference - Complete guide for using the command-line interface.
Made with ❤️ by Júnior Sbrissa | Errør 404 | NotFounnd