Skip to main content

External Code

In your tstl project, you might want to use some existing Lua code. Or you might want to import a Lua library from npm. This page describes how to use external Lua with your TypeScript code and TSTL.


This page is about importing code that actually executes something. In a tstl project, it is common to depend on external library that provide type declarations. Type declaration libraries only provide types: they do not contribute any code to your actual program output. Thus, they work a little differently from what is discussed on this page. For information on how type declarations work, see the type declarations page.

Adding Lua files to your project sources

The most straightforward way to add Lua code is to put the Lua file directly next to your TypeScript files. Next, you add a declaration file with the same name. Then, you can import the Lua code in your TypeScript.

For example, a project might look like this:

├── main.ts
├── someLua.lua
├── someLua.d.ts
└── tsconfig.json
import { foo, bar } from "./someLua";

local someLua = {}

function someLua:foo()

function someLua:bar()

return someLua
export function foo(): void;
export function bar(): void;

Importing a Lua module that only exports an array

Building on the previous section, you might want also want to import a Lua file that exports an array. For example, something like:

return {
foo = 123,
bar = 456,
foo = 789,
bar = 987,

Writing a definitions file for this is tricky, since the Lua file has no named imports and no default export. Here, you have to use export = syntax, like so:

interface Thing {
foo: number;
bar: number;

declare const things: Thing[];
export = things;

Then, in your TypeScript code, you can import it like:

import * as things from "./module";

print(things[0].foo); // Prints "123"

For more information about this export syntax, see the official TypeScript documentation.

Importing Lua packages from npm

tstl supports module resolution for libraries, which means you can use and create npm packages containing .lua files. (Most packages on npm contain JavaScript files, but npm allows you to create packages with whatever kinds of files you want.)

Using Lua packages

To use a Lua package, install it via npm and use it in the same way that you would in a normal TypeScript project. In other words:

# If you use npm:
npm install foo --save

# If you use yarn:
yarn add foo

# If you use pnpm:
pnpm add foo

And then use it in your code:

import { someFunction } from "foo";


Since the npm package was presumably made for tstl users, it will almost certainly include .d.ts files alongside the .lua files, which is necessary for tstl to import the Lua files properly. If there are no .d.ts files, you can try creating some for the package yourself.

Creating Lua packages

For more information on creating a Lua package yourself, see the page on publishing modules.

Importing JavaScript or TypeScript packages from npm

Importing JavaScript or TypeScript packages from npm will not work. This means that it is impossible to use common JavaScript/TypeScript libraries like Underscore.js and so on.

(It is not possible for tstl to work with a generic npm package because most TypeScript libraries only publish the compiled JavaScript to npm. And tstl can't convert JavaScript to Lua because it needs the type information to create correct code. For example, tstl needs to be able to distinguish between arrays and objects in order to write the correct index.)

As a workaround, you can copy paste TypeScript code from a package repository directly into your project. (That way, it will be compiled by tstl alongside your normal code.)

Alternatively, you could fork an existing package and re-publish it as Lua files (instead of JavaScript) so that it can be directly consumed by other tstl projects. However, doing this kind of thing will only work for really basic packages, since you would have to also fork all of the dependencies and convert those to Lua as well.

Obviously, tstl programs will not have access to any of the Node.js standard libraries or APIs (like e.g. import path from "path";), so make sure that any code that you integrate into your project is not Node-specific.