Skip to content

Development Environment

memmof edited this page Feb 19, 2026 · 29 revisions

Welcome to the Lago development environment setup guide!

This documentation is designed for contributors who want to work on Lago. If you're just looking to try Lago locally, please refer to the Lago public documentation for a simpler setup.

Prerequisites

Before you begin, ensure you have the following installed:

  • Git

  • Docker

  • Homebrew (macOS only)

    /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
  • OpenSSL

    # Ubuntu/Debian
    sudo apt update
    sudo apt install openssl
    
    # macOS
    brew install openssl

Setting Up Your Local Environment

Clone the Repository

First of all, you need to clone the Lago repo on your machine. Since we're using Git submodules, you need to use the following command:

git clone --recurse-submodules git@github.com:getlago/lago.git
cd lago

lago command

In order to simplify how we work with Docker, we suggest creating a lago command that will be available in your terminal.

You'll need to export the LAGO_PATH environment variable and add the lago alias to your shell rc, e.g. .bashrc or .zshrc:

  • For Bash:

    echo "export LAGO_PATH=${PWD}" >> ~/.bashrc
    echo 'alias lago="docker compose -f $LAGO_PATH/docker-compose.dev.yml"' >> ~/.bashrc
    echo 'alias lago-worktree="$LAGO_PATH/front/scripts/lago-worktree.sh"' >> ~/.bashrc
    source ~/.bashrc
  • For Zsh:

    echo "export LAGO_PATH=${PWD}" >> ~/.zshrc
    echo 'alias lago="docker compose -f $LAGO_PATH/docker-compose.dev.yml"' >> ~/.zshrc
    echo 'alias lago-worktree="$LAGO_PATH/front/scripts/lago-worktree.sh"' >> ~/.zshrc
    source ~/.zshrc
  • For Fish:

    echo "setenv LAGO_PATH $PWD" >> ~/.config/fish/config.fish
    echo 'alias lago="docker compose -f $LAGO_PATH/docker-compose.dev.yml"' >> ~/.config/fish/config.fish
    echo 'alias lago-worktree="$LAGO_PATH/front/scripts/lago-worktree.sh"' >> ~/.config/fish/config.fish
    source ~/.config/fish/config.fish

Traefik

Traefik is used to manage the TLS certificates and the routing to the different services.

To make it work:

  1. Install mkcert :

    brew install mkcert nss
  2. Generate some certs for TLS usage:

    mkcert -install
    cd $LAGO_PATH/traefik
    mkdir certs
    cd certs
    mkcert -cert-file lago.dev.pem -key-file lago.dev-key.pem lago.dev "*.lago.dev"
  3. Add all custom domains to your /etc/hosts file:

    # Lago local domains
    127.0.0.1 traefik.lago.dev
    127.0.0.1 api.lago.dev
    127.0.0.1 app.lago.dev
    127.0.0.1 pdf.lago.dev
    127.0.0.1 license.lago.dev
    127.0.0.1 mail.lago.dev
    127.0.0.1 webhook.lago.dev

Configuring the API

cd $LAGO_PATH
cp ./api/.env.dist ./api/.env
touch ./api/config/master.key

Running the app

Start the dependencies (DB, Redis, Traefik, Mailhog, Clickhouse) via:

lago up -d --wait db redis traefik mailhog clickhouse webhook

Then start the default services (Front, API, API worker, Clock (CRON)):

lago up front api api-worker api-clock

You can now access your local Lago at https://app.lago.dev.

Once everything is running fine, you can run the services in detached mode:

lago up -d --wait front api api-worker api-clock

Arbitrary commands

Since lago is an alias for docker compose, you can run arbitrary commands using lago exec <service> <command>.

For instance, to start the Rails console or run migrations, run:

lago exec api bundle exec rails console
# or
lago exec api bundle exec rails db:migrate

Environment Variables

Docker services will rely on .env.development.default to find all the necessary env variable. You can override any variable by creating/updating the .env.development file.

Example: If you want to disable Clickhouse, you can set LAGO_CLICKHOUSE_ENABLED=false in your .env.development, which will override the default value set in .env.development.default

Note that .env.development.default is versioned with Git but .env.development is ignored. So make sure to only update .env.development when you want to override a variable.

Also keep in mind that the docker .env files are not interpolated so make sure all values are static (no ENV_VAR=${MY_VAR_FROM_SHELL}).

Seeding your DB

When launching the API for the first time, the DB will be seeded with some data (organization, user, etc.). See the seed files for more information.

You can also specify the organization, user, and API key to be created when starting the app by setting the following env variables to your .env.development file:

LAGO_CREATE_ORG=true
LAGO_ORG_USER_EMAIL=your-email@example.com
LAGO_ORG_USER_PASSWORD=password
LAGO_ORG_NAME=Acme
LAGO_ORG_API_KEY=lago_key_1234567890

Dedicated workers and queues

By default, asynchronous jobs are processed by the api-worker or api-clock services in the queues defined respectively in api/config/sidekiq/sidekiq.yml and api/config/sidekiq/sidekiq_clock.yml.

But on production, we rely on dedicated workers and queues for certain jobs. Whether jobs are pushed to those queues or not is controlled with boolean env variables starting with SIDEKIQ_ such as SIDEKIQ_EVENTS.

You can reproduce this behavior locally by enabling a dedicated queue in .env.development, e.g. SIDEKIQ_EVENTS=true, and running the associated queue worker:

lago up -d api-events-worker

To get the full list of workers, run:

lago config --services | grep 'worker'

Testing

Before running tests, you'll need to create the test database:

lago exec -e LAGO_DISABLE_SCHEMA_DUMP=true -e RAILS_ENV=test api bundle exec rails db:create db:migrate

Running tests automatically

It is possible to run tests automatically when you save a file using Guard:

lago exec api bundle exec guard

Running tests manually

It is also possible to run tests manually via RSpec:

lago exec api bundle exec rspec
lago exec api bundle exec rspec <your_file_spec.rb>

Linting

We use Rubocop to lint the code.

To run the linter, run:

lago exec api bundle exec rubocop
lago exec api bundle exec rubocop -A # Auto-correct offenses

We recommend running the linter automatically when you save a file using your editor "Format on save" feature.

Development

We rely on Git submodules to manage the API and Front repositories. Check the Git submodules documentation for more information.

Running Multiple Frontends in Parallel

The lago-worktree script lets you run isolated frontend instances side-by-side using git worktrees. Each worktree gets its own branch, Docker container, and port — only the front (and optionally the API) run in a separate container, while everything else (database, Redis, Redpanda, PDF service, etc.) is shared with the main stack.

This is especially useful for AI-assisted development: you can spin up parallel worktrees and let multiple AI agents (Claude Code, Cursor, etc.) work on different tickets simultaneously, each in its own isolated environment other then the main branch.

Setup

Prerequisites

  • The main Lago stack must be running (lago up -d)
  • Docker and pnpm installed

Quick Start

# Create a worktree and start it (front only, shares the main API)
lago-worktree create TASK-0001

# Create a worktree with a dedicated API container too
lago-worktree create TASK-0001 --from-api=main

# Branch off a specific front branch instead of main
lago-worktree create TASK-0001 --from-front=feat/ui

# Both custom bases
lago-worktree create LAGO-0001 --from-front=feat/ui --from-api=feat/endpoint

Commands

Command Description
create <branch> [--from-front=<base>] [--from-api=<base>] Create worktree(s) and start containers
up <name> Start an existing (stopped) worktree
down <name> Stop containers and free the port
destroy <name> Stop containers and delete the worktree + branch
ps List all worktree instances with status and ports

How It Works

  • Front ports are auto-assigned and auto-incremented starting from 3001 (3001, 3002, 3003, ...).
  • API ports (when using --from-api) are auto-assigned and auto-incremented starting from 4001 (4001, 4002, 4003, ...).
  • Each worktree container joins the shared lago_dev_default Docker network, so it can reach the database, Redis, and other services from the main stack.
  • Without --from-api, the front proxies API calls to the shared main API on port 3000.

Example Workflow

# 1. Start working on a ticket
lago-worktree create TASK-1234

# 2. Open http://localhost:3001 in the browser

# 3. Check running instances
lago-worktree ps

# 4. Stop when done for the day
lago-worktree down TASK-1234

# 5. Resume later
lago-worktree up TASK-1234

# 6. No longer needed or merged into main — clean up everything
lago-worktree destroy TASK-1234

Working on a submodule

Simply go in the submodule directory and checkout a new branch:

cd $LAGO_PATH/api
git checkout -b <your_branch_name>
# make your changes
git add .
git commit -m "feat: add your changes"
git push origin <your_branch_name>

This will create a new branch in the lago-api repository and push it to the remote repository.

Updating a reference

If you want to update a reference to a commit in the submodule, you can do so by checking out the commit within the submodule and committing the changes to the main repository:

cd $LAGO_PATH/api
git fetch origin main
git checkout <commit_hash>
cd ..
git add api
git commit -m "feat: update api submodule"
git push origin main

Pulling the latest changes

To pull the latest changes from the submodules, run:

git pull --recurse-submodules

Emails

We rely on Mailhog to test emails locally.

To access the Mailhog web interface, you can use the following URL: https://mail.lago.dev.

Webhooks

We rely on Webhook tester to test webhooks locally.

The seeds create a webhook endpoint with the following URL: http://webhook/11111111-2222-3333-4444-555555555555.

Requests sent to this URL will be logged in the Webhook tester web interface: https://webhook.lago.dev/s/11111111-2222-3333-4444-555555555555.

Setup license service

Follow instructions at https://github.com/getlago/lago-license.

Clone this wiki locally