Created: 2012-03-25 11:33
Updated: 2018-05-31 14:14
License: gpl-3.0


This README references: version 2.1

This script implements a parser mapping .ini style configuration files to Lua tables and vice versa.

The current release v2.1 is a DEVELOPMENT release. See the Changelog for changes relative to the 2.0 release.

Stable releses are all releases with an even minor version number (currently: 2.0).


Make sure all dependencies are installed (-> DEPENDENCIES.

# clone the repository
git clone lua-ini && cd lua-ini

# should exit without errors
make test doc

If the tests ran successfully, you can take the module ini.lua from the repository and put it wherever you want -> "installed".


INI format

I briefly describe the format ini.lua supports as of now.

Flat INI files

  • Flat INI files don't have nested sections
  • Section names may consist of any character as in the [.] Lua regex symbol
  • Key names must not contain the = character and spaces [%s], values may contain any character in [.].
  • EXCEPTION: if the read64/write64() API is used, Lua strings holding arbitrary binary values may be passed.
  • Key names must not be preceeded by any [%s].
  • Lines beginning with # and empty lines will be ignored

Example file:

key1=value1 with some spaces and punctuation =)(!/_%@


Nested INI files

The flat format applies, with the following extensions:

  • Sections may be nested
  • Section names must not contain the / character
  • The last section in a file is not required to be closed
  • Sections are closed with a [/$section] element
  • Sections must be closed in the same order they were opened
  • Section openings and closings as well as key names may be preceeded by [%s]*

Example file:




  • Every key and value to be written must be convertable to a string using tostring()
  • No extensive error checking yet
  • No autodetection of nested/unnested file format yet
local ini = require("ini")
ini.write(outfile, data)

ini.write_nested(outfile, data)
--- Flat INI files

-- The table format as passed to write(), and returned by read()
local data = { SectionA = { key1 = "value1" }, Section2 = { key2 = "value2" } }

-- write(outfile, datatable)
-- returns NIL if outfile couldn't be opened, otherwise true

ini.write("flat.ini", data)

-- read(infile)
-- returns:
--  in case of success: <data table>, <list of rejected/ungrammatical lines' line numbers>
--  in case of failure, #<data table> == 0 or
--                      NIL if infile couldn't be opened.
local data, rejected = read(outfile)

--- Nested INI files
-- The API works the same, but the table format can hold nested tables
data = { SecA = { SecAB = { a=1 } } }

-- writing:
ini.write_nested(outfile, data)
data, rejected = ini.read_nested(outfile)


This API works analog to the unnested read/write API, except for the following changes:

  • All values with a metatable holding a key __ini_is_binary which evaluates as true will be stored in a base64 encoded form.
  • If a non-base64 value begins with the sequence "base64:", it will be parsed as base64. This is a limitation and will be fixed in the upcoming 2.2 release.
  • read64() will produce data tables with all the necessary metatables in place.


local ini = require("ini")
local data = {
    DATA = {
        bin = 0xaf6723dc
    STRINGS = {
        str = "Hello World!"

-- setting a metatable for non-table data types requires the debug
-- library!
debug.setmetatable(data.DATA.bin, { __ini_is_binary = true })

ini.write64("test.ini", data)

-- is equivalent to the data referenced by $data
local d = ini.read64("test.ini")


This is the logical extension of the read64/write64 API, to which it adds the ability to preserve in addition to the base64 binary data type all native Lua data types minus table and user data, meaning your strings, numbers, boolean, or binary data can be stored and read without losing any type information.


local ini = require("ini")

local data = {
    Time = {
        hour = 6,
        minute = 50,
        second = 13,
        milliseconds = 493,
        day = "Mo",
        month = "Nov"
    Location = {
        x = 14.4,
        y = 22.1,
        ishere = true

ini.write_typed("test-typed.0.ini", data)
local b = ini.read_typed("test-typed.0.ini")
ini.write_typed("test-typed.1.ini", b)

-- test-typed.{0,1}.ini contain exactly the same data.
-- the data returned from ini.read_typed(...) is equivalent to the
-- data stored in the input `data` table.



Additionally, there is a (at this point basic) HTML documentation generated using LuaDoc in the doc directory. It may be re-generated by issueing the make doc command. This requires LuaDoc to be installed.


ini.lua - read/write access to INI files in Lua
Copyright (C) 2013 Jens Oliver John <>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <>.
Cookies help us deliver our services. By using our services, you agree to our use of cookies Learn more