Logo

MonoCalc

/

Lua Prettier

Programming

Re-prints the source with the style options below.

Load a sample

Ctrl/Cmd+Enter formats · Ctrl/Cmd+K clears

Lua source

Formatted Lua

Style

What `stylua` prints out of the box: four spaces, 120 columns.
Grammar the parser accepts.
1–8 spaces per level.
Wraps at this column (40–200).
Only switched when it adds no escapes.
Lua's trailing `;` is optional.

Runs entirely in your browser - your code is never uploaded, and it is parsed, never executed. Inputs up to 500,000 characters.

About This Tool

Lua Prettier - Format, Beautify and Validate Lua Online

Lua turns up wherever a program needs a small scripting language bolted onto something bigger: Neovim init.lua configs, Roblox and LÖVE 2D game code, World of Warcraft addons, Redis EVAL scripts, OpenResty and nginx request handlers, Wireshark dissectors, Garry's Mod servers and embedded firmware. Because it usually arrives as a snippet pasted from a forum post, a wiki, a chat message or a game console, it also arrives with whatever indentation the last four people used. This Lua formatter rewrites it into one consistent style.

Rather than nudging end keywords around with regular expressions, the tool parses your source into a real abstract syntax tree and prints it again from scratch. That distinction matters more in Lua than in most languages, because a brace-counting beautifier has no braces to count - and a [[long string]] or a --[==[ block comment ]==] full of Lua-looking text will defeat it entirely.

What it understands

The full grammar, across dialects: every block form from do…end through repeat…until and both flavours of for; every function form including the colon sugar in function obj:method() with its implicit self; table constructors mixing array parts, key = value pairs and computed [expr] = value keys; call sugar such as require "socket" and setmetatable{…}; varargs, multiple assignment and multiple return values; and the operators that make Lua Lua - .. for concatenation, ~= for inequality, # for length and the word operators and, or and not.

Newer syntax is covered too: goto and ::label:: from 5.2, integer division // and the bitwise operators from 5.3, and the local x <const> attribute from 5.4. Pick a dialect older than your code and you get a message naming the exact construct and the version it needs, instead of a bewildering token error.

Beyond indentation

Expand mode rebuilds structure from minified, packed or single-line Lua, which is the fastest way to make an obfuscated addon or a config blob reviewable. Compact mode does the reverse, keeping statements on one line for a slide, a chat message or a single-line EVAL fixture. Diff mode lists every line the formatter would touch, and Compare mode renders the same file under two presets side by side - useful for settling whether a team moves from the 2-space community style guide to StyLua's 4-space default.

Validate mode answers "is this even valid Lua?" and does it better than the interpreter does. Lua's own diagnostic for a missing end points at the end of the file, which is the least useful place to look; this tool replays the block openers and tells you the line where the unclosed function or if actually started.

Style options that settle arguments

Four presets cover the common house styles - StyLua's default, the community style guide, Roblox/Luau and a typical Neovim config - or you can set indentation, print width, quote preference, semicolon handling and table layout yourself. Tables can auto-fit, always expand or preserve your own line breaks, with an optional trailing separator and column-aligned = signs. The tool also emits the matching stylua.toml and .editorconfig block so the same style can be enforced in CI.

Alongside the formatted source you get a function outline drawn from the parsed tree, a de-duplicated list of required modules, and a report of identifiers that resolve to globals rather than locals - a classic Lua footgun, flagged as advice and never rewritten on your behalf.

Formatting only - never a rewrite
Identifiers are never renamed and nothing is executed. Every result is parsed a second time and compared against the input tree, its comments and its value-truncating parentheses; if anything fails to match you get a warning rather than a quiet mistake. Long strings and long comments are copied through byte for byte, and the parentheses in (f()) are kept, because dropping them would truncate a multi-value call to a single value.

Private by construction

The parser and printer are JavaScript that runs inside your own browser tab. Nothing is uploaded, nothing is logged and no network request is made after the page loads, so pasting a script that happens to carry an internal hostname, a server address or an API key does not put it anywhere. Files up to 2 MB can be dropped straight onto the editor.

Frequently Asked Questions

Is the Lua Prettier free?

Yes, Lua Prettier is totally free :)

Can I use the Lua Prettier offline?

Yes, you can install the webapp as PWA.

Is it safe to use Lua Prettier?

Yes, any data related to Lua Prettier only stored in your browser (if storage required). You can simply clear browser cache to clear all the stored data. We do not store any data on server.

How does this Lua formatter work?

Your source is parsed in the browser into a real syntax tree and then printed again from scratch at the width and indentation you pick. Because the output is generated from the parsed structure rather than by shuffling `end` keywords around with regular expressions, a `--[==[` comment or a `[[long string]]` full of Lua-looking text cannot throw the layout off the way a brace-counting beautifier does.

Is my code uploaded or executed anywhere?

Neither. The parser and printer are JavaScript that runs inside your own tab, with no server round-trip and no logging, and the tool only ever reads your code - it never runs it. That matters for Lua in particular, because pasted snippets routinely carry game server addresses, addon internals, Redis keys and the occasional token nobody remembered to strip.

Can formatting change what my script does?

It should not, and the tool proves it rather than promising it: every result is parsed a second time and compared against the input tree node for node, along with the comments and the parentheses that decide how many values a call returns. If anything differs you get a warning instead of a quiet mistake. The options that genuinely rewrite the file - stripping comments, sorting requires, normalising call parentheses - are called out in the panel.

Which Lua versions are supported?

Lua 5.1, 5.2, 5.3, 5.4 and LuaJIT. The underlying parser implements the 5.1 to 5.3 grammars directly; 5.4 is handled on top of that, since the only new syntax 5.4 introduced is the `local x <const>` attribute, which is set aside before parsing and printed back onto the declaration afterwards. Picking a dialect older than the code needs gives you a message naming the construct and the version it requires.

Why does the output keep the parentheses in `(f())`?

Because removing them would change the program. A bare `f()` in a list position expands to every value the call returned, while `(f())` truncates it to exactly one - the same difference that makes `print(f())` and `print((f()))` behave differently. Parsers throw parentheses away, so this tool recovers the ones you actually wrote from the token stream and keeps every one that carries meaning.

Does it work on minified or single-line Lua?

Yes - that is what Expand mode is for. A packed addon, a config blob or a script squeezed onto one line is re-broken into statements, indented and spaced so it can be read and reviewed. It is strictly a formatter, though: identifiers keep whatever names the minifier gave them, because renaming them back is not something any tool can do from the source alone.