Want to take your software engineering career to the next level? Join the mailing list for career tips & advice Click here


A web framework for Lua and OpenResty written in MoonScript

Subscribe to updates I use lapis

Statistics on lapis

Number of watchers on Github 2407
Number of open issues 171
Average time to close an issue 20 days
Main language MoonScript
Average time to merge a PR about 1 month
Open pull requests 24+
Closed pull requests 20+
Last commit 4 months ago
Repo Created almost 8 years ago
Repo Last Updated 2 months ago
Size 2.84 MB
Homepage http://leafo.net/...
Organization / Authorleafo
Latest Releasev1.8.0
Page Updated
Do you use lapis? Leave a review!
View open issues (171)
View lapis activity
View on github
Book a Mock Interview With Me (Silicon Valley Engineering Leader, 100s of interviews conducted)
Software engineers: It's time to get promoted. Starting NOW! Subscribe to my mailing list and I will equip you with tools, tips and actionable advice to grow in your career.
Evaluating lapis for your project? Score Explanation
Commits Score (?)
Issues & PR Score (?)


A web framework for Lua/MoonScript supporting OpenResty or http.server

Build Status

Twitch Link

Lapis is production ready, use it on your next huge project.

Learn more on the homepage: http://leafo.net/lapis/

Join Our Community

We just created a Discord for Lapis users and those interested in it to communicate. You can join us here: https://discord.gg/Y75ZXrD

Lapis Powered

Made a website in Lapis? Tell us

Running Tests

If you need to run tests outside of our CI. The test suites require Busted and MoonScript. There are three separate test suites:

  • busted -- test Lua implementations
  • busted spec_postgres -- integration tests with PostgreSQL. Requires a running PostgreSQL server
  • busted spec_mysql -- integration tests with MySQL. Requires a running MySQL server
  • busted spec_openresty/ -- integration tests with OpenResty as a server. Requires installation of OpenResty & Databases
  • busted spec_cqueues/ -- integration tests with lua-http and cqueues as a server.

Test suites that require databases need to have the initial database created. A lapis_test database is created on each. You can run each command respectively.

make test_db # postgres test db
make mysql_test_db
  • PostgreSQL: Ensure the postgres user can be logged in with no password.
  • MySQL: Ensure the root user can be logged in with no password.

Using the Docker image

This repository contains a Dockerfile for running the entire test suite. You can run it with the following commands:

docker build -t lapis-test .
docker run lapis-test

docker build will pull in the files in the current directory, including any changes. To test modified code, build again before running the test suite. It should be a quick operation since dependency installation is cached.

License (MIT)

Copyright (C) 2020 by Leaf Corcoran

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the Software), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.


lapis open issues Ask a question     (View All Issues)
  • almost 4 years Implement cqueues server backend
  • almost 4 years Long url request produces delay of about 30 secs before reaching handler function
  • almost 4 years Does not install cleanly on Ubuntu 16.04 LTS
  • almost 4 years How to PUT with a body in a test request()?
  • about 4 years Setting session data in Widget
  • about 4 years [Bug] Sub-application before_filter redirects not working
  • about 4 years How to write file response?
  • about 4 years Lapis for Lua >= 5.3
  • about 4 years Changing database credentials per-page
  • about 4 years [Bug] Sub-application layouts do not work?
  • about 4 years [Bug] Model enumerations debug does not list items below 1
  • about 4 years [Feature] Can we get type info on error messages?
  • about 4 years views_prefix not working?
  • about 4 years Nested tables in session are always empty
  • about 4 years What exit codes can lapis return?
  • over 4 years Handling db errors (postgressql)
  • over 4 years OSX: can not find suitable server installation
  • over 4 years Launch resty-luajit console with lapis.db
  • over 4 years use prepare/execute with postgres
  • over 4 years How to detect Lapis environment in init_by_lua*?
  • over 4 years 'flow' not found in documentation search
  • over 4 years Make server implementations use a module interface
  • over 4 years normalize trailing dots in views
  • over 4 years Layouts and widgets documentation for Lua is missing
  • over 4 years Missing documentation for https://github.com/leafo/lapis/pull/377
  • over 4 years Lapis community?
  • over 4 years Can't setup heroku postgres
  • over 4 years SQLite3 Support
  • over 4 years there are so many tcp time-out of mysql,i can not use the connection pool of openresty mysql
  • over 4 years Update documentation, with detailed instructions to buid and run Lapis
lapis open pull requests (View All Pulls)
  • Clarified wording in docs/html_generation.md
  • Improved HTTP verb handling
  • add select_all function
  • Add config flag to disable reading request body
  • Don't depend on nginx as much
  • Use luaossl's hmac module if available
  • db.postgres: implement wait() and post() based on Postgres notifications
  • Allow migrations to run on remote mysql hosts
  • Fix json return
  • Add error labels to parsers via LPegLabel
  • testing util.trim with unicode space characters
  • typo fix in docs/html_generation.md
  • wip on #259
  • Fix missing "set $_url '';" in nginx.conf generation
  • Fix #299 broken link + missing example
  • Lapis new create default config
  • Missing link in docs/input_validation.md
  • Added `add_headers()` method to request objects
  • Allow host configuration parameter for cqueues/lua-http server
  • Added cookie check for CSRF protection, very IMPORTANT mechanism
  • Describe how to log configuration
  • Use last field of a compound PK when setting auto ids
  • Add host to cache key name for multi-tenants applications
  • Fix for #608
lapis questions on Stackoverflow (View All Questions)
  • Lapis POST gets redirected to index
  • Lapis input validation
  • Lapis Framework does not create new project
  • Lua (Lapis) random values returns the same result even using randomseed
  • Greater than, Less than string Lua (Lapis)
  • Lapis: could not load `etlua` file
  • Configuration error lapis. Luarocks may not be configured correctly
lapis list of languages used
lapis latest release notes
v1.8.0 v1.8.0



  • Add support for a column mapping table when specifying the key forinclude_inand any relations. See more documentation forModel\include_in
  • Add support for composite foreign keys withinclude_inand relations
  • each_itemmethod for Paginators that will return a Lua iterator for going over every row but queries in batches set byper_page
  • Anorderedoption can be passed toModel\paginatedanget_X_paginatedto create anOrderedPaginatorinstead of aOffsetPaginator
  • Addskip_renderaction render option to prevent Lapis from writing anything (Suitable for manually writing to output buffer with something likengx.print)
  • fetchrelations can now specify if they return a collection of items withmanyso nested preloading can traverse the loaded objects
  • addservealias for thelapis servercommand line command
  • addapp_onlycode cache option for cqueues to attempt to load app on every dispatch
  • Aresty_mysqlobject can be included in the MySQL configuration object to provide additional parameters when initializng aresty.mysqlconnection
  • Pgmoon connections will now read thetimeoutfield from the PostgreSQL config object (Contributed by turbo679)
  • Addset_loggerandget_loggerfunctions to thelapis.db.mysqlandlapis.db.postgresmodule
  • (lapis.db.postgres)escape_identifierfunction will now flattendb.listobjects into raw SQL
  • (lapis.db.postgres.schema)create_indexsupport aconcurrentlyoption to create index concurrently (Contributed by Michael Ball659)
  • addtestvalidation for manually specifying a function to test input


  • assert_errorwill now fail witherrorif the error it yielded was not captured and execution attempted to continue
  • initial project templates usecontent_by_lua_block(Contributed by ryanford674)
  • each_pagemethod on paginators no longer allocates a coroutine, a plain function iterator is used
  • attempting to preload an object that isn't a class will throw an error
  • attempting to use an invalid order withOrderedPaginatorwill throw an error
  • measure_performancenow works even when outside of nginx when reporting query time
  • (lapis.html)classnamesignores empty strings and will return first argument directly if passed a string
  • (lapis.logging)querylog function can now take a prefix and duration
  • Removed undocumentedlocalsaction render option


  • Fix bug where internal shell_escape function would strip'characters
  • Returning{ json = false }in action render will actually render false as json instead of skipping json render


  • Started rewriting how options tables are described in the documentation. Uses a grid layout with collapsing examples.
  • Many parts of Models documentation have been rewritten for clarity
  • Remove outdated references to fields that are deprecated/removed (eg.cmd_url)
  • Add documentation for thetimestampoption formodel\update
  • Updated colors of site to be blue


  • Specs now run on GitHub actions with matrix for LuaJIT, OpenResty's LuaJIT, and all versions of Lua
  • We now have a MoonScript Discord, join here:https://discord.gg/Y75ZXrD
  • Fix typo in docs from Chris Tanner621
  • Fix typo in docs from TangentFoxy634685672


  • Replaced the CSRF implementation, removed the key parameter and replaced with it randomly generated string stored in cookie.
  • Sessions now use the lapis.encoding module to encode an decode. Session loading error messages have changed to include the error from encode_with_secret and decode_with_secret
  • Remove all support for luacrypto, luaossl is required


  • Add support for chaning HMAC function, add sha256 HMAC config option
  • Support parsing cookies when there are multiple cookie headers
  • Add enum type fro MySQL
  • Add support for encoding NULL and empty arrays for to_json and JSON render
  • Add config template for cqueues/lua-http support
  • Request object for cqueues/lua-http contains all the same fields as OpenResty counterpart
  • Performance object is available for cqueues/lua-http
  • Environment name is shown on server start log
  • Add bind_host config option to set which interface cqueues/lua-http binds to, defaults to


  • Fix issue with MySQL migrations where query result was not being converted to number
  • Fix a crash when request args could not be parsed
  • Fix a crash when the query parameter type changes when being parsed (between table and literal)
  • json_params works with cqueues/lua-http
  • cqeueus/lua-http test server now works correctly, is now part of CI
  • cqeueus/lua-http will no longer get stuck in infinite loop when port is already taken
  • cqeueus/lua-http will only ready & parse body for form encoded content type
  • Terminal output buffering is disabled for cqeueus/lua-http so service files can read logs from stdout/stderr
v1.6.0 Lapis 1.6.0


  • Add a new general purpose preload function that can preload many relations at once for many kinds of model instances, including recursively preloading relations
  • Addition of cqueues and lua-http server backend
  • Pgmoon connection status is logged to performance table for each request when performance measurements are enable
  • fetch relations can provide a method for preloading with the preload option
  • default_url_params has been added to request support object for extending the default parameters passed into `url_for
  • matches_pattern validation can be used to test an input against a Lua pattern
  • relation_is_loaded function can be used to test if a model has a relation loaded
  • mock_request can insert a session via a Lua table
  • lapis.time module with a sleep function that executes correct implementation for the current backend server
  • If you use when instead of where when creating an index an error is thrown
  • lapis.spec.request, the mock_request function supports cookies option
  • Add render_to_file method for widgets
  • Add documentation for Flow


  • Route precedence sorting now uses a score based approach where multiple variables or splats can affect the final order
  • Mocked requests have ngx.md5 implemented with luacrypto
  • Query logs use luasocket to measure time elapsed for a more accurate measurement
  • URL parsing uses find and sub instead of match to parse very long paths faster (#498)
  • db.NULL values are always stripped when inserting a new row from a model's create method
  • Test server can be run even if there isn't a database configured
  • Refactor backend implementation to be extensible to allow for cqueues/lua-http implementation
  • Add support for test server to run on cqueues backend
  • Replace luacrypto with luaossl

Minor changes

  • Lua and MoonScript are added as mime types in default mime.types file (#513)
  • Various improvements to the documentation


  • Encoding a query string with a parameter with a boolean value will no longer throw an error
  • Fix issue where *.lua would be included in .gitignore for Lua projects (#501)
  • A user set content type will no longer be overwritten when outputting with the json action return handler
  • Check for Content-Disposition header for file uploads is no longer case sensitive

Note on cqueues/lua-http

With this release we're adding a new server backend for Lapis. Although the backend is functional, there are some things that aren't available yet. Database connections are shared across all requests so you have to be careful about leaving transactions or state open. Additionally, there's no way to spawn multiple workers. For production environments we still recommend OpenResty.

Other projects in MoonScript
Powered by Autocode - Instant Webhooks, Scripts and APIs
Autocode logo wordmark