We value your privacy

This site uses cookies to improve your browsing experience, analyze site traffic, and show personalized content. See our Privacy Policy.

  1. MooseStack
  2. Configuration
  3. Dev Environment

Dev Environment Configuration

This reference covers configuration options specific to the local development workflow (moose dev), including lifecycle hooks, Docker infrastructure extensions, and network defaults.

Container Runtime

By default, Moose uses docker as the container runtime for local development infrastructure. You can switch to an alternative Docker-compatible CLI such as Finch, Podman, or nerdctl.

Configuration

Set the container CLI in your global Moose config file:

~/.moose/config.toml
[dev]container_cli_path = "finch"

This applies to all Moose projects on your machine. You can also override per session with an environment variable:

MOOSE_DEV__CONTAINER_CLI_PATH=finch moose dev
KeyEnv VariableDefaultDescription
container_cli_pathMOOSE_DEV__CONTAINER_CLI_PATHdockerContainer CLI executable name or path. Must support compose, ps, exec, logs, and info subcommands.
Finch Setup

Finch is an open-source container tool by AWS that provides a Docker-compatible CLI backed by containerd and nerdctl.

  1. Install Finch: brew install --cask finch (macOS)
  2. Initialize the VM: finch vm init && finch vm start
  3. Configure Moose to use Finch:
echo -e '\n[dev]\ncontainer_cli_path = "finch"' >> ~/.moose/config.toml

Lifecycle Hooks

Configure shell commands that run automatically during the moose dev lifecycle. Hooks are defined in the [http_server_config] section and execute after all infrastructure (OlapTables, topics, etc.) has been applied — making them the right place for any work that depends on tables already existing.

moose.config.toml
[http_server_config]# Runs once when `moose dev` first startson_first_start_script = "uv run python app/scripts/setup_views.py" # Runs after every successful file-change reloadon_reload_complete_script = "uv run python app/scripts/setup_views.py"
KeyEnv VariableTypeDefaultDescription
on_first_start_scriptMOOSE_HTTP_SERVER_CONFIG__ON_FIRST_START_SCRIPTString—Shell command executed once when moose dev starts. Guaranteed to run only once per process.
on_reload_complete_scriptMOOSE_HTTP_SERVER_CONFIG__ON_RELOAD_COMPLETE_SCRIPTString—Shell command executed after every successful code/infra reload.
Execution semantics
  • Scripts run via $SHELL -c <script> from your project root (stdout/stderr appear in the terminal).
  • on_first_start_script runs exactly once per moose dev process — an atomic flag prevents duplicate runs even if the start path is triggered multiple times.
  • on_reload_complete_script runs only after a successful reload; failed reloads (e.g. TypeScript compile errors) do not trigger it.
  • Both hooks are blocking — Moose waits for the script to finish before continuing.
  • Hooks are dev-only and are never executed in production.

Post-Startup SQL Setup

The most common use case is running SQL against ClickHouse after all tables are guaranteed to exist. This is especially useful in multi-database setups where views in one database reference tables in another, since Moose's infrastructure ordering cannot guarantee cross-database dependency resolution.

moose.config.toml

[http_server_config]on_first_start_script = "uv run python app/scripts/setup_views.py"on_reload_complete_script = "uv run python app/scripts/setup_views.py"

Setting both hooks ensures views are created on first start and kept up-to-date whenever your SQL definitions change during development.

app/scripts/setup_views.py

import osimport sysimport clickhouse_connect # Make app-level imports available when the script runs from the project rootsys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))) from app.datamodels.silver.open_orders import OpenOrders_SQL# Import other SQL strings here... # List views in strict dependency order (dependencies before dependants)VIEWS = [    ("silver.OpenOrders", OpenOrders_SQL),    # ("silver.OtherView", OtherView_SQL),] def get_client():    return clickhouse_connect.get_client(        host=os.getenv("CLICKHOUSE_HOST", "localhost"),        port=int(os.getenv("CLICKHOUSE_PORT", "18123")),        username=os.getenv("CLICKHOUSE_USER", "panda"),        password=os.getenv("CLICKHOUSE_PASSWORD", "pandapass"),    ) if __name__ == "__main__":    client = get_client()    for name, sql in VIEWS:        client.command(f"CREATE OR REPLACE VIEW {name} AS {sql}")        print(f"  created {name}")    print("Views ready.")

CREATE OR REPLACE VIEW makes the script idempotent — safe to run on every reload.

When to use this pattern
  • Multi-database setups: views in one database that reference tables in additional_databases
  • Reference data seeding: inserting lookup data after tables are created
  • Any SQL that must run after all OlapTables exist, such as materialized views with complex cross-table dependencies

Other Common Examples

Sync external tables on start

[http_server_config]on_first_start_script = "moose db pull --clickhouse-url $REMOTE_DB_URL"

Regenerate SDK clients on reload

[http_server_config]on_reload_complete_script = "openapi-generator-cli generate -i .moose/openapi.yaml ..."

File Watcher

The dev server watches your project and hot-reloads when you save changes.

  • TypeScript projects: Reloads are driven by TypeScript compilation. The compiler runs in watch mode; when you save a file, an incremental compile runs. Only after a successful compile does Moose re-plan and apply infrastructure changes. Compilation errors block reloads (fix errors in your code to continue). Compiled output goes to your tsconfig.json outDir or .moose/compiled. See Moose Dev for details.
  • Python projects: A file watcher detects changes and triggers reloads directly.

Use ignore_patterns to exclude files (e.g. generated by lifecycle hooks) that should not trigger reloads.

[watcher_config]# Patterns use standard glob syntaxignore_patterns = ["generated/**", "*.gen.ts"]

Debugging Data Flow

To debug data as it flows through your pipeline, use the --log-payloads flag:

moose dev --log-payloads

This logs payloads at three key points with searchable prefixes:

  • PAYLOAD:INGEST - Data received at ingest API
  • PAYLOAD:STREAM_IN - Data before streaming function
  • PAYLOAD:STREAM_OUT - Data after streaming function

All logs appear in Moose logs and can be viewed using moose logs --tail.

Debugging SQL Queries

When a ClickHouse SQL query fails, Moose logs the error status and message at error level. To also see the full SQL statement that failed:

Enable debug-level logging to see the full SQL statement in the logs:

MOOSE_LOGGER__LEVEL=Debug moose dev

Then filter the logs for the failing statement:

moose logs --filter "Failed SQL"

See the Troubleshooting guide for more details.

Docker Infrastructure Extensions

Extend the default Moose development infrastructure by creating a specific override file in your project root.

File NamePurpose
docker-compose.dev.override.yamlAdds or overrides services in the generated Docker Compose setup.

Usage

Create docker-compose.dev.override.yaml to add services like PostgreSQL or monitoring tools. Moose automatically detects and merges this file when running moose dev.

# docker-compose.dev.override.yamlservices:  postgres:    image: postgres:16    environment:      POSTGRES_PASSWORD: mypassword    ports:      - "5432:5432"
Limitations

Do not use this file to configure Moose-managed services (ClickHouse, Redpanda, Redis, Temporal). Use moose.config.toml for those components to avoid configuration conflicts.

Externally Managed Tables

When working with tables marked as EXTERNALLY_MANAGED (tables that exist in a production database but are managed outside Moose), you can configure the dev environment to create local mirror tables for development and testing.

Configuration

[dev.externally_managed.tables]# Create local mirror tables for EXTERNALLY_MANAGED tablescreate_local_mirrors = true # Number of sample rows to seed (0 = schema only, no data)sample_size = 1000 # Re-create tables on every dev server startrefresh_on_startup = false
KeyTypeDefaultDescription
create_local_mirrorsBooleanfalseWhen true, creates local tables matching the schema of externally managed tables.
sample_sizeInteger0Number of rows to copy from the remote database. Set to 0 to create empty tables (schema only).
refresh_on_startupBooleanfalseWhen true, drops and recreates mirror tables on each moose dev start.
Remote Credentials

If you have a remote ClickHouse URL configured, Moose will mirror table schemas and sample data from the remote database. Without remote access, tables are created using local schema definitions (empty).

Remote ClickHouse Connection

To mirror data from a production or staging database, configure a remote ClickHouse connection:

[dev.remote_clickhouse]host = "your-clickhouse-host.example.com"port = 8443database = "production_db"use_ssl = trueprotocol = "http"
KeyTypeDefaultDescription
hostString-Hostname of the remote ClickHouse server.
portInteger8443 (SSL) / 8123 (non-SSL)HTTP port for the remote server.
databaseString-Default database to query on the remote server.
use_sslBooleantrueWhether to use TLS (HTTPS) for connections.
protocolStringhttpClickHouse interface protocol — http selects the HTTP interface (vs native). TLS is controlled separately by use_ssl.
Credential Storage

Credentials (username/password) are not stored in moose.config.toml. On first run, Moose will prompt for credentials and store them securely in your OS keychain. You can also set MOOSE_REMOTE_CLICKHOUSE_USER and MOOSE_REMOTE_CLICKHOUSE_PASSWORD environment variables.

Networking Reference

Reference for default ports and URLs used by the Moose Runtime in development mode.

Default Ports

PortServiceDescriptionConfig Key
4000API ServerMain Ingestion/Consumption APIshttp_server_config.port
5001Management APIHealth checks & Metricshttp_server_config.management_port
18123ClickHouse HTTPOLAP Database (HTTP)clickhouse_config.host_port
9000ClickHouse NativeOLAP Database (TCP)clickhouse_config.native_port
19092RedpandaKafka Streamingredpanda_config.broker
8080Temporal UIWorkflow Dashboardtemporal_config.ui_port

Service URLs

Access points for local development services:

ServiceURL
Main APIhttp://localhost:4000
Management APIhttp://localhost:5001/metrics
OpenAPI Spechttp://localhost:5001/openapi.yaml
Temporal UIhttp://localhost:8080

On this page

Container RuntimeConfigurationLifecycle HooksPost-Startup SQL SetupOther Common ExamplesFile WatcherDebugging Data FlowDebugging SQL QueriesDocker Infrastructure ExtensionsUsageExternally Managed TablesConfigurationRemote ClickHouse ConnectionNetworking ReferenceDefault PortsService URLs
Edit this page
FiveonefourFiveonefour
Fiveonefour Docs
MooseStackHostingTemplatesGuides
Release Notes
Source575
  • Overview
Build a New App
  • 5 Minute Quickstart
  • Browse Templates
  • Existing ClickHouse
Add to Existing App
  • Next.js
  • Fastify
Fundamentals
  • Moose Runtime
  • MooseDev MCP
  • Language Server
  • Data Modeling
Moose Modules
  • Moose OLAP
  • Moose Streams
  • Moose Workflows
  • Moose APIs & Web Apps
Deployment & Lifecycle
  • Moose Dev
  • Moose Migrate
  • Moose Deploy
Reference
  • API Reference
  • Query Layer
  • Testing Utilities
  • Data Types
  • Table Engines
  • CLI
  • Configuration
    • Core Settings
    • Project Settings
    • TypeScript
    • Telemetry
    • Git
    • Features
    • Migrations
    • Docker
    • Infrastructure
    • ClickHouse
    • Redpanda
    • Redis
    • Temporal
    • HTTP Server
    • State Storage
    • Security
    • JWT
    • Row-Level Security
    • Admin API
    • Development
    • Dev Environment
  • Observability Metrics
  • Help
  • Release Notes
Contribution
  • Documentation
  • Framework