Lucky Logo

Build lightning fast web apps with fewer bugs

Lucky is a web framework written in Crystal. It helps you work quickly, catch bugs at compile time, and deliver blazing fast responses.

🚀 Say goodbye to slow

Lucky is extremely fast and uses very little memory. You and your users will love the extra dose of speed.

🔋 Batteries included

Authentication, asset management, CORS, database ORM, and more can all be included when creating a new Lucky project.

😁 Fewer bugs. More joy

Instead of finding bugs in QA or in production, Lucky is designed to catch as many bugs as possible at compile time.

# Why is modern web development so complicated?

Have you ever thought:

  • “Why do I have to write so much boilerplate?”
  • “How do so many bugs make it to production?”
  • “Why is my app so slow!?”
  • “Why do I have to choose between fast prototyping and long term maintainability?”

# What if you could create something quickly and maintain it for years to come?

  • Generators for quick code creation
  • Built in authentication (Optional)
  • Secure by default
  • Built in Webpack config to get an SPA off the ground fast (Optional)
  • Insanely fast execution so users aren’t left waiting
  • Powerful type system that helps catch bugs before they ever hit production

If this sounds interesting, let’s get started.

# What does Lucky look like?

Lucky uses Action classes for handling HTTP request and responses. The classes map the routes and parameters it handles to a response block. Lucky can generate these classes for you with ’lucky gen.action`.

Using a class per action provides very solid automatic error detection, as well as generation of routing, path, and link helpers and methods.

# JSON API

class Api::Users::Show < ApiAction
  get "/api/users/:user_id" do
    json user_json
  end

  private def user_json
    user = UserQuery.find(user_id)
    {name: user.name, email: user.email}
  end
end

# Database

# Set up the model
class User < BaseModel
  table do
    column last_active_at : Time
    column last_name : String
  end
end

# Add some methods to help query the database
class UserQuery < User::BaseQuery
  def recently_active
    last_active_at.gt(1.week.ago)
  end

  def sorted_by_last_name
    last_name.lower.desc_order
  end
end

# Query the database
UserQuery.new.recently_active.sorted_by_last_name

# Rendering HTML

class Users::Index < BrowserAction
  get "/users" do
    users = UserQuery.new.sorted_by_last_name
    html IndexPage, users: users
  end
end

class Users::IndexPage < MainLayout
  needs users : UserQuery

  def content
    ul class: "users-list" do
      users.each do |user|
        li { link user.name, to: Users::Show.with(user) }
      end
    end
  end
end

# JavaScript Components

class Home::IndexPage < MainLayout
  def content
    # Lucky includes Webpack!
    # You can enable React or Vue.js support. Then...

    # Mount your JavaScript component/app
    tag("MyApp", title: "MyApp is the best")

    # Optionally render regular HTML for non-interactive elements
    footer "Copyright MyApp 2024"
  end
end

# Not quite ready to try Lucky?

If you’re not quite ready to dive in but want to stay up to date, subscribe to our blog, or follow us on Twitter.