unreadable.gg

changelog

Every release of the decompiler, newest first. Each is named by its version, the one the API sends with every result, so you can look up what changed in the version that decompiled your file.

activity

819 changes to the decompiler since aug 19

the site and the api are live

2026.10.11-7046806

  • Decompile a file in your browser: drop it on unreadable.gg. The source shows beside your file's bytes, with its verdict, ready to copy or download.
  • Scripts and agents can send the same file to POST https://api.unreadable.gg/v1/decompile and get back the source, a verdict, notes and the version that wrote it. See the API docs.
  • Every connection gets 5 free decompiles a day, on the site and through the API together, with no key or account. Errors and refused decompiles don't count.
  • Your files are never stored or logged: see privacy.

bytecode version 14

2026.10.11-4227ea3

  • Reads bytecode version 14 and the calls current Luau compilers write by default. Modules from them used to be refused.
  • Notes and errors carry fixed codes a program can act on, such as function-refused and not-luau-bytecode: see notes and errors.
  • A function the compiler kept from code it removed, such as the body of if false then … end, is printed back inside if false then … end instead of being left out. Where it has to guess what the function captured, the guess is marked.
  • Fixed a case where the first statements of a loop could be left out of the output.
  • The parameters of a function that also takes ... keep their names, and so do locals that are copied and read later.
  • local a, b = -0.5, #x prints as one list, as it was written.
  • Very large modules decompile much faster at -O0 and -O1.
  • Three more shapes are refused rather than guessed: a branch whose inner arm computes a value, a table constructor whose parts don't agree, and a function that needs too many passes to settle.

continue in nested loops

2026.10.03-4be51f9

  • A continue inside nested loops comes back as continue.
  • An assignment to several places at once, such as a.x, b.y = 1, 2, comes back as one statement.

fewer wrong programs

2026.09.27-1dc49cb

  • Fixed several cases where the output could have run differently from the input: assignments to undeclared and captured variables, and generic for loops left by a return. Where one can't be printed faithfully yet, it's refused instead.
  • A module that had started taking seconds to decompile is back to a few hundred milliseconds.
  • The decompiler builds for WebAssembly, which is how the site and the API run it.

conditions as one expression

2026.09.20-55cbf5f

  • Conditions with three or more tests print as one and/or expression.
  • A variable a loop carries from one pass to the next is no longer declared again on every pass.

and/or as values

2026.09.02-39ae4d2

  • and/or chains used as values fold back into one expression, as in local x = a and b or c.
  • A damaged or crafted file can no longer make the decompiler reserve memory for more than the file holds: every count it reads is checked first.

table constructors and recorded types

2026.08.30-f0c3823

  • Table constructors come back as { … } instead of a table filled in one assignment at a time.
  • A type the bytecode records for a local is printed with it, as in local w: number.
  • if not keeps its two arms in the order they were written, and a do … end block keeps its locals inside it.
  • A statement that starts with ( gets a ; before it, so it isn't read as a call on the line above.
  • A file from another Lua version is refused by name instead of read as Luau. See Lua versions.

first version

2026.08.23-38b2adc

  • Decompiles Luau bytecode back into source, and marks or refuses what it can't reproduce instead of guessing.
  • Reading a file can't crash the decompiler: a crafted file that would overflow its stack is turned away, and nothing on the way in may abort.